diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c00e2688f1..e14c5d1624 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -111,6 +111,9 @@ The use of the : operator to override type safety checks is not allowed. You mus ### Type paths must begin with a / eg: `/datum/thing`, not `datum/thing` +### Type paths must be lowercase +eg: `/datum/thing/blue`, not `datum/thing/BLUE` or `datum/thing/Blue` + ### Datum type paths must began with "datum" In DM, this is optional, but omitting it makes finding definitions harder. @@ -240,6 +243,8 @@ This prevents nesting levels from getting deeper then they need to be. * Queries must never specify the database, be it in code, or in text files in the repo. +* Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy. + ### Mapping Standards * TGM Format & Map Merge * All new maps submitted to the repo through a pull request must be in TGM format (unless there is a valid reason present to have it in the default BYOND format.) This is done using the [Map Merge](https://github.com/tgstation/tgstation/wiki/Map-Merger) utility included in the repo to convert the file to TGM format. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 949f1c4c44..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -[Round ID]: # (If you discovered this issue from playing tgstation hosted servers:) -[Round ID]: # (**INCLUDE THE ROUND ID**) -[Round ID]: # (It can be found in the Status panel or retrieved from https://atlantaned.space/statbus/round.php ! The round id let's us look up valuable information and logs for the round the bug happened.) - -[Testmerges]: # (If you believe the issue to be caused by a test merge [OOC tab -> Show Server Revision], report it in the pull request's comment section instead.) - -[Reproduction]: # (Explain your issue in detail, including the steps to reproduce it. Issues without proper reproduction steps or explanation are open to being ignored/closed by maintainers.) - -[For Admins]: # (Oddities induced by var-edits and other admin tools are not necessarily bugs. Verify that your issues occur under regular circumstances before reporting them.) \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..09f99f6c85 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help reproduce and fix the issue +--- + +## Round ID: + + + +## Testmerges: + + + +## Reproduction: + + + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..2c9eb90c72 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,7 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +Please be aware that feature discussions most often take place on the Citadel Station Discord and should not be requested here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7855fd5782..f204eb0a72 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,16 @@ -[Changelogs]: # (Your PR should contain a detailed changelog of notable changes, titled and categorized appropriately. This includes, new features, sprites, sounds, balance changes, admin tools, map edits, removals, big refactors, config changes, hosting changes and important fixes. An example changelog has been provided below for you to edit. If you need additional help, read https://github.com/tgstation/tgstation/wiki/Changelogs) + + -:cl: optional name here +## About The Pull Request + + + +## Why It's Good For The Game + + + +## Changelog +:cl: add: Added new things add: Added more things del: Removed old things @@ -19,4 +29,5 @@ admin: messed with admin stuff server: something server ops should know /:cl: -[why]: # (Please add a short description [two lines down] of why you think these changes would benefit the game. If you can't justify it in words, it might not be worth adding.) + + diff --git a/.travis.yml b/.travis.yml index 7138b23354..bef3a69ad7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: generic sudo: false +dist: xenial branches: except: - ___TGS3TempBranch @@ -14,6 +15,7 @@ matrix: packages: - python3 - python3-pip + - python3-setuptools cache: directories: - tgui/node_modules @@ -43,7 +45,8 @@ matrix: - gcc-multilib - g++-7 - g++-7-multilib - - libmariadbclient-dev:i386 + - libmariadb-client-lgpl-dev:i386 + - libmariadbd-dev cache: directories: - $HOME/.cargo diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index b3a0289761..738148c948 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -209,6 +209,8 @@ dir = 8 }, /obj/item/malf_upgrade, +/obj/item/disk/tech_disk/illegal, +/obj/structure/safe, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/ash_walkers) "aB" = ( diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm index ba291fc258..fd2e56a53f 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm @@ -272,7 +272,14 @@ /obj/machinery/light, /turf/open/floor/plasteel/freezer, /area/ruin/powered/seedvault) - +"Z" = ( +/obj/item/disk/design_disk/plant_disk, +/obj/machinery/autolathe{ + hacked = TRUE; + desc = "This autolathe seems to have its safety light off." + }, +/turf/open/floor/plasteel/freezer, +/area/ruin/powered/seedvault) (1,1,1) = {" a a @@ -375,7 +382,7 @@ h h u R -u +Z Q a a diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index ef36495c58..e820b06f61 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -2183,9 +2183,7 @@ /obj/effect/turf_decal/tile/purple{ dir = 8 }, -/turf/open/floor/plasteel/white{ - icon_state = "whitepurple" - }, +/turf/open/floor/plasteel/white, /area/ruin/space/has_grav/ancientstation/rnd) "fU" = ( /obj/effect/decal/cleanable/dirt, diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index bba92be7a7..dcd2c47cb2 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -27901,8 +27901,8 @@ pixel_x = 30 }, /obj/machinery/light, -/mob/living/simple_animal/bot/cleanbot{ - name = "C.L.E.A.N." +/obj/machinery/computer/crew{ + dir = 1 }, /turf/open/floor/plasteel/white, /area/medical/medbay/central) @@ -31596,7 +31596,7 @@ /area/medical/sleeper) "bwC" = ( /obj/machinery/computer/med_data{ - dir = 4 + dir = 3 }, /turf/open/floor/plasteel/white, /area/medical/sleeper) @@ -56882,6 +56882,12 @@ /obj/item/pen, /turf/open/floor/plasteel/white, /area/science/circuit) +"ium" = ( +/mob/living/simple_animal/bot/cleanbot{ + name = "C.L.E.A.N." + }, +/turf/open/floor/plasteel/white, +/area/medical/medbay/central) "izv" = ( /obj/machinery/vending/clothing, /obj/machinery/light/small{ @@ -94182,7 +94188,7 @@ blm bmL boi bpw -bhh +ium bsx btX bvj diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 4c454aa61a..e35defd485 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -35,3 +35,8 @@ //Overthrow time to update heads obj #define OBJECTIVE_UPDATING_TIME 300 + +//Gangshit +#define NOT_DOMINATING -1 +#define MAX_LEADERS_GANG 3 +#define INITIAL_DOM_ATTEMPTS 3 diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index b5ba44d956..928837979c 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -1,8 +1,5 @@ //LISTMOS //indices of values in gas lists. -#define MOLES 1 -#define ARCHIVE 2 -#define GAS_META 3 #define META_GAS_SPECIFIC_HEAT 1 #define META_GAS_NAME 2 #define META_GAS_MOLES_VISIBLE 3 @@ -242,20 +239,25 @@ //HELPERS #define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity()) - -#define ADD_GAS(gas_id, out_list)\ - var/list/tmp_gaslist = GLOB.gaslist_cache[gas_id]; out_list[gas_id] = tmp_gaslist.Copy(); - -#define ASSERT_GAS(gas_id, gas_mixture) if (!gas_mixture.gases[gas_id]) { ADD_GAS(gas_id, gas_mixture.gases) }; - +#define QUANTIZE(variable) (round(variable,0.0000001))/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that + once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */ //prefer this to gas_mixture/total_moles in performance critical areas #define TOTAL_MOLES(cached_gases, out_var)\ out_var = 0;\ for(var/total_moles_id in cached_gases){\ - out_var += cached_gases[total_moles_id][MOLES];\ + out_var += cached_gases[total_moles_id];\ } +//Unomos - So for whatever reason, garbage collection actually drastically decreases the cost of atmos later in the round. Turning this into a define yields massively improved performance. +#define GAS_GARBAGE_COLLECT(GASGASGAS)\ + var/list/CACHE_GAS = GASGASGAS;\ + for(var/id in CACHE_GAS){\ + if(QUANTIZE(CACHE_GAS[id]) <= 0)\ + CACHE_GAS -= id;\ + } + +#define ARCHIVE_TEMPERATURE(gas) gas.temperature_archived = gas.temperature GLOBAL_LIST_INIT(pipe_paint_colors, list( "amethyst" = rgb(130,43,255), //supplymain diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 9f5f52180c..2abe0db04e 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -33,8 +33,8 @@ #define BALLS_VOLUME_MULT 1 #define BALLS_SIZE_MIN 1 -#define BALLS_SIZE_DEF 3 -#define BALLS_SIZE_MAX 7 +#define BALLS_SIZE_DEF 2 +#define BALLS_SIZE_MAX 3 #define BALLS_SACK_SIZE_MIN 1 #define BALLS_SACK_SIZE_DEF 8 diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 3338fc1cda..dbe8cfbb62 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -142,8 +142,9 @@ #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity)) // /obj signals -#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled) -#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value) +#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled) +#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag) +#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value) // /obj/item signals #define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user) diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index 9f3d38efa1..aa9c5cf34e 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -103,6 +103,7 @@ #define CAT_SOUP "Soups" #define CAT_SPAGHETTI "Spaghettis" #define CAT_SUSHI "Fish" +#define CAT_ICE "Frozen" #define RCD_FLOORWALL 1 #define RCD_AIRLOCK 2 diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index ad9aef5a8b..60148e0388 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -56,9 +56,6 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define FLYING (1<<1) #define VENTCRAWLING (1<<2) -// Flags for reagents -#define REAGENT_NOREACT (1<<0) - //Fire and Acid stuff, for resistance_flags #define LAVA_PROOF (1<<0) #define FIRE_PROOF (1<<1) //100% immune to fire damage (but not necessarily to lava or heat) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index be58b64f41..19710a89fe 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -218,6 +218,9 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) //Gets the turf this atom inhabits #define get_turf(A) (get_step(A, 0)) +//Same as above except gets the area instead +#define get_area(A) (isarea(A) ? A : get_step(A, 0)?.loc) + //Ghost orbit types: #define GHOST_ORBIT_CIRCLE "circle" #define GHOST_ORBIT_TRIANGLE "triangle" diff --git a/code/__DEFINES/reagents.dm b/code/__DEFINES/reagents.dm index f8f59a367f..c3682d905d 100644 --- a/code/__DEFINES/reagents.dm +++ b/code/__DEFINES/reagents.dm @@ -2,7 +2,7 @@ #define LIQUID 2 #define GAS 3 -// container_type defines +// reagents_flags defines #define INJECTABLE (1<<0) // Makes it possible to add reagents through droppers and syringes. #define DRAWABLE (1<<1) // Makes it possible to remove reagents through syringes. @@ -11,6 +11,7 @@ #define TRANSPARENT (1<<4) // Used on containers which you want to be able to see the reagents off. #define AMOUNT_VISIBLE (1<<5) // For non-transparent containers that still have the general amount of reagents in them visible. +#define NO_REACT (1<<6) // Applied to a reagent holder, the contents will not react with each other. // Is an open container for all intents and purposes. #define OPENCONTAINER (REFILLABLE | DRAINABLE | TRANSPARENT) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 6773d55e53..b316c003a9 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -33,7 +33,8 @@ #define ROLE_DRONE "drone" #define ROLE_DEATHSQUAD "deathsquad" #define ROLE_LAVALAND "lavaland" -#define ROLE_INTERNAL_AFFAIRS "internal affairs agent" +#define ROLE_INTERNAL_AFFAIRS "internal affairs agent" +#define ROLE_GANG "gangster" //Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. //The gamemode specific ones are just so the gamemodes can query whether a player is old enough @@ -58,7 +59,8 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult, ROLE_OVERTHROW = /datum/game_mode/overthrow, ROLE_INTERNAL_AFFAIRS = /datum/game_mode/traitor/internal_affairs, - ROLE_SENTIENCE + ROLE_SENTIENCE, + ROLE_GANG = /datum/game_mode/gang )) //Job defines for what happens when you fail to qualify for any job during job selection diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index ff45ac474f..b42cbb8f00 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -1,3 +1,61 @@ +// trait accessor defines +#define ADD_TRAIT(target, trait, source) \ + do { \ + var/list/_L; \ + if (!target.status_traits) { \ + target.status_traits = list(); \ + _L = target.status_traits; \ + _L[trait] = list(source); \ + } else { \ + _L = target.status_traits; \ + if (_L[trait]) { \ + _L[trait] |= list(source); \ + } else { \ + _L[trait] = list(source); \ + } \ + } \ + } while (0) +#define REMOVE_TRAIT(target, trait, sources) \ + do { \ + var/list/_L = target.status_traits; \ + var/list/_S; \ + if (sources && !islist(sources)) { \ + _S = list(sources); \ + } else { \ + _S = sources\ + }; \ + if (_L && _L[trait]) { \ + for (var/_T in _L[trait]) { \ + if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \ + _L[trait] -= _T \ + } \ + };\ + if (!length(_L[trait])) { \ + _L -= trait \ + }; \ + if (!length(_L)) { \ + target.status_traits = null \ + }; \ + } \ + } while (0) +#define REMOVE_TRAITS_NOT_IN(target, sources) \ + do { \ + var/list/_L = target.status_traits; \ + var/list/_S = sources; \ + if (_L) { \ + for (var/_T in _L) { \ + _L[_T] &= _S;\ + if (!length(_L[_T])) { \ + _L -= _T } \ + };\ + if (!length(_L)) { \ + target.status_traits = null\ + };\ + }\ + } while (0) +#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE) +#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE) + //mob traits #define TRAIT_BLIND "blind" #define TRAIT_MUTE "mute" @@ -79,6 +137,10 @@ #define TRAIT_NYMPHO "nymphomania" #define TRAIT_MASO "masochism" #define TRAIT_PARA "paraplegic" +#define TRAIT_EMPATH "empath" +#define TRAIT_FRIENDLY "friendly" +#define TRAIT_ASSBLASTUSA "assblastusa" +#define TRAIT_CULT_EYES "cult_eyes" // common trait sources #define TRAIT_GENERIC "generic" @@ -101,4 +163,3 @@ #define STASIS_MUTE "stasis" #define GENETICS_SPELL "genetics_spell" #define EYES_COVERED "eyes_covered" -#define CULT_EYES "cult_eyes" diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index eb2a564d1b..668b151b6e 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -58,8 +58,11 @@ GLOBAL_LIST_EMPTY(ipc_antennas_list) //Genitals and Arousal Lists GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. +GLOBAL_LIST_EMPTY(balls_shapes_list) +GLOBAL_LIST_EMPTY(balls_shapes_icons) GLOBAL_LIST_EMPTY(breasts_size_list) GLOBAL_LIST_EMPTY(breasts_shapes_list) +GLOBAL_LIST_EMPTY(breasts_shapes_icons) GLOBAL_LIST_EMPTY(vagina_shapes_list) GLOBAL_LIST_INIT(cum_into_containers_list, list(/obj/item/reagent_containers/food/snacks/pie)) //Yer fuggin snowflake name list jfc GLOBAL_LIST_INIT(dick_nouns, list("dick","cock","member","shaft")) @@ -123,36 +126,36 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) /mob/living/carbon/proc/has_penis() if(getorganslot("penis"))//slot shared with ovipositor if(istype(getorganslot("penis"), /obj/item/organ/genital/penis)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/proc/has_balls() if(getorganslot("balls")) if(istype(getorganslot("balls"), /obj/item/organ/genital/testicles)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/proc/has_vagina() if(getorganslot("vagina")) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/proc/has_breasts() if(getorganslot("breasts")) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/proc/has_ovipositor() if(getorganslot("penis"))//shared slot if(istype(getorganslot("penis"), /obj/item/organ/genital/ovipositor)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/human/proc/has_eggsack() if(getorganslot("balls")) if(istype(getorganslot("balls"), /obj/item/organ/genital/eggsack)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/carbon/human/proc/is_bodypart_exposed(bodypart) @@ -161,16 +164,16 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) L = get_equipped_items() for(var/obj/item/I in L) if(I.body_parts_covered & GROIN) - return 0 - return 1 + return FALSE + return TRUE /mob/living/carbon/proc/is_chest_exposed(var/list/L) if(!L) L = get_equipped_items() for(var/obj/item/I in L) if(I.body_parts_covered & CHEST) - return 0 - return 1 + return FALSE + return TRUE //////////////////////// //DANGER | DEBUG PROCS// @@ -191,40 +194,3 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) H.give_vagina() H.give_womb() H.give_breasts() - -/client/proc/test_mammal_overlays() - set name = "Mass Give Mammalitus" - set category = "Dangerous" - set desc = "Turns every human into a mammal with tails, ears, etc. WARNING: NOT FOR LIVE SERVER USAGE!!" - - log_admin("[src] turned everyone into mammals.") - message_admins("[src] turned everyone into mammals.") - for(var/mob/living/carbon/human/H in GLOB.mob_list) - if(!H.dna) - continue - var/datum/dna/hdna = H.dna - H.set_species(/datum/species/mammal) - var/subspec = pick("Fox","Wolf","Fennec") - switch(subspec) - if("Wolf") - hdna.features["mam_tail"] = "Wolf" - hdna.features["mam_ears"] = "Wolf" - hdna.features["mam_snouts"] = "Wolf" - hdna.features["mam_body_markings"] = "Wolf" - hdna.features["mcolor"] = "555" - hdna.features["mcolor2"] = "999" - hdna.features["mcolor3"] = "999" - if("Fox") - hdna.features["mam_tail"] = "Fox" - hdna.features["mam_ears"] = "Fox" - hdna.features["mam_snouts"] = "Fox, Long" - hdna.features["mam_body_markings"] = "Fox" - hdna.features["mcolor"] = "f60" - hdna.features["mcolor2"] = "fff" - hdna.features["mcolor3"] = "fff" - if("Fennec") - hdna.features["mam_tail"] = "Fennec" - hdna.features["mam_ears"] = "Fennec" - hdna.features["mam_snouts"] = "Fox, Short" - hdna.features["mam_body_markings"] = "Fox" - H.regenerate_icons() diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 899ef16306..c741a08108 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -8,12 +8,6 @@ #define Z_TURFS(ZLEVEL) block(locate(1,1,ZLEVEL), locate(world.maxx, world.maxy, ZLEVEL)) #define CULT_POLL_WAIT 2400 -/proc/get_area(atom/A) - if(isarea(A)) - return A - var/turf/T = get_turf(A) - return T ? T.loc : null - /proc/get_area_name(atom/X, format_text = FALSE) var/area/A = isarea(X) ? X : get_area(X) if(!A) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index f6ef08fe0d..ac113b4e08 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -46,7 +46,6 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list) //genitals init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list) - for(var/K in GLOB.cock_shapes_list) var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K] GLOB.cock_shapes_icons[K] = value.icon_state @@ -54,6 +53,14 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list) GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. + for(var/K in GLOB.breasts_shapes_list) + var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K] + GLOB.breasts_shapes_icons[K] = value.icon_state + + init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) + for(var/K in GLOB.balls_shapes_list) + var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K] + GLOB.balls_shapes_icons[K] = value.icon_state //END OF CIT CHANGES //Species diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 34a34273dc..51c814a5f9 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -77,6 +77,8 @@ //CIT CHANGES - genitals and such if(!GLOB.cock_shapes_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list) + if(!GLOB.balls_shapes_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) if(!GLOB.vagina_shapes_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list) if(!GLOB.breasts_shapes_list.len) @@ -168,6 +170,7 @@ "balls_amount" = 2, "balls_sack_size" = BALLS_SACK_SIZE_DEF, "balls_size" = BALLS_SIZE_DEF, + "balls_shape" = "Pair", "balls_cum_rate" = CUM_RATE, "balls_cum_mult" = CUM_RATE_MULT, "balls_efficiency" = CUM_EFFICIENCY, @@ -185,7 +188,7 @@ "has_breasts" = FALSE, "breasts_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), "breasts_size" = pick(GLOB.breasts_size_list), - "breasts_shape" = pick(GLOB.breasts_shapes_list), + "breasts_shape" = "Pair", "breasts_fluid" = "milk", "has_vag" = FALSE, "vag_shape" = pick(GLOB.vagina_shapes_list), diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 835a733752..c37e6fa531 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -115,9 +115,6 @@ GLOBAL_LIST_INIT(bitfields, list( "GOLIATH_RESISTANCE" = GOLIATH_RESISTANCE, "GOLIATH_WEAKNESS" = GOLIATH_WEAKNESS ), - "reagents_holder_flags" = list( - "REAGENT_NOREACT" = REAGENT_NOREACT - ), "flags_1" = list( "NOJAUNT_1" = NOJAUNT_1, "UNUSED_RESERVATION_TURF_1" = UNUSED_RESERVATION_TURF_1, @@ -158,13 +155,14 @@ GLOBAL_LIST_INIT(bitfields, list( "SMOOTH_BORDER" = SMOOTH_BORDER, "SMOOTH_QUEUED" = SMOOTH_QUEUED, ), - "container_type" = list( + "reagents_holder_flags" = list( "INJECTABLE" = INJECTABLE, "DRAWABLE" = DRAWABLE, "REFILLABLE" = REFILLABLE, "DRAINABLE" = DRAINABLE, "TRANSPARENT" = TRANSPARENT, "AMOUNT_VISIBLE" = AMOUNT_VISIBLE, + "NO_REACT" = NO_REACT, ), "car_traits" = list( "CAN_KIDNAP" = CAN_KIDNAP, diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 8b0ac278cd..47b7e2ab62 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -40,6 +40,54 @@ GLOBAL_LIST_EMPTY(caps_list) GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things +GLOBAL_LIST_INIT(ai_core_display_screens, list( + ":thinking:", + "Alien", + "Angel", + "Banned", + "Bliss", + "Blue", + "Clown", + "Database", + "Dorf", + "Firewall", + "Fuzzy", + "Gentoo", + "Glitchman", + "Gondola", + "Goon", + "Hades", + "Heartline", + "Helios", + "House", + "Inverted", + "Matrix", + "Monochrome", + "Murica", + "Nanotrasen", + "Not Malf", + "President", + "Random", + "Rainbow", + "Red", + "Red October", + "Static", + "Syndicat Meow", + "TechDemon", + "Text", + "Too Deep", + "Triumvirate", + "Triumvirate-M", + "Weird")) + +/proc/resolve_ai_icon(input) + if(!input || !(input in GLOB.ai_core_display_screens)) + return "ai" + else + if(input == "Random") + input = pick(GLOB.ai_core_display_screens - "Random") + return "ai-[lowertext(input)]" + GLOBAL_LIST_INIT(security_depts_prefs, list(SEC_DEPT_RANDOM, SEC_DEPT_NONE, SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, SEC_DEPT_SCIENCE, SEC_DEPT_SUPPLY)) //Backpacks @@ -117,7 +165,7 @@ GLOBAL_LIST_INIT(TAGGERLOCATIONS, list("Disposals", "CMO Office", "Chemistry", "Research", "RD Office", "Robotics", "HoP Office", "Library", "Chapel", "Theatre", "Bar", "Kitchen", "Hydroponics", "Janitor Closet","Genetics", - "Circuitry", "Toxins", "Dormitories", "Virology", + "Circuitry", "Toxins", "Dormitories", "Virology", "Xenobiology", "Law Office","Detective's Office")) GLOBAL_LIST_INIT(station_prefixes, world.file2list("strings/station_prefixes.txt") + "") diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 36049de77b..efd405a4dc 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -109,5 +109,8 @@ GLOBAL_LIST_INIT(maintenance_loot, list( /obj/item/reagent_containers/pill/floorpill = 1, /obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint /obj/item/storage/pill_bottle/penis_enlargement = 2, + /obj/item/clothing/shoes/wheelys = 1, + /obj/item/clothing/shoes/kindleKicks = 1, + /obj/item/autosurgeon/penis = 1, "" = 3 )) diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 03b951e6bb..df91223ed1 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -1,4 +1,7 @@ #define NEXT_PAGE_ID "__next__" +#define DEFAULT_CHECK_DELAY 20 + +GLOBAL_LIST_EMPTY(radial_menus) /obj/screen/radial icon = 'icons/mob/radial.dmi' @@ -10,14 +13,19 @@ icon_state = "radial_slice" var/choice var/next_page = FALSE + var/tooltips = FALSE /obj/screen/radial/slice/MouseEntered(location, control, params) . = ..() icon_state = "radial_slice_focus" + if(tooltips) + openToolTip(usr, src, params, title = name) /obj/screen/radial/slice/MouseExited(location, control, params) . = ..() icon_state = "radial_slice" + if(tooltips) + closeToolTip(usr) /obj/screen/radial/slice/Click(location, control, params) if(usr.client == parent.current_user) @@ -30,6 +38,14 @@ name = "Close Menu" icon_state = "radial_center" +/obj/screen/radial/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" + /obj/screen/radial/center/Click(location, control, params) if(usr.client == parent.current_user) parent.finished = TRUE @@ -48,6 +64,9 @@ var/atom/anchor var/image/menu_holder var/finished = FALSE + var/datum/callback/custom_check_callback + var/next_check = 0 + var/check_delay = DEFAULT_CHECK_DELAY var/radius = 32 var/starting_angle = 0 @@ -57,7 +76,7 @@ var/max_elements var/pages = 1 var/current_page = 1 - + var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift var/py_shift = 0 var/entry_animation = TRUE @@ -75,7 +94,7 @@ restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth. //Sets defaults -//These assume 45 deg min_angle +//These assume 45 deg min_angle /datum/radial_menu/proc/restrict_to_dir(dir) switch(dir) if(NORTH) @@ -91,18 +110,19 @@ starting_angle = 180 ending_angle = 45 -/datum/radial_menu/proc/setup_menu() +/datum/radial_menu/proc/setup_menu(use_tooltips) if(ending_angle > starting_angle) zone = ending_angle - starting_angle else zone = 360 - starting_angle + ending_angle - + max_elements = round(zone / min_angle) var/paged = max_elements < choices.len if(elements.len < max_elements) var/elements_to_add = max_elements - elements.len for(var/i in 1 to elements_to_add) //Create all elements - var/obj/screen/radial/new_element = new /obj/screen/radial/slice + var/obj/screen/radial/slice/new_element = new /obj/screen/radial/slice + new_element.tooltips = use_tooltips new_element.parent = src elements += new_element @@ -163,7 +183,7 @@ else E.pixel_y = py E.pixel_x = px - + //Visuals E.alpha = 255 E.mouse_opacity = MOUSE_OPACITY_ICON @@ -183,7 +203,7 @@ E.next_page = FALSE if(choices_icons[choice_id]) E.add_overlay(choices_icons[choice_id]) - + /datum/radial_menu/New() close_button = new close_button.parent = src @@ -200,7 +220,7 @@ /datum/radial_menu/proc/get_next_id() return "c_[choices.len]" -/datum/radial_menu/proc/set_choices(list/new_choices) +/datum/radial_menu/proc/set_choices(list/new_choices, use_tooltips) if(choices.len) Reset() for(var/E in new_choices) @@ -211,7 +231,7 @@ var/I = extract_image(new_choices[E]) if(I) choices_icons[id] = I - setup_menu() + setup_menu(use_tooltips) /datum/radial_menu/proc/extract_image(E) @@ -220,7 +240,7 @@ MA.layer = ABOVE_HUD_LAYER MA.appearance_flags |= RESET_TRANSFORM return MA - + /datum/radial_menu/proc/next_page() if(pages > 1) @@ -243,28 +263,49 @@ if(current_user) current_user.images -= menu_holder -/datum/radial_menu/proc/wait() +/datum/radial_menu/proc/wait(atom/user, atom/anchor, require_near = FALSE) while (current_user && !finished && !selected_choice) + if(require_near && !in_range(anchor, user)) + return + if(custom_check_callback && next_check < world.time) + if(!custom_check_callback.Invoke()) + return + else + next_check = world.time + check_delay stoplag(1) /datum/radial_menu/Destroy() Reset() hide() + QDEL_NULL(custom_check_callback) . = ..() + /* - Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen) + Presents radial menu to user anchored to anchor (or user if the anchor is currently in users screen) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user,atom/anchor,list/choices) +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE) + if(!user || !anchor || !length(choices)) + return + if(!uniqueid) + uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" + + if(GLOB.radial_menus[uniqueid]) + return + var/datum/radial_menu/menu = new - if(!user) - user = usr + GLOB.radial_menus[uniqueid] = menu + if(radius) + menu.radius = radius + if(istype(custom_check)) + menu.custom_check_callback = custom_check menu.anchor = anchor menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud - menu.set_choices(choices) + menu.set_choices(choices, tooltips) menu.show_to(user) - menu.wait() + menu.wait(user, anchor, require_near) var/answer = menu.selected_choice qdel(menu) + GLOB.radial_menus -= uniqueid return answer \ No newline at end of file diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm new file mode 100644 index 0000000000..0b5e8dc356 --- /dev/null +++ b/code/_onclick/hud/radial_persistent.dm @@ -0,0 +1,76 @@ +/* + A derivative of radial menu which persists onscreen until closed and invokes a callback each time an element is clicked +*/ + +/obj/screen/radial/persistent/center + name = "Close Menu" + icon_state = "radial_center" + +/obj/screen/radial/persistent/center/Click(location, control, params) + if(usr.client == parent.current_user) + parent.element_chosen(null,usr) + +/obj/screen/radial/persistent/center/MouseEntered(location, control, params) + . = ..() + icon_state = "radial_center_focus" + +/obj/screen/radial/persistent/center/MouseExited(location, control, params) + . = ..() + icon_state = "radial_center" + + + +/datum/radial_menu/persistent + var/uniqueid + var/datum/callback/select_proc_callback + +/datum/radial_menu/persistent/New() + close_button = new /obj/screen/radial/persistent/center + close_button.parent = src + + +/datum/radial_menu/persistent/element_chosen(choice_id,mob/user) + select_proc_callback.Invoke(choices_values[choice_id]) + + +/datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips) + if(!newchoices.len) + return + Reset() + set_choices(newchoices,tooltips) + +/datum/radial_menu/persistent/Destroy() + QDEL_NULL(select_proc_callback) + GLOB.radial_menus -= uniqueid + Reset() + hide() + . = ..() + +/* + Creates a persistent radial menu and shows it to the user, anchored to anchor (or user if the anchor is currently in users screen). + Choices should be a list where list keys are movables or text used for element names and return value + and list values are movables/icons/images used for element icons + Select_proc is the proc to be called each time an element on the menu is clicked, and should accept the chosen element as its final argument + Clicking the center button will return a choice of null +*/ +/proc/show_radial_menu_persistent(mob/user, atom/anchor, list/choices, datum/callback/select_proc, uniqueid, radius, tooltips = FALSE) + if(!user || !anchor || !length(choices) || !select_proc) + return + if(!uniqueid) + uniqueid = "defmenu_[REF(user)]_[REF(anchor)]" + + if(GLOB.radial_menus[uniqueid]) + return + + var/datum/radial_menu/persistent/menu = new + menu.uniqueid = uniqueid + GLOB.radial_menus[uniqueid] = menu + if(radius) + menu.radius = radius + menu.select_proc_callback = select_proc + menu.anchor = anchor + menu.check_screen_border(user) //Do what's needed to make it look good near borders or on hud + menu.set_choices(choices, tooltips) + menu.show_to(user) + return menu + diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index d23d0905e9..2a14d232aa 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -64,7 +64,7 @@ to_chat(user, "You're too exhausted.") // CIT CHANGE - ditto return // CIT CHANGE - ditto - if(force && user.has_trait(TRAIT_PACIFISM)) + if(force && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm other living beings!") return diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index de58c1a0d7..77ad712b99 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -116,7 +116,7 @@ SUBSYSTEM_DEF(throwing) return dist_travelled++ - + if (dist_travelled > MAX_THROWING_DIST) finalize() return @@ -154,7 +154,7 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing/proc/hitcheck() for (var/thing in get_turf(thrownthing)) var/atom/movable/AM = thing - if (AM == thrownthing) + if (AM == thrownthing || (AM == thrower && !ismob(thrownthing))) continue if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags_1 & ON_BORDER_1)) finalize(hit=TRUE, target=AM) diff --git a/code/datums/action.dm b/code/datums/action.dm index b7089279cb..f64a549b29 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -195,11 +195,16 @@ /datum/action/item_action/toggle_firemode name = "Toggle Firemode" -/datum/action/item_action/rcl +/datum/action/item_action/rcl_col name = "Change Cable Color" icon_icon = 'icons/mob/actions/actions_items.dmi' button_icon_state = "rcl_rainbow" +/datum/action/item_action/rcl_gui + name = "Toggle Fast Wiring Gui" + icon_icon = 'icons/mob/actions/actions_items.dmi' + button_icon_state = "rcl_gui" + /datum/action/item_action/startchainsaw name = "Pull The Starting Cord" diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm index afd53726db..f2fec3bb63 100644 --- a/code/datums/brain_damage/mild.dm +++ b/code/datums/brain_damage/mild.dm @@ -42,7 +42,7 @@ lose_text = "You feel smart again." /datum/brain_trauma/mild/dumbness/on_gain() - owner.add_trait(TRAIT_DUMB, TRAUMA_TRAIT) + ADD_TRAIT(owner, TRAIT_DUMB, TRAUMA_TRAIT) SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "dumb", /datum/mood_event/oblivious) ..() @@ -55,7 +55,7 @@ ..() /datum/brain_trauma/mild/dumbness/on_lose() - owner.remove_trait(TRAIT_DUMB, TRAUMA_TRAIT) + REMOVE_TRAIT(owner, TRAIT_DUMB, TRAUMA_TRAIT) owner.derpspeech = 0 SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "dumb") ..() diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index f2d96c9e4d..852b6b93c2 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -13,11 +13,11 @@ lose_text = "You suddenly remember how to speak." /datum/brain_trauma/severe/mute/on_gain() - owner.add_trait(TRAIT_MUTE, TRAUMA_TRAIT) + ADD_TRAIT(owner, TRAIT_MUTE, TRAUMA_TRAIT) ..() /datum/brain_trauma/severe/mute/on_lose() - owner.remove_trait(TRAIT_MUTE, TRAUMA_TRAIT) + REMOVE_TRAIT(owner, TRAIT_MUTE, TRAUMA_TRAIT) ..() /datum/brain_trauma/severe/aphasia @@ -171,7 +171,7 @@ stress -= 4 /datum/brain_trauma/severe/monophobia/proc/check_alone() - if(owner.has_trait(TRAIT_BLIND)) + if(HAS_TRAIT(owner, TRAIT_BLIND)) return TRUE for(var/mob/M in oview(owner, 7)) if(!isliving(M)) //ghosts ain't people @@ -233,11 +233,11 @@ lose_text = "You feel in control of your hands again." /datum/brain_trauma/severe/discoordination/on_gain() - owner.add_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT) + ADD_TRAIT(owner, TRAIT_MONKEYLIKE, TRAUMA_TRAIT) ..() /datum/brain_trauma/severe/discoordination/on_lose() - owner.remove_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT) + REMOVE_TRAIT(owner, TRAIT_MONKEYLIKE, TRAUMA_TRAIT) ..() /datum/brain_trauma/severe/pacifism @@ -248,9 +248,9 @@ lose_text = "You no longer feel compelled to not harm." /datum/brain_trauma/severe/pacifism/on_gain() - owner.add_trait(TRAIT_PACIFISM, TRAUMA_TRAIT) + ADD_TRAIT(owner, TRAIT_PACIFISM, TRAUMA_TRAIT) ..() /datum/brain_trauma/severe/pacifism/on_lose() - owner.remove_trait(TRAIT_PACIFISM, TRAUMA_TRAIT) + REMOVE_TRAIT(owner, TRAIT_PACIFISM, TRAUMA_TRAIT) ..() diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index 9ce65717f1..612af13392 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -192,7 +192,7 @@ return //no random switching /datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq) - if(owner.has_trait(TRAIT_DEAF) || owner == speaker) + if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == speaker) return message if(findtext(message, codeword)) message = replacetext(message, codeword, "[codeword]") diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index 1e1b7a0a48..838a1b576a 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -24,7 +24,7 @@ if(ishuman(AM)) var/mob/living/carbon/human/H = AM - if(H.has_trait(TRAIT_PIERCEIMMUNE)) + if(HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) return if((flags & CALTROP_IGNORE_WALKERS) && H.m_intent == MOVE_INTENT_WALK) @@ -46,7 +46,7 @@ return var/damage = rand(min_damage, max_damage) - if(H.has_trait(TRAIT_LIGHT_STEP)) + if(HAS_TRAIT(H, TRAIT_LIGHT_STEP)) damage *= 0.75 H.apply_damage(damage, BRUTE, picked_def_zone) diff --git a/code/datums/components/earhealing.dm b/code/datums/components/earhealing.dm index 9396eab3a3..6eb71285e0 100644 --- a/code/datums/components/earhealing.dm +++ b/code/datums/components/earhealing.dm @@ -23,7 +23,7 @@ if (!wearer) STOP_PROCESSING(SSobj, src) return - if(!wearer.has_trait(TRAIT_DEAF)) + if(!HAS_TRAIT(wearer, TRAIT_DEAF)) var/obj/item/organ/ears/ears = wearer.getorganslot(ORGAN_SLOT_EARS) if (ears) ears.deaf = max(ears.deaf - 1, (ears.ear_damage < UNHEALING_EAR_DAMAGE ? 0 : 1)) // Do not clear deafness while above the unhealing ear damage threshold diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 933c38505b..b32921a4ce 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -15,7 +15,7 @@ /datum/component/mood/Initialize() if(!isliving(parent)) return COMPONENT_INCOMPATIBLE - + START_PROCESSING(SSmood, src) RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event) @@ -150,17 +150,17 @@ else owner.crit_threshold -= (holdmyinsanityeffect - insanity_effect) - if(owner.has_trait(TRAIT_DEPRESSION)) + if(HAS_TRAIT(owner, TRAIT_DEPRESSION)) if(prob(0.05)) add_event(null, "depression", /datum/mood_event/depression) clear_event(null, "jolly") - if(owner.has_trait(TRAIT_JOLLY)) + if(HAS_TRAIT(owner, TRAIT_JOLLY)) if(prob(0.05)) add_event(null, "jolly", /datum/mood_event/jolly) clear_event(null, "depression") holdmyinsanityeffect = insanity_effect - + HandleNutrition(owner) /datum/component/mood/proc/DecreaseSanity(amount, minimum = SANITY_INSANE) diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm index 4d7e8bddc5..0b78605869 100644 --- a/code/datums/components/storage/concrete/_concrete.dm +++ b/code/datums/components/storage/concrete/_concrete.dm @@ -6,6 +6,8 @@ /datum/component/storage/concrete var/drop_all_on_deconstruct = TRUE var/drop_all_on_destroy = FALSE + var/drop_all_on_break = FALSE + var/unlock_on_break = FALSE var/transfer_contents_on_component_transfer = FALSE var/list/datum/component/storage/slaves = list() @@ -16,6 +18,7 @@ . = ..() RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del) RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct) + RegisterSignal(parent, COMSIG_OBJ_BREAK, .proc/on_break) /datum/component/storage/concrete/Destroy() var/atom/real_location = real_location() @@ -100,6 +103,12 @@ if(drop_all_on_deconstruct) do_quick_empty() +/datum/component/storage/concrete/proc/on_break(datum/source, damage_flag) + if(drop_all_on_break) + do_quick_empty() + if(unlock_on_break) + set_locked(source, FALSE) + /datum/component/storage/concrete/can_see_contents() . = ..() for(var/i in slaves) diff --git a/code/datums/components/storage/concrete/emergency.dm b/code/datums/components/storage/concrete/emergency.dm new file mode 100644 index 0000000000..e5f9d83a17 --- /dev/null +++ b/code/datums/components/storage/concrete/emergency.dm @@ -0,0 +1,22 @@ +/datum/component/storage/concrete/emergency + drop_all_on_break = TRUE + unlock_on_break = TRUE + locked = TRUE + +/datum/component/storage/concrete/emergency/Initialize() + . = ..() + RegisterSignal(parent, COMSIG_ATOM_EMAG_ACT, .proc/unlock_me) + +/datum/component/storage/concrete/emergency/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE) + if(!silent && istype(I, /obj/item/card/emag)) + silent = TRUE // suppresses the message + return ..() + +/datum/component/storage/concrete/check_locked(datum/source, mob/user, message = FALSE) + . = locked && GLOB.security_level < SEC_LEVEL_RED + if(message && . && user) + to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.") + +/datum/component/storage/concrete/emergency/proc/unlock_me(datum/source) + if(locked) + set_locked(source, FALSE) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index dc25729e37..869fe59ae9 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -156,8 +156,7 @@ next += slave.parent /datum/component/storage/proc/attack_self(datum/source, mob/M) - if(locked) - to_chat(M, "[parent] seems to be locked!") + if(check_locked(source, M, TRUE)) return FALSE if((M.get_active_held_item() == parent) && allow_quick_empty) quick_empty(M) @@ -166,8 +165,7 @@ if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE)) return FALSE . = COMPONENT_NO_ATTACK - if(locked) - to_chat(M, "[parent] seems to be locked!") + if(check_locked(source, M, TRUE)) return FALSE var/atom/A = parent var/obj/item/I = O @@ -238,8 +236,7 @@ var/atom/A = parent if((!ishuman(M) && (A.loc != M)) || (M.stat != CONSCIOUS) || M.restrained() || !M.canmove) return - if(locked) - to_chat(M, "[parent] seems to be locked!") + if(check_locked(null, M, TRUE)) return FALSE A.add_fingerprint(M) to_chat(M, "You start dumping out [parent].") @@ -281,7 +278,7 @@ /datum/component/storage/proc/set_locked(datum/source, new_state) locked = new_state - if(locked) + if(check_locked()) close_all() /datum/component/storage/proc/_process_numerical_display() @@ -456,8 +453,7 @@ var/atom/A = parent var/atom/dump_destination = dest_object.get_dumping_location() if(A.Adjacent(M) && dump_destination && M.Adjacent(dump_destination)) - if(locked) - to_chat(M, "[parent] seems to be locked!") + if(check_locked(null, M, TRUE)) return FALSE if(dump_destination.storage_contents_dump_act(src, M)) playsound(A, "rustle", 50, 1, -5) @@ -563,10 +559,9 @@ var/atom/host = parent if(real_location == I.loc) return FALSE //Means the item is already in the storage item - if(locked) + if(check_locked(null, M, !stop_messages)) if(M && !stop_messages) host.add_fingerprint(M) - to_chat(M, "[host] seems to be locked!") return FALSE if(real_location.contents.len >= max_items) if(!stop_messages) @@ -659,8 +654,10 @@ /datum/component/storage/proc/on_check() return TRUE -/datum/component/storage/proc/check_locked() - return locked +/datum/component/storage/proc/check_locked(datum/source, mob/user, message = FALSE) + . = locked + if(message && . && user) + to_chat(user, "[parent] seems to be locked!") /datum/component/storage/proc/signal_take_type(datum/source, type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted) if(!force) @@ -720,9 +717,7 @@ if(A.loc == user) . = COMPONENT_NO_ATTACK_HAND - if(locked) - to_chat(user, "[parent] seems to be locked!") - else + if(!check_locked(source, user, TRUE)) show_to(user) A.do_jiggle() @@ -747,8 +742,7 @@ /datum/component/storage/proc/on_alt_click(datum/source, mob/user) if(!isliving(user) || !user.CanReach(parent)) return - if(locked) - to_chat(user, "[parent] seems to be locked!") + if(check_locked(source, user, TRUE)) return var/atom/A = parent diff --git a/code/datums/datum.dm b/code/datums/datum.dm index e74e30b536..cdb195dd82 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -2,6 +2,7 @@ var/gc_destroyed //Time when this object was destroyed. var/list/active_timers //for SStimer var/list/datum_components //for /datum/components + var/list/status_traits var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register var/list/signal_procs var/signal_enabled = FALSE diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index ba570eca06..e1432bf9a6 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -117,7 +117,7 @@ /mob/living/carbon/AirborneContractDisease(datum/disease/D, force_spread) if(internal) return - if(has_trait(TRAIT_NOBREATH)) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) return ..() @@ -137,7 +137,7 @@ /mob/living/carbon/human/CanContractDisease(datum/disease/D) if(dna) - if(has_trait(TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity) + if(HAS_TRAIT(src, TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity) return FALSE for(var/thing in D.required_organs) diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index 0ace2ca8fd..e666c7acd6 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -233,7 +233,7 @@ /datum/symptom/heal/coma/CanHeal(datum/disease/advance/A) var/mob/living/M = A.affected_mob - if(M.has_trait(TRAIT_DEATHCOMA)) + if(HAS_TRAIT(M, TRAIT_DEATHCOMA)) return power else if(M.IsUnconscious() || M.stat == UNCONSCIOUS) return power * 0.9 @@ -364,15 +364,15 @@ /datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A) var/mob/living/M = A.affected_mob var/datum/gas_mixture/environment - var/list/gases + var/plasmamount . = 0 if(M.loc) environment = M.loc.return_air() if(environment) - gases = environment.gases - if(gases["plasma"] && gases["plasma"][MOLES] > gases["plasma"][GAS_META][META_GAS_MOLES_VISIBLE]) //if there's enough plasma in the air to see + plasmamount = environment.gases[/datum/gas/plasma] + if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see . += power * 0.5 if(M.reagents.has_reagent("plasma")) . += power * 0.75 diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index ffc145bd72..8d7cc5ed70 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -85,14 +85,14 @@ if(4, 5) M.restoreEars() - if(M.has_trait(TRAIT_BLIND, EYE_DAMAGE)) + if(HAS_TRAIT_FROM(M, TRAIT_BLIND, EYE_DAMAGE)) if(prob(20)) to_chat(M, "Your vision slowly returns...") M.cure_blind(EYE_DAMAGE) M.cure_nearsighted(EYE_DAMAGE) M.blur_eyes(35) - else if(M.has_trait(TRAIT_NEARSIGHT, EYE_DAMAGE)) + else if(HAS_TRAIT_FROM(M, TRAIT_NEARSIGHT, EYE_DAMAGE)) to_chat(M, "You can finally focus your eyes on distant objects.") M.cure_nearsighted(EYE_DAMAGE) M.blur_eyes(10) diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index 0b42012f76..d1cc6905a6 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -61,7 +61,7 @@ Bonus M.become_nearsighted(EYE_DAMAGE) if(prob(eyes.eye_damage - 10 + 1)) if(!remove_eyes) - if(!M.has_trait(TRAIT_BLIND)) + if(!HAS_TRAIT(M, TRAIT_BLIND)) to_chat(M, "You go blind!") M.become_blind(EYE_DAMAGE) else diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm index 57cdb9bcf5..6c91cc3a7d 100644 --- a/code/datums/emotes.dm +++ b/code/datums/emotes.dm @@ -133,7 +133,7 @@ if(isliving(user)) var/mob/living/L = user - if(L.has_trait(TRAIT_EMOTEMUTE)) + if(HAS_TRAIT(L, TRAIT_EMOTEMUTE)) return FALSE /datum/emote/sound diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index d673cdb16d..0623e2f5f9 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -103,11 +103,11 @@ // Can most things breathe? if(trace_gases) continue - if(!(A_gases[/datum/gas/oxygen] && A_gases[/datum/gas/oxygen][MOLES] >= 16)) + if(A_gases[/datum/gas/oxygen] >= 16) continue if(A_gases[/datum/gas/plasma]) continue - if(A_gases[/datum/gas/carbon_dioxide] && A_gases[/datum/gas/carbon_dioxide][MOLES] >= 10) + if(A_gases[/datum/gas/carbon_dioxide] >= 10) continue // Aim for goldilocks temperatures and pressure diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index 8a5f0f9439..127413262c 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -86,13 +86,13 @@ return 0 /datum/martial_art/krav_maga/proc/leg_sweep(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) - if(D.stat || D.IsKnockdown()) + if(D.lying || D.IsKnockdown()) return 0 D.visible_message("[A] leg sweeps [D]!", \ "[A] leg sweeps you!") playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1) D.apply_damage(5, BRUTE) - D.Knockdown(40) + D.Knockdown(40, override_hardstun = 0.01, 25) log_combat(A, D, "leg sweeped") return 1 @@ -191,3 +191,18 @@ heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE + +/obj/item/clothing/gloves/krav_maga/combatglovesplus + name = "combat gloves plus" + desc = "These tactical gloves are fireproof and shock resistant, and using nanochip technology it teaches you the powers of krav maga." + icon_state = "black" + item_state = "blackglovesplus" + siemens_coefficient = 0 + permeability_coefficient = 0.05 + strip_delay = 80 + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + resistance_flags = NONE + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 50) diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index 4a15afd672..035e5ac833 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -179,7 +179,7 @@ /obj/item/twohanded/bostaff/attack(mob/target, mob/living/user) add_fingerprint(user) - if((user.has_trait(TRAIT_CLUMSY)) && prob(50)) + if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50)) to_chat(user, "You club yourself over the head with [src].") user.Knockdown(60) if(ishuman(user)) diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index 4021d11128..06857c0f55 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -125,3 +125,11 @@ /datum/mood_event/surgery description = "HE'S CUTTING ME OPEN!!\n" mood_change = -8 + +/datum/mood_event/sad_empath + description = "Someone seems upset...\n" + mood_change = -2 + timeout = 600 + +/datum/mood_event/sad_empath/add_effects(mob/sadtarget) + description = "[sadtarget.name] seems upset...\n" diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm index 6989744fe3..051a548d1d 100644 --- a/code/datums/mood_events/generic_positive_events.dm +++ b/code/datums/mood_events/generic_positive_events.dm @@ -75,3 +75,27 @@ description = "There is something soothing about this music.\n" mood_change = 3 timeout = 600 + +/datum/mood_event/betterhug + description = "Someone was very nice to me.\n" + mood_change = 3 + timeout = 3000 + +/datum/mood_event/betterhug/add_effects(mob/friend) + description = "[friend.name] was very nice to me.\n" + +/datum/mood_event/besthug + description = "Someone is great to be around, they make me feel so happy!\n" + mood_change = 5 + timeout = 3000 + +/datum/mood_event/besthug/add_effects(mob/friend) + description = "[friend.name] is great to be around, [friend.p_they()] makes me feel so happy!\n" + +/datum/mood_event/happy_empath + description = "Someone seems happy!\n" + mood_change = 2 + timeout = 600 + +/datum/mood_event/happy_empath/add_effects(var/mob/happytarget) + description = "[happytarget.name]'s happiness is infectious!\n" diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index e114a43736..461c221ff8 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -86,12 +86,12 @@ /datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.add_trait(TRAIT_CLUMSY, GENETIC_MUTATION) + ADD_TRAIT(owner, TRAIT_CLUMSY, GENETIC_MUTATION) /datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.remove_trait(TRAIT_CLUMSY, GENETIC_MUTATION) + REMOVE_TRAIT(owner, TRAIT_CLUMSY, GENETIC_MUTATION) //Tourettes causes you to randomly stand in place and shout. @@ -125,12 +125,12 @@ /datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.add_trait(TRAIT_DEAF, GENETIC_MUTATION) + ADD_TRAIT(owner, TRAIT_DEAF, GENETIC_MUTATION) /datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.remove_trait(TRAIT_DEAF, GENETIC_MUTATION) + REMOVE_TRAIT(owner, TRAIT_DEAF, GENETIC_MUTATION) //Monified turns you into a monkey. diff --git a/code/datums/mutations/cold_resistance.dm b/code/datums/mutations/cold_resistance.dm index 6c3ac2982d..3d8fbababa 100644 --- a/code/datums/mutations/cold_resistance.dm +++ b/code/datums/mutations/cold_resistance.dm @@ -17,14 +17,14 @@ /datum/mutation/human/cold_resistance/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.add_trait(TRAIT_RESISTCOLD, "cold_resistance") -// owner.add_trait(TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE + ADD_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance") +// ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE /datum/mutation/human/cold_resistance/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.remove_trait(TRAIT_RESISTCOLD, "cold_resistance") -// owner.remove_trait(TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE + REMOVE_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance") +// REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance") CITADEL CHANGE /datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner) if(owner.getFireLoss()) diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index 7bcd056fab..0c760f4620 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -11,8 +11,8 @@ /datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.add_trait(TRAIT_STUNIMMUNE, TRAIT_HULK) - owner.add_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK) + ADD_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK) + ADD_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK) owner.update_body_parts() SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk) @@ -28,8 +28,8 @@ /datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.remove_trait(TRAIT_STUNIMMUNE, TRAIT_HULK) - owner.remove_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK) + REMOVE_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK) + REMOVE_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK) owner.update_body_parts() SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "hulk") diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 3f303535ce..d986672924 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -30,12 +30,12 @@ /datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.add_trait(TRAIT_MUTE, GENETIC_MUTATION) + ADD_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION) /datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.remove_trait(TRAIT_MUTE, GENETIC_MUTATION) + REMOVE_TRAIT(owner, TRAIT_MUTE, GENETIC_MUTATION) /datum/mutation/human/smile @@ -229,4 +229,4 @@ /datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner) ..() owner.grant_language(/datum/language/common) - owner.remove_language(/datum/language/beachbum) + owner.remove_language(/datum/language/beachbum) \ No newline at end of file diff --git a/code/datums/saymode.dm b/code/datums/saymode.dm index ed6edd11ab..c4f485653e 100644 --- a/code/datums/saymode.dm +++ b/code/datums/saymode.dm @@ -27,7 +27,7 @@ switch(M.lingcheck()) if (LINGHIVE_LING) var/mob/living/L = M - if (!L.has_trait(CHANGELING_HIVEMIND_MUTE)) + if (!HAS_TRAIT(L, CHANGELING_HIVEMIND_MUTE)) to_chat(M, msg) if(LINGHIVE_LINK) to_chat(M, msg) @@ -35,7 +35,7 @@ if(prob(40)) to_chat(M, "We can faintly sense an outsider trying to communicate through the hivemind...") if(LINGHIVE_LING) - if (user.has_trait(CHANGELING_HIVEMIND_MUTE)) + if (HAS_TRAIT(user, CHANGELING_HIVEMIND_MUTE)) to_chat(user, "The poison in the air hinders our ability to interact with the hivemind.") return FALSE var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) @@ -52,7 +52,7 @@ to_chat(M, msg) if(LINGHIVE_LING) var/mob/living/L = M - if (!L.has_trait(CHANGELING_HIVEMIND_MUTE)) + if (!HAS_TRAIT(L, CHANGELING_HIVEMIND_MUTE)) to_chat(M, msg) if(LINGHIVE_OUTSIDER) if(prob(40)) diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index dd8ee1b166..0512977d1a 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -465,13 +465,13 @@ /datum/status_effect/hippocraticOath/on_apply() //Makes the user passive, it's in their oath not to harm! - owner.add_trait(TRAIT_PACIFISM, "hippocraticOath") + ADD_TRAIT(owner, TRAIT_PACIFISM, "hippocraticOath") var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] H.add_hud_to(owner) return ..() /datum/status_effect/hippocraticOath/on_remove() - owner.remove_trait(TRAIT_PACIFISM, "hippocraticOath") + REMOVE_TRAIT(owner, TRAIT_PACIFISM, "hippocraticOath") var/datum/atom_hud/H = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] H.remove_hud_from(owner) diff --git a/code/datums/traits/_quirk.dm b/code/datums/traits/_quirk.dm index 963afacec3..cc6dd8db3f 100644 --- a/code/datums/traits/_quirk.dm +++ b/code/datums/traits/_quirk.dm @@ -21,7 +21,7 @@ to_chat(quirk_holder, gain_text) quirk_holder.roundstart_quirks += src if(mob_trait) - quirk_holder.add_trait(mob_trait, ROUNDSTART_TRAIT) + ADD_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT) START_PROCESSING(SSquirks, src) add() if(spawn_effects) @@ -35,7 +35,7 @@ to_chat(quirk_holder, lose_text) quirk_holder.roundstart_quirks -= src if(mob_trait) - quirk_holder.remove_trait(mob_trait, ROUNDSTART_TRAIT, TRUE) + REMOVE_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT) SSquirks.quirk_objects -= src return ..() @@ -43,8 +43,8 @@ quirk_holder.roundstart_quirks -= src to_mob.roundstart_quirks += src if(mob_trait) - quirk_holder.remove_trait(mob_trait, ROUNDSTART_TRAIT) - to_mob.add_trait(mob_trait, ROUNDSTART_TRAIT) + REMOVE_TRAIT(quirk_holder, mob_trait, ROUNDSTART_TRAIT) + ADD_TRAIT(to_mob, mob_trait, ROUNDSTART_TRAIT) quirk_holder = to_mob on_transfer() @@ -111,7 +111,7 @@ Use this as a guideline mob_trait = TRAIT_NEARSIGHT ///This define is in __DEFINES/traits.dm and is the actual "trait" that the game tracks - ///You'll need to use "has_trait(X, sources)" checks around the code to check this; for instance, the Ageusia trait is checked in taste code + ///You'll need to use "HAS_TRAIT_FROM(src, X, sources)" checks around the code to check this; for instance, the Ageusia trait is checked in taste code ///If you need help finding where to put it, the declaration finder on GitHub is the best way to locate it gain_text = "Things far away from you start looking blurry." diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm index 513115b194..300a1264eb 100644 --- a/code/datums/traits/good.dm +++ b/code/datums/traits/good.dm @@ -35,6 +35,14 @@ lose_text = "You no longer feel like drinking would ease your pain." medical_record_text = "Patient has unusually efficient liver metabolism and can slowly regenerate wounds by drinking alcoholic beverages." +/datum/quirk/empath + name = "Empath" + desc = "Whether it's a sixth sense or careful study of body language, it only takes you a quick glance at someone to understand how they feel." + value = 2 + mob_trait = TRAIT_EMPATH + gain_text = "You feel in tune with those around you." + lose_text = "You feel isolated from others." + /datum/quirk/freerunning name = "Freerunning" desc = "You're great at quick moves! You can climb tables more quickly." @@ -43,6 +51,15 @@ gain_text = "You feel lithe on your feet!" lose_text = "You feel clumsy again." +/datum/quirk/friendly + name = "Friendly" + desc = "You give the best hugs, especially when you're in the right mood." + value = 1 + mob_trait = TRAIT_FRIENDLY + gain_text = "You want to hug someone." + lose_text = "You no longer feel compelled to hug others." + mood_quirk = TRUE + /datum/quirk/jolly name = "Jolly" desc = "You sometimes just feel happy, for no reason at all." diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index aba9404d9a..7c13310af8 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -60,7 +60,7 @@ if("Scientist") heirloom_type = /obj/item/toy/plush/slimeplushie if("Assistant") - heirloom_type = /obj/item/storage/toolbox/mechanical/old/heirloom + heirloom_type = /obj/item/clothing/gloves/cut/family if("Chaplain") heirloom_type = /obj/item/camera/spooky/family if("Captain") diff --git a/code/datums/traits/neutral.dm b/code/datums/traits/neutral.dm index f299e9904a..f70e3a3c68 100644 --- a/code/datums/traits/neutral.dm +++ b/code/datums/traits/neutral.dm @@ -93,3 +93,12 @@ gain_text = "You feel more prudish." lose_text = "You don't feel as prudish as before." medical_record_text = "Patient exhibits a special gene that makes them immune to Crocin and Hexacrocin." + +/datum/quirk/assblastusa + name = "Buns of Steel" + desc = "You've never skipped ass day. With this trait, you are completely immune to all forms of ass slapping and anyone who tries to slap your rock hard ass usually gets a broken hand." + mob_trait = TRAIT_ASSBLASTUSA + value = 0 + medical_record_text = "Patient never skipped ass day." + gain_text = "Your ass rivals those of golems." + lose_text = "Your butt feels more squishy and slappable." \ No newline at end of file diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm index 0906a7e053..f3b8118087 100644 --- a/code/datums/weather/weather_types/radiation_storm.dm +++ b/code/datums/weather/weather_types/radiation_storm.dm @@ -33,7 +33,7 @@ if(prob(40)) if(ishuman(L)) var/mob/living/carbon/human/H = L - if(H.dna && !H.has_trait(TRAIT_RADIMMUNE)) + if(H.dna && !HAS_TRAIT(H, TRAIT_RADIMMUNE)) if(prob(max(0,100-resist))) H.randmuti() if(prob(50)) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 48596a0b6d..81e2371f9a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -6,7 +6,6 @@ var/flags_1 = NONE var/interaction_flags_atom = NONE - var/container_type = NONE var/datum/reagents/reagents = null //This atom's HUD (med/sec, etc) images. Associative list. @@ -203,16 +202,16 @@ return is_refillable() && is_drainable() /atom/proc/is_injectable(allowmobs = TRUE) - return reagents && (container_type & (INJECTABLE | REFILLABLE)) + return reagents && (reagents.reagents_holder_flags & (INJECTABLE | REFILLABLE)) /atom/proc/is_drawable(allowmobs = TRUE) - return reagents && (container_type & (DRAWABLE | DRAINABLE)) + return reagents && (reagents.reagents_holder_flags & (DRAWABLE | DRAINABLE)) /atom/proc/is_refillable() - return reagents && (container_type & REFILLABLE) + return reagents && (reagents.reagents_holder_flags & REFILLABLE) /atom/proc/is_drainable() - return reagents && (container_type & DRAINABLE) + return reagents && (reagents.reagents_holder_flags & DRAINABLE) /atom/proc/AllowDrop() @@ -261,7 +260,7 @@ to_chat(user, desc) if(reagents) - if(container_type & TRANSPARENT) + if(reagents.reagents_holder_flags & TRANSPARENT) to_chat(user, "It contains:") if(reagents.reagent_list.len) if(user.can_see_reagents()) //Show each individual reagent @@ -274,7 +273,7 @@ to_chat(user, "[total_volume] units of various reagents") else to_chat(user, "Nothing.") - else if(container_type & AMOUNT_VISIBLE) + else if(reagents.reagents_holder_flags & AMOUNT_VISIBLE) if(reagents.total_volume) to_chat(user, "It has [reagents.total_volume] unit\s left.") else diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e56f6d366c..c37c120b93 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -31,6 +31,7 @@ var/atom/movable/pulling var/grab_state = 0 var/throwforce = 0 + var/can_be_z_moved = TRUE /atom/movable/vv_edit_var(var_name, var_value) var/static/list/banned_edits = list("step_x", "step_y", "step_size") diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 3af43ffb78..8506a4133a 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -100,7 +100,7 @@ //helper for getting the appropriate health status /proc/RoundHealth(mob/living/M) - if(M.stat == DEAD || (M.has_trait(TRAIT_FAKEDEATH))) + if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_FAKEDEATH))) return "health-100" //what's our health? it doesn't matter, we're dead, or faking var/maxi_health = M.maxHealth if(iscarbon(M) && M.health < 0) @@ -172,7 +172,7 @@ var/image/holder = hud_list[STATUS_HUD] var/icon/I = icon(icon, icon_state, dir) holder.pixel_y = I.Height() - world.icon_size - if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH))) + if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) holder.icon_state = "huddead" else holder.icon_state = "hudhealthy" @@ -182,9 +182,9 @@ var/icon/I = icon(icon, icon_state, dir) var/virus_threat = check_virus() holder.pixel_y = I.Height() - world.icon_size - if(has_trait(TRAIT_XENO_HOST)) + if(HAS_TRAIT(src, TRAIT_XENO_HOST)) holder.icon_state = "hudxeno" - else if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH))) + else if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) if(tod) var/tdelta = round(world.time - timeofdeath) if(tdelta < (DEFIB_TIME_LIMIT * 10)) @@ -242,7 +242,7 @@ var/icon/IC = icon(icon, icon_state, dir) holder.pixel_y = IC.Height() - world.icon_size holder.icon_state = "hud_imp_chem" - if(has_trait(TRAIT_MINDSHIELD)) + if(HAS_TRAIT(src, TRAIT_MINDSHIELD)) holder = hud_list[IMPLOYAL_HUD] var/icon/IC = icon(icon, icon_state, dir) holder.pixel_y = IC.Height() - world.icon_size diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index d6513b5d40..a24d846f15 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -64,7 +64,7 @@ Credit where due: return FALSE if(isliving(M)) var/mob/living/L = M - if(L.has_trait(TRAIT_MINDSHIELD)) + if(HAS_TRAIT(L, TRAIT_MINDSHIELD)) return FALSE if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab) || istype(M, /mob/camera/eminence)) return TRUE @@ -131,7 +131,7 @@ Credit where due: config_tag = "clockwork_cult" antag_flag = ROLE_SERVANT_OF_RATVAR false_report_weight = 10 - required_players = 30 + required_players = 35 required_enemies = 3 recommended_enemies = 5 enemy_minimum_age = 7 diff --git a/code/game/gamemodes/clown_ops/clown_ops.dm b/code/game/gamemodes/clown_ops/clown_ops.dm index 12d3106c8d..a666b57afd 100644 --- a/code/game/gamemodes/clown_ops/clown_ops.dm +++ b/code/game/gamemodes/clown_ops/clown_ops.dm @@ -62,5 +62,6 @@ /datum/outfit/syndicate/clownop/leader name = "Clown Operative Leader - Basic" id = /obj/item/card/id/syndicate/nuke_leader + gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus r_hand = /obj/item/nuclear_challenge/clownops command_radio = TRUE diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 7b492e3a95..8f091b6372 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -26,7 +26,7 @@ return FALSE else return FALSE - if(M.has_trait(TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client) + if(HAS_TRAIT(M, TRAIT_MINDSHIELD) || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M) || !M.client) return FALSE //can't convert machines, shielded, braindead, or ratvar's dogs return TRUE diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index d76552982c..615d55a818 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -137,6 +137,7 @@ /datum/outfit/syndicate/leader name = "Syndicate Leader - Basic" id = /obj/item/card/id/syndicate/nuke_leader + gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus r_hand = /obj/item/nuclear_challenge command_radio = TRUE diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 7532d18d06..f6b1def645 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -542,6 +542,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) return checking.researched_nodes.len >= target_amount /datum/objective/capture + var/captured_amount = 0 /datum/objective/capture/proc/gen_amount_goal() target_amount = rand(5,10) @@ -549,8 +550,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) return target_amount /datum/objective/capture/check_completion()//Basically runs through all the mobs in the area to determine how much they are worth. - var/captured_amount = 0 - var/area/centcom/holding/A = GLOB.areas_by_type[/area/centcom/holding] + /*var/area/centcom/holding/A = GLOB.areas_by_type[/area/centcom/holding] for(var/mob/living/carbon/human/M in A)//Humans. if(M.stat == DEAD)//Dead folks are worth less. captured_amount+=0.5 @@ -573,7 +573,7 @@ GLOBAL_LIST_EMPTY(possible_items_special) if(M.stat == DEAD) captured_amount+=1 continue - captured_amount+=2 + captured_amount+=2*/ //Removed in favour of adding points on capture, in energy_net_nets.dm return captured_amount >= target_amount diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 6603bb3604..e56495d808 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -124,7 +124,7 @@ /datum/objective_item/steal/plasma/check_special_completion(obj/item/tank/T) var/target_amount = text2num(name) var/found_amount = 0 - found_amount += T.air_contents.gases[/datum/gas/plasma] ? T.air_contents.gases[/datum/gas/plasma][MOLES] : 0 + found_amount += T.air_contents.gases[/datum/gas/plasma] return found_amount>=target_amount diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index d3b5e53a1b..36a5c6ede4 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -182,11 +182,11 @@ //Get the clone body ready maim_clone(H) - H.add_trait(TRAIT_STABLEHEART, "cloning") - H.add_trait(TRAIT_EMOTEMUTE, "cloning") - H.add_trait(TRAIT_MUTE, "cloning") - H.add_trait(TRAIT_NOBREATH, "cloning") - H.add_trait(TRAIT_NOCRITDAMAGE, "cloning") + ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning") + ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning") + ADD_TRAIT(H, TRAIT_MUTE, "cloning") + ADD_TRAIT(H, TRAIT_NOBREATH, "cloning") + ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning") H.Unconscious(80) clonemind.transfer_to(H) @@ -361,11 +361,11 @@ if(!mob_occupant) return - mob_occupant.remove_trait(TRAIT_STABLEHEART, "cloning") - mob_occupant.remove_trait(TRAIT_EMOTEMUTE, "cloning") - mob_occupant.remove_trait(TRAIT_MUTE, "cloning") - mob_occupant.remove_trait(TRAIT_NOCRITDAMAGE, "cloning") - mob_occupant.remove_trait(TRAIT_NOBREATH, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_STABLEHEART, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_EMOTEMUTE, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_MUTE, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_NOCRITDAMAGE, "cloning") + REMOVE_TRAIT(mob_occupant, TRAIT_NOBREATH, "cloning") if(grab_ghost_when == CLONER_MATURE_CLONE) mob_occupant.grab_ghost() @@ -452,7 +452,7 @@ // brain function, they also have no limbs or internal organs. - if(!H.has_trait(TRAIT_NODISMEMBER)) + if(!HAS_TRAIT(H, TRAIT_NODISMEMBER)) var/static/list/zones = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) for(var/zone in zones) var/obj/item/bodypart/BP = H.get_bodypart(zone) diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 1f262c0979..efbbe36228 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -1,3 +1,9 @@ +#define ARCADE_WEIGHT_TRICK 4 +#define ARCADE_WEIGHT_USELESS 2 +#define ARCADE_WEIGHT_RARE 1 +#define ARCADE_WEIGHT_PLUSH 3 + + /obj/machinery/computer/arcade name = "random arcade" desc = "random arcade machine" @@ -6,55 +12,66 @@ icon_screen = "invaders" clockwork = TRUE //it'd look weird var/list/prizes = list( - /obj/item/storage/box/snappops = 8, - /obj/item/toy/talking/AI = 8, - /obj/item/toy/talking/codex_gigas = 8, - /obj/item/clothing/under/syndicate/tacticool = 8, - /obj/item/toy/sword = 8, - /obj/item/toy/gun = 8, - /obj/item/gun/ballistic/shotgun/toy/crossbow = 8, - /obj/item/storage/box/fakesyndiesuit = 8, - /obj/item/storage/crayons = 8, - /obj/item/toy/spinningtoy = 8, - /obj/item/toy/prize/ripley = 4, - /obj/item/toy/prize/fireripley = 4, - /obj/item/toy/prize/deathripley = 4, - /obj/item/toy/prize/gygax = 4, - /obj/item/toy/prize/durand = 4, - /obj/item/toy/prize/honk = 4, - /obj/item/toy/prize/marauder = 4, - /obj/item/toy/prize/seraph = 4, - /obj/item/toy/prize/mauler = 4, - /obj/item/toy/prize/odysseus = 4, - /obj/item/toy/prize/phazon = 4, - /obj/item/toy/prize/reticence = 4, - /obj/item/toy/cards/deck = 8, - /obj/item/toy/nuke = 8, - /obj/item/toy/minimeteor = 8, - /obj/item/toy/redbutton = 8, - /obj/item/toy/talking/owl = 8, - /obj/item/toy/talking/griffin = 8, - /obj/item/coin/antagtoken = 8, - /obj/item/stack/tile/fakespace/loaded = 8, - /obj/item/stack/tile/fakepit/loaded = 8, - /obj/item/toy/toy_xeno = 8, - /obj/item/storage/box/actionfigure = 4, - /obj/item/restraints/handcuffs/fake = 8, - /obj/item/grenade/chem_grenade/glitter/pink = 4, - /obj/item/grenade/chem_grenade/glitter/blue = 4, - /obj/item/grenade/chem_grenade/glitter/white = 4, - /obj/item/toy/eightball = 8, - /obj/item/toy/windupToolbox = 8, - /obj/item/toy/clockwork_watch = 8, - /obj/item/toy/toy_dagger = 8, - /obj/item/extendohand/acme = 4, - /obj/item/hot_potato/harmless/toy = 4, - /obj/item/card/emagfake = 4, - /obj/item/clothing/shoes/wheelys = 8, - /obj/item/clothing/shoes/kindleKicks = 8, - /obj/item/storage/belt/military/snack = 8, - /obj/item/toy/plush/random = 450 - )//plushies have a 0.6 chance + /obj/item/toy/balloon = ARCADE_WEIGHT_USELESS, + /obj/item/toy/beach_ball = ARCADE_WEIGHT_USELESS, + /obj/item/toy/cattoy = ARCADE_WEIGHT_USELESS, + /obj/item/toy/clockwork_watch = ARCADE_WEIGHT_TRICK, + /obj/item/toy/dummy = ARCADE_WEIGHT_TRICK, + /obj/item/toy/eightball = ARCADE_WEIGHT_USELESS, + /obj/item/toy/eightball/haunted = ARCADE_WEIGHT_RARE, + /obj/item/storage/box/actionfigure = ARCADE_WEIGHT_USELESS, + /obj/item/toy/foamblade = ARCADE_WEIGHT_TRICK, + /obj/item/toy/gun = ARCADE_WEIGHT_TRICK, + /obj/item/toy/gun/justicar = ARCADE_WEIGHT_TRICK, + /obj/item/toy/gun/m41 = ARCADE_WEIGHT_TRICK, + /obj/item/toy/katana = ARCADE_WEIGHT_TRICK, + /obj/item/toy/minimeteor = ARCADE_WEIGHT_TRICK, + /obj/item/toy/nuke = ARCADE_WEIGHT_TRICK, + /obj/item/toy/plush/random = ARCADE_WEIGHT_PLUSH, + /obj/item/toy/redbutton = ARCADE_WEIGHT_TRICK, + /obj/item/toy/spinningtoy = ARCADE_WEIGHT_TRICK, + /obj/item/toy/sword = ARCADE_WEIGHT_TRICK, + /obj/item/toy/sword/cx = ARCADE_WEIGHT_TRICK, + /obj/item/toy/sword/darksabre = ARCADE_WEIGHT_TRICK, + /obj/item/toy/talking/AI = ARCADE_WEIGHT_USELESS, + /obj/item/toy/talking/codex_gigas = ARCADE_WEIGHT_USELESS, + /obj/item/toy/talking/griffin = ARCADE_WEIGHT_USELESS, + /obj/item/toy/talking/owl = ARCADE_WEIGHT_USELESS, + /obj/item/toy/toy_dagger = ARCADE_WEIGHT_TRICK, + /obj/item/toy/toy_xeno = ARCADE_WEIGHT_TRICK, + /obj/item/toy/windupToolbox = ARCADE_WEIGHT_TRICK, + + /obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE, + /mob/living/simple_animal/bot/secbot/grievous/toy = ARCADE_WEIGHT_RARE, + /obj/item/clothing/mask/facehugger/toy = ARCADE_WEIGHT_RARE, + /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = ARCADE_WEIGHT_TRICK, + /obj/item/hot_potato/harmless/toy = ARCADE_WEIGHT_RARE, + /obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE, + /obj/item/twohanded/hypereutactic/toy = ARCADE_WEIGHT_RARE, + /obj/item/twohanded/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE, + + /obj/item/storage/box/snappops = ARCADE_WEIGHT_TRICK, + /obj/item/clothing/under/syndicate/tacticool = ARCADE_WEIGHT_TRICK, + /obj/item/gun/ballistic/shotgun/toy/crossbow = ARCADE_WEIGHT_TRICK, + /obj/item/storage/box/fakesyndiesuit = ARCADE_WEIGHT_TRICK, + /obj/item/storage/crayons = ARCADE_WEIGHT_USELESS, + /obj/item/coin/antagtoken = ARCADE_WEIGHT_USELESS, + /obj/item/stack/tile/fakespace/loaded = ARCADE_WEIGHT_TRICK, + /obj/item/stack/tile/fakepit/loaded = ARCADE_WEIGHT_TRICK, + /obj/item/restraints/handcuffs/fake = ARCADE_WEIGHT_TRICK, + + /obj/item/grenade/chem_grenade/glitter/pink = ARCADE_WEIGHT_TRICK, + /obj/item/grenade/chem_grenade/glitter/blue = ARCADE_WEIGHT_TRICK, + /obj/item/grenade/chem_grenade/glitter/white = ARCADE_WEIGHT_TRICK, + + /obj/item/extendohand/acme = ARCADE_WEIGHT_TRICK, + /obj/item/card/emagfake = ARCADE_WEIGHT_TRICK, + /obj/item/clothing/shoes/wheelys = ARCADE_WEIGHT_RARE, + /obj/item/clothing/shoes/kindleKicks = ARCADE_WEIGHT_RARE, + /obj/item/storage/belt/military/snack = ARCADE_WEIGHT_RARE, + + /obj/item/clothing/mask/fakemoustache/italian = ARCADE_WEIGHT_RARE + ) light_color = LIGHT_COLOR_GREEN @@ -74,7 +91,8 @@ /obj/machinery/computer/arcade/proc/prizevend(mob/user) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "arcade", /datum/mood_event/arcade) - if(prob(0.0001)) //1 in a million + + if(prob(1) && prob(1) && prob(1)) //Proper 1 in a million new /obj/item/gun/energy/pulse/prize(src) SSmedals.UnlockMedal(MEDAL_PULSE, usr.client) @@ -124,6 +142,8 @@ var/blocked = FALSE //Player cannot attack/heal while set var/turtle = 0 + var/turn_speed = 5 //Measured in deciseconds. + /obj/machinery/computer/arcade/battle/Reset() var/name_action var/name_part1 @@ -172,7 +192,7 @@ if(turtle > 0) turtle-- - sleep(10) + sleep(turn_speed) enemy_hp -= attackamt arcade_action(usr) @@ -185,7 +205,7 @@ updateUsrDialog() turtle++ - sleep(10) + sleep(turn_speed) player_mp -= pointamt player_hp += healamt blocked = TRUE @@ -202,7 +222,7 @@ turtle-- updateUsrDialog() - sleep(10) + sleep(turn_speed) arcade_action(usr) if (href_list["close"]) @@ -211,10 +231,10 @@ else if (href_list["newgame"]) //Reset everything temp = "New Round" - player_hp = 30 - player_mp = 10 - enemy_hp = 45 - enemy_mp = 20 + player_hp = initial(player_hp) + player_mp = initial(player_mp) + enemy_hp = initial(enemy_hp) + enemy_mp = initial(enemy_mp) gameover = FALSE turtle = 0 @@ -260,7 +280,7 @@ if (player_mp <= 0) gameover = TRUE - sleep(10) + sleep(turn_speed) temp = "You have been drained! GAME OVER" playsound(loc, 'sound/arcade/lose.ogg', 50, 1, extrarange = -3, falloff = 10) if(obj_flags & EMAGGED) diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index baa6fa577e..6576f51e46 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -59,8 +59,8 @@ var/total_moles = air_sample.total_moles() if(total_moles) for(var/gas_id in air_sample.gases) - var/gas_name = air_sample.gases[gas_id][GAS_META][META_GAS_NAME] - signal.data["gases"][gas_name] = air_sample.gases[gas_id][MOLES] / total_moles * 100 + var/gas_name = GLOB.meta_gas_names[gas_id] + signal.data["gases"][gas_name] = air_sample.gases[gas_id] / total_moles * 100 radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 00a5c8941d..39d5c3d56f 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -450,7 +450,7 @@ scantemp = "Subject's brain is not responding to scanning stimuli." playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return - if((mob_occupant.has_trait(TRAIT_NOCLONE)) && (src.scanner.scan_level < 2)) + if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2)) scantemp = "Subject no longer contains the fundamental materials required to create a living clone." playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0) return diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 43f5b96fbd..752765baa1 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -173,14 +173,15 @@ var/obj/machinery/shuttle_manipulator/M = locate() in GLOB.machines if(M) SSshuttle.shuttle_purchased = TRUE - M.unload_preview() - M.load_template(S) - M.existing_shuttle = SSshuttle.emergency - M.action_load(S) SSshuttle.points -= S.credit_cost minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase") message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].") SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]") + M.unload_preview() + M.load_template(S) + M.existing_shuttle = SSshuttle.emergency + M.action_load(S) + message_admins("[S.name] loaded, purchased by [usr]") else to_chat(usr, "Something went wrong! The shuttle exchange system seems to be down.") else diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 2980c741be..9d49574317 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -76,7 +76,7 @@ if(connected && connected.is_operational()) if(connected.occupant) //set occupant_status message viable_occupant = connected.occupant - if(viable_occupant.has_dna() && !viable_occupant.has_trait(TRAIT_RADIMMUNE) && !viable_occupant.has_trait(TRAIT_NOCLONE) || (connected.scan_level == 3)) //occupant is viable for dna modification + if(viable_occupant.has_dna() && !HAS_TRAIT(viable_occupant, TRAIT_RADIMMUNE) && !HAS_TRAIT(viable_occupant, TRAIT_NOCLONE) || (connected.scan_level == 3)) //occupant is viable for dna modification occupant_status += "[viable_occupant.name] => " switch(viable_occupant.stat) if(CONSCIOUS) @@ -523,7 +523,7 @@ var/mob/living/carbon/viable_occupant = null if(connected) viable_occupant = connected.occupant - if(!istype(viable_occupant) || !viable_occupant.dna || viable_occupant.has_trait(TRAIT_RADIMMUNE) || viable_occupant.has_trait(TRAIT_NOCLONE)) + if(!istype(viable_occupant) || !viable_occupant.dna || HAS_TRAIT(viable_occupant, TRAIT_RADIMMUNE) || HAS_TRAIT(viable_occupant, TRAIT_NOCLONE)) viable_occupant = null return viable_occupant diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm index 90a6b07733..7895fb8c9f 100644 --- a/code/game/machinery/dna_scanner.dm +++ b/code/game/machinery/dna_scanner.dm @@ -99,7 +99,7 @@ var/mob/living/mob_occupant = get_mob_or_brainmob(occupant) if(istype(mob_occupant)) if(locate_computer(/obj/machinery/computer/cloning)) - if(!mob_occupant.suiciding && !(mob_occupant.has_trait(TRAIT_NOCLONE)) && !mob_occupant.hellbound) + if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound) mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src) // DNA manipulators cannot operate on severed heads or brains diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 0183fcecd4..1081cb5fa7 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -763,7 +763,7 @@ if(ishuman(user) && prob(40) && src.density) var/mob/living/carbon/human/H = user - if((H.has_trait(TRAIT_DUMB)) && Adjacent(user)) + if((HAS_TRAIT(H, TRAIT_DUMB)) && Adjacent(user)) playsound(src.loc, 'sound/effects/bang.ogg', 25, 1) if(!istype(H.head, /obj/item/clothing/head/helmet)) H.visible_message("[user] headbutts the airlock.", \ diff --git a/code/game/machinery/exp_cloner.dm b/code/game/machinery/exp_cloner.dm index 45ac999a6a..e8364d2271 100644 --- a/code/game/machinery/exp_cloner.dm +++ b/code/game/machinery/exp_cloner.dm @@ -42,11 +42,11 @@ icon_state = "pod_1" //Get the clone body ready maim_clone(H) - H.add_trait(TRAIT_STABLEHEART, "cloning") - H.add_trait(TRAIT_EMOTEMUTE, "cloning") - H.add_trait(TRAIT_MUTE, "cloning") - H.add_trait(TRAIT_NOBREATH, "cloning") - H.add_trait(TRAIT_NOCRITDAMAGE, "cloning") + ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning") + ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning") + ADD_TRAIT(H, TRAIT_MUTE, "cloning") + ADD_TRAIT(H, TRAIT_NOBREATH, "cloning") + ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning") H.Unconscious(80) var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H) @@ -268,7 +268,7 @@ scantemp = "Unable to locate valid genetic data." playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return - if((mob_occupant.has_trait(TRAIT_NOCLONE)) && (src.scanner.scan_level < 2)) + if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2)) scantemp = "Subject no longer contains the fundamental materials required to create a living clone." playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0) return diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm index 1f40672e05..0042da1c92 100644 --- a/code/game/machinery/harvester.dm +++ b/code/game/machinery/harvester.dm @@ -73,7 +73,7 @@ say("Subject is not organic.") playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1) return - if(!allow_living && !(C.stat == DEAD || C.has_trait(TRAIT_FAKEDEATH))) //I mean, the machines scanners arent advanced enough to tell you're alive + if(!allow_living && !(C.stat == DEAD || HAS_TRAIT(C, TRAIT_FAKEDEATH))) //I mean, the machines scanners arent advanced enough to tell you're alive say("Subject is still alive.") playsound(src, 'sound/machines/buzz-sigh.ogg', 30, 1) return diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 8a0658fd0f..a3250fe1b0 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -10,7 +10,6 @@ icon = 'icons/obj/machines/limbgrower.dmi' icon_state = "limbgrower_idleoff" density = TRUE - container_type = OPENCONTAINER use_power = IDLE_POWER_USE idle_power_usage = 10 active_power_usage = 100 @@ -34,7 +33,7 @@ ) /obj/machinery/limbgrower/Initialize() - create_reagents(100) + create_reagents(100, OPENCONTAINER) stored_research = new /datum/techweb/specialized/autounlocking/limbgrower . = ..() diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 911bb76bda..b0204ddeb8 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -485,7 +485,7 @@ threatcount += 4 if(shoot_unloyal) - if (!perp.has_trait(TRAIT_MINDSHIELD)) + if (!HAS_TRAIT(perp, TRAIT_MINDSHIELD)) threatcount += 4 return threatcount diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 99baad11ae..ba08109427 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -257,8 +257,7 @@ /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/Initialize() . = ..() - create_reagents(max_volume) - reagents.set_reacting(FALSE) + create_reagents(max_volume, NO_REACT) syringes = new known_reagents = list("epinephrine"="Epinephrine","charcoal"="Charcoal") processed_reagents = new @@ -274,7 +273,7 @@ /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/critfail() ..() if(reagents) - reagents.set_reacting(TRUE) + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/can_attach(obj/mecha/medical/M) if(..()) diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 1a3886c3df..80c92c7922 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -421,14 +421,13 @@ if(!istype(T)) return var/datum/gas_mixture/GM = new - GM.add_gas(/datum/gas/plasma) if(prob(10)) - GM.gases[/datum/gas/plasma][MOLES] += 100 + GM.gases[/datum/gas/plasma] += 100 GM.temperature = 1500+T0C //should be enough to start a fire T.visible_message("[src] suddenly disgorges a cloud of heated plasma.") qdel(src) else - GM.gases[/datum/gas/plasma][MOLES] += 5 + GM.gases[/datum/gas/plasma] += 5 GM.temperature = istype(T) ? T.air.return_temperature() : T20C T.visible_message("[src] suddenly disgorges a cloud of plasma.") T.assume_air(GM) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index d5de4a4898..4700dda60d 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -237,9 +237,8 @@ cabin_air = new cabin_air.temperature = T20C cabin_air.volume = 200 - cabin_air.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen) - cabin_air.gases[/datum/gas/oxygen][MOLES] = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) - cabin_air.gases[/datum/gas/nitrogen][MOLES] = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[/datum/gas/oxygen] = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.gases[/datum/gas/nitrogen] = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) return cabin_air /obj/mecha/proc/add_radio() @@ -446,13 +445,13 @@ var/mob/living/L = user if(!Adjacent(target)) if(selected && selected.is_ranged()) - if(L.has_trait(TRAIT_PACIFISM) && selected.harmful) + if(HAS_TRAIT(L, TRAIT_PACIFISM) && selected.harmful) to_chat(user, "You don't want to harm other living beings!") return if(selected.action(target,params)) selected.start_cooldown() else if(selected && selected.is_melee()) - if(isliving(target) && selected.harmful && L.has_trait(TRAIT_PACIFISM)) + if(isliving(target) && selected.harmful && HAS_TRAIT(L, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm other living beings!") return if(selected.action(target,params)) diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 07152b0310..d5aff99f32 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -72,7 +72,7 @@ ..() if(ishuman(O)) var/mob/living/carbon/human/H = O - if(H.shoes && blood_state && bloodiness && !H.has_trait(TRAIT_LIGHT_STEP)) + if(H.shoes && blood_state && bloodiness && !HAS_TRAIT(H, TRAIT_LIGHT_STEP)) var/obj/item/clothing/shoes/S = H.shoes var/add_blood = 0 if(bloodiness >= BLOOD_GAIN_PER_STEP) diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index f1a1655fb4..35f06c2768 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -60,7 +60,7 @@ /obj/effect/decal/cleanable/blood/gibs/Crossed(mob/living/L) if(istype(L) && has_gravity(loc)) - playsound(loc, 'sound/effects/gib_step.ogg', L.has_trait(TRAIT_LIGHT_STEP) ? 20 : 50, 1) + playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1) . = ..() /obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions) diff --git a/code/game/objects/effects/decals/crayon.dm b/code/game/objects/effects/decals/crayon.dm index 34263ef9a4..0a0348ae39 100644 --- a/code/game/objects/effects/decals/crayon.dm +++ b/code/game/objects/effects/decals/crayon.dm @@ -3,6 +3,7 @@ desc = "Graffiti. Damn kids." icon = 'icons/effects/crayondecal.dmi' icon_state = "rune1" + plane = GAME_PLANE //makes the graffiti visible over a wall. gender = NEUTER mergeable_decal = FALSE var/do_icon_rotate = TRUE diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index 264715e2ac..10ee73915c 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -1,347 +1,347 @@ -// Foam -// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin. -#define ALUMINUM_FOAM 1 -#define IRON_FOAM 2 -#define RESIN_FOAM 3 - - -/obj/effect/particle_effect/foam - name = "foam" - icon_state = "foam" - opacity = 0 - anchored = TRUE - density = FALSE - layer = EDGED_TURF_LAYER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - var/amount = 3 - animate_movement = 0 - var/metal = 0 - var/lifetime = 40 - var/reagent_divisor = 7 - var/static/list/blacklisted_turfs = typecacheof(list( - /turf/open/space/transit, - /turf/open/chasm, - /turf/open/lava)) - -/obj/effect/particle_effect/foam/firefighting - name = "firefighting foam" - lifetime = 20 //doesn't last as long as normal foam - amount = 0 //no spread - var/absorbed_plasma = 0 - -/obj/effect/particle_effect/foam/firefighting/MakeSlippery() - return - -/obj/effect/particle_effect/foam/firefighting/process() - ..() - - var/turf/open/T = get_turf(src) - var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T) - if(hotspot && istype(T) && T.air) - qdel(hotspot) - var/datum/gas_mixture/G = T.air - var/plas_amt = min(30,G.gases[/datum/gas/plasma][MOLES]) //Absorb some plasma - G.gases[/datum/gas/plasma][MOLES] -= plas_amt - absorbed_plasma += plas_amt - if(G.temperature > T20C) - G.temperature = max(G.temperature/2,T20C) - G.garbage_collect() - T.air_update_turf() - -/obj/effect/particle_effect/foam/firefighting/kill_foam() - STOP_PROCESSING(SSfastprocess, src) - - if(absorbed_plasma) - var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src)) - if(!P) - P = new(loc) - P.reagents.add_reagent("stable_plasma", absorbed_plasma) - - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L) - if(!istype(L)) - return - L.adjust_fire_stacks(-2) - L.ExtinguishMob() - -/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return - -/obj/effect/particle_effect/foam/metal - name = "aluminium foam" - metal = ALUMINUM_FOAM - icon_state = "mfoam" - -/obj/effect/particle_effect/foam/metal/MakeSlippery() - return - -/obj/effect/particle_effect/foam/metal/smart - name = "smart foam" - -/obj/effect/particle_effect/foam/metal/iron - name = "iron foam" - metal = IRON_FOAM - -/obj/effect/particle_effect/foam/metal/resin - name = "resin foam" - metal = RESIN_FOAM - -/obj/effect/particle_effect/foam/long_life - lifetime = 150 - -/obj/effect/particle_effect/foam/Initialize() - . = ..() - MakeSlippery() - create_reagents(1000) //limited by the size of the reagent holder anyway. - START_PROCESSING(SSfastprocess, src) - playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) - -/obj/effect/particle_effect/foam/proc/MakeSlippery() - AddComponent(/datum/component/slippery, 100) - -/obj/effect/particle_effect/foam/Destroy() - STOP_PROCESSING(SSfastprocess, src) - return ..() - - -/obj/effect/particle_effect/foam/proc/kill_foam() - STOP_PROCESSING(SSfastprocess, src) - switch(metal) - if(ALUMINUM_FOAM) - new /obj/structure/foamedmetal(get_turf(src)) - if(IRON_FOAM) - new /obj/structure/foamedmetal/iron(get_turf(src)) - if(RESIN_FOAM) - new /obj/structure/foamedmetal/resin(get_turf(src)) - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls - STOP_PROCESSING(SSfastprocess, src) - if(metal) - var/turf/T = get_turf(src) - if(isspaceturf(T)) //Block up any exposed space - T.PlaceOnTop(/turf/open/floor/plating/foam) - for(var/direction in GLOB.cardinals) - var/turf/cardinal_turf = get_step(T, direction) - if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf! - new/obj/structure/foamedmetal(T) - break - flick("[icon_state]-disolve", src) - QDEL_IN(src, 5) - -/obj/effect/particle_effect/foam/process() - lifetime-- - if(lifetime < 1) - kill_foam() - return - - var/fraction = 1/initial(reagent_divisor) - for(var/obj/O in range(0,src)) - if(O.type == src.type) - continue - if(isturf(O.loc)) - var/turf/T = O.loc - if(T.intact && O.level == 1) //hidden under the floor - continue - if(lifetime % reagent_divisor) - reagents.reaction(O, VAPOR, fraction) - var/hit = 0 - for(var/mob/living/L in range(0,src)) - hit += foam_mob(L) - if(hit) - lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate. - var/T = get_turf(src) - if(lifetime % reagent_divisor) - reagents.reaction(T, VAPOR, fraction) - - if(--amount < 0) - return - spread_foam() - -/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L) - if(lifetime<1) - return 0 - if(!istype(L)) - return 0 - var/fraction = 1/initial(reagent_divisor) - if(lifetime % reagent_divisor) - reagents.reaction(L, VAPOR, fraction) - lifetime-- - return 1 - -/obj/effect/particle_effect/foam/proc/spread_foam() - var/turf/t_loc = get_turf(src) - for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) - var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam! - if(foundfoam) - continue - - if(is_type_in_typecache(T, blacklisted_turfs)) - continue - - for(var/mob/living/L in T) - foam_mob(L) - var/obj/effect/particle_effect/foam/F = new src.type(T) - F.amount = amount - reagents.copy_to(F, (reagents.total_volume)) - F.add_atom_colour(color, FIXED_COLOUR_PRIORITY) - F.metal = metal - - -/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated - kill_foam() - - -/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) - return - - -/////////////////////////////////////////////// -//FOAM EFFECT DATUM -/datum/effect_system/foam_spread - var/amount = 10 // the size of the foam spread. - var/obj/chemholder - effect_type = /obj/effect/particle_effect/foam - var/metal = 0 - - -/datum/effect_system/foam_spread/metal - effect_type = /obj/effect/particle_effect/foam/metal - - -/datum/effect_system/foam_spread/metal/smart - effect_type = /obj/effect/particle_effect/foam/smart - - -/datum/effect_system/foam_spread/long - effect_type = /obj/effect/particle_effect/foam/long_life - -/datum/effect_system/foam_spread/New() - ..() - chemholder = new /obj() - var/datum/reagents/R = new/datum/reagents(1000) - chemholder.reagents = R - R.my_atom = chemholder - -/datum/effect_system/foam_spread/Destroy() - qdel(chemholder) - chemholder = null - return ..() - -/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - - amount = round(sqrt(amt / 2), 1) - carry.copy_to(chemholder, carry.total_volume) - -/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype) - ..() - metal = metaltype - -/datum/effect_system/foam_spread/start() - var/obj/effect/particle_effect/foam/F = new effect_type(location) - var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) - chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount) - F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY) - F.amount = amount - F.metal = metal - - -////////////////////////////////////////////////////////// -// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break -/obj/structure/foamedmetal - icon = 'icons/effects/effects.dmi' - icon_state = "metalfoam" - density = TRUE - opacity = 1 // changed in New() - anchored = TRUE - layer = EDGED_TURF_LAYER - resistance_flags = FIRE_PROOF | ACID_PROOF - name = "foamed metal" - desc = "A lightweight foamed metal wall." - gender = PLURAL - max_integrity = 20 - CanAtmosPass = ATMOS_PASS_DENSITY - -/obj/structure/foamedmetal/Initialize() - . = ..() - air_update_turf(1) - -/obj/structure/foamedmetal/Move() - var/turf/T = loc - . = ..() - move_update_air(T) - -/obj/structure/foamedmetal/attack_paw(mob/user) - return attack_hand(user) - -/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) - -/obj/structure/foamedmetal/attack_hand(mob/user) - . = ..() - if(.) - return - user.changeNext_move(CLICK_CD_MELEE) - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - to_chat(user, "You hit [src] but bounce off it!") - playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) - -/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target) - return !density - -/obj/structure/foamedmetal/iron - max_integrity = 50 - icon_state = "ironfoam" - -//Atmos Backpack Resin, transparent, prevents atmos and filters the air -/obj/structure/foamedmetal/resin - name = "\improper ATMOS Resin" - desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature." - opacity = FALSE - icon_state = "atmos_resin" - alpha = 120 - max_integrity = 10 - -/obj/structure/foamedmetal/resin/Initialize() - . = ..() - if(isopenturf(loc)) - var/turf/open/O = loc - O.ClearWet() - if(O.air) - var/datum/gas_mixture/G = O.air - G.temperature = 293.15 - for(var/obj/effect/hotspot/H in O) - qdel(H) - var/list/G_gases = G.gases - for(var/I in G_gases) - if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen) - continue - G_gases[I][MOLES] = 0 - G.garbage_collect() - O.air_update_turf() - for(var/obj/machinery/atmospherics/components/unary/U in O) - if(!U.welded) - U.welded = TRUE - U.update_icon() - U.visible_message("[U] sealed shut!") - for(var/mob/living/L in O) - L.ExtinguishMob() - for(var/obj/item/Item in O) - Item.extinguish() - -/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && (mover.pass_flags & PASSGLASS)) - return TRUE - . = ..() - -#undef ALUMINUM_FOAM -#undef IRON_FOAM -#undef RESIN_FOAM +// Foam +// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin. +#define ALUMINUM_FOAM 1 +#define IRON_FOAM 2 +#define RESIN_FOAM 3 + + +/obj/effect/particle_effect/foam + name = "foam" + icon_state = "foam" + opacity = 0 + anchored = TRUE + density = FALSE + layer = EDGED_TURF_LAYER + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + var/amount = 3 + animate_movement = 0 + var/metal = 0 + var/lifetime = 40 + var/reagent_divisor = 7 + var/static/list/blacklisted_turfs = typecacheof(list( + /turf/open/space/transit, + /turf/open/chasm, + /turf/open/lava)) + +/obj/effect/particle_effect/foam/firefighting + name = "firefighting foam" + lifetime = 20 //doesn't last as long as normal foam + amount = 0 //no spread + var/absorbed_plasma = 0 + +/obj/effect/particle_effect/foam/firefighting/MakeSlippery() + return + +/obj/effect/particle_effect/foam/firefighting/process() + ..() + + var/turf/open/T = get_turf(src) + var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T) + if(hotspot && istype(T) && T.air) + qdel(hotspot) + var/datum/gas_mixture/G = T.air + var/plas_amt = min(30,G.gases[/datum/gas/plasma]) //Absorb some plasma + G.gases[/datum/gas/plasma] -= plas_amt + absorbed_plasma += plas_amt + if(G.temperature > T20C) + G.temperature = max(G.temperature/2,T20C) + GAS_GARBAGE_COLLECT(G.gases) + T.air_update_turf() + +/obj/effect/particle_effect/foam/firefighting/kill_foam() + STOP_PROCESSING(SSfastprocess, src) + + if(absorbed_plasma) + var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src)) + if(!P) + P = new(loc) + P.reagents.add_reagent("stable_plasma", absorbed_plasma) + + flick("[icon_state]-disolve", src) + QDEL_IN(src, 5) + +/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L) + if(!istype(L)) + return + L.adjust_fire_stacks(-2) + L.ExtinguishMob() + +/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return + +/obj/effect/particle_effect/foam/metal + name = "aluminium foam" + metal = ALUMINUM_FOAM + icon_state = "mfoam" + +/obj/effect/particle_effect/foam/metal/MakeSlippery() + return + +/obj/effect/particle_effect/foam/metal/smart + name = "smart foam" + +/obj/effect/particle_effect/foam/metal/iron + name = "iron foam" + metal = IRON_FOAM + +/obj/effect/particle_effect/foam/metal/resin + name = "resin foam" + metal = RESIN_FOAM + +/obj/effect/particle_effect/foam/long_life + lifetime = 150 + +/obj/effect/particle_effect/foam/Initialize() + . = ..() + MakeSlippery() + create_reagents(1000) //limited by the size of the reagent holder anyway. + START_PROCESSING(SSfastprocess, src) + playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) + +/obj/effect/particle_effect/foam/proc/MakeSlippery() + AddComponent(/datum/component/slippery, 100) + +/obj/effect/particle_effect/foam/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + + +/obj/effect/particle_effect/foam/proc/kill_foam() + STOP_PROCESSING(SSfastprocess, src) + switch(metal) + if(ALUMINUM_FOAM) + new /obj/structure/foamedmetal(get_turf(src)) + if(IRON_FOAM) + new /obj/structure/foamedmetal/iron(get_turf(src)) + if(RESIN_FOAM) + new /obj/structure/foamedmetal/resin(get_turf(src)) + flick("[icon_state]-disolve", src) + QDEL_IN(src, 5) + +/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls + STOP_PROCESSING(SSfastprocess, src) + if(metal) + var/turf/T = get_turf(src) + if(isspaceturf(T)) //Block up any exposed space + T.PlaceOnTop(/turf/open/floor/plating/foam) + for(var/direction in GLOB.cardinals) + var/turf/cardinal_turf = get_step(T, direction) + if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf! + new/obj/structure/foamedmetal(T) + break + flick("[icon_state]-disolve", src) + QDEL_IN(src, 5) + +/obj/effect/particle_effect/foam/process() + lifetime-- + if(lifetime < 1) + kill_foam() + return + + var/fraction = 1/initial(reagent_divisor) + for(var/obj/O in range(0,src)) + if(O.type == src.type) + continue + if(isturf(O.loc)) + var/turf/T = O.loc + if(T.intact && O.level == 1) //hidden under the floor + continue + if(lifetime % reagent_divisor) + reagents.reaction(O, VAPOR, fraction) + var/hit = 0 + for(var/mob/living/L in range(0,src)) + hit += foam_mob(L) + if(hit) + lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate. + var/T = get_turf(src) + if(lifetime % reagent_divisor) + reagents.reaction(T, VAPOR, fraction) + + if(--amount < 0) + return + spread_foam() + +/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L) + if(lifetime<1) + return 0 + if(!istype(L)) + return 0 + var/fraction = 1/initial(reagent_divisor) + if(lifetime % reagent_divisor) + reagents.reaction(L, VAPOR, fraction) + lifetime-- + return 1 + +/obj/effect/particle_effect/foam/proc/spread_foam() + var/turf/t_loc = get_turf(src) + for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) + var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam! + if(foundfoam) + continue + + if(is_type_in_typecache(T, blacklisted_turfs)) + continue + + for(var/mob/living/L in T) + foam_mob(L) + var/obj/effect/particle_effect/foam/F = new src.type(T) + F.amount = amount + reagents.copy_to(F, (reagents.total_volume)) + F.add_atom_colour(color, FIXED_COLOUR_PRIORITY) + F.metal = metal + + +/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated + kill_foam() + + +/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + return + + +/////////////////////////////////////////////// +//FOAM EFFECT DATUM +/datum/effect_system/foam_spread + var/amount = 10 // the size of the foam spread. + var/obj/chemholder + effect_type = /obj/effect/particle_effect/foam + var/metal = 0 + + +/datum/effect_system/foam_spread/metal + effect_type = /obj/effect/particle_effect/foam/metal + + +/datum/effect_system/foam_spread/metal/smart + effect_type = /obj/effect/particle_effect/foam/smart + + +/datum/effect_system/foam_spread/long + effect_type = /obj/effect/particle_effect/foam/long_life + +/datum/effect_system/foam_spread/New() + ..() + chemholder = new /obj() + var/datum/reagents/R = new/datum/reagents(1000) + chemholder.reagents = R + R.my_atom = chemholder + +/datum/effect_system/foam_spread/Destroy() + qdel(chemholder) + chemholder = null + return ..() + +/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null) + if(isturf(loca)) + location = loca + else + location = get_turf(loca) + + amount = round(sqrt(amt / 2), 1) + carry.copy_to(chemholder, carry.total_volume) + +/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype) + ..() + metal = metaltype + +/datum/effect_system/foam_spread/start() + var/obj/effect/particle_effect/foam/F = new effect_type(location) + var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) + chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount) + F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY) + F.amount = amount + F.metal = metal + + +////////////////////////////////////////////////////////// +// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break +/obj/structure/foamedmetal + icon = 'icons/effects/effects.dmi' + icon_state = "metalfoam" + density = TRUE + opacity = 1 // changed in New() + anchored = TRUE + layer = EDGED_TURF_LAYER + resistance_flags = FIRE_PROOF | ACID_PROOF + name = "foamed metal" + desc = "A lightweight foamed metal wall." + gender = PLURAL + max_integrity = 20 + CanAtmosPass = ATMOS_PASS_DENSITY + +/obj/structure/foamedmetal/Initialize() + . = ..() + air_update_turf(1) + +/obj/structure/foamedmetal/Move() + var/turf/T = loc + . = ..() + move_update_air(T) + +/obj/structure/foamedmetal/attack_paw(mob/user) + return attack_hand(user) + +/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) + +/obj/structure/foamedmetal/attack_hand(mob/user) + . = ..() + if(.) + return + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) + to_chat(user, "You hit [src] but bounce off it!") + playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) + +/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target) + return !density + +/obj/structure/foamedmetal/iron + max_integrity = 50 + icon_state = "ironfoam" + +//Atmos Backpack Resin, transparent, prevents atmos and filters the air +/obj/structure/foamedmetal/resin + name = "\improper ATMOS Resin" + desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature." + opacity = FALSE + icon_state = "atmos_resin" + alpha = 120 + max_integrity = 10 + +/obj/structure/foamedmetal/resin/Initialize() + . = ..() + if(isopenturf(loc)) + var/turf/open/O = loc + O.ClearWet() + if(O.air) + var/datum/gas_mixture/G = O.air + G.temperature = 293.15 + for(var/obj/effect/hotspot/H in O) + qdel(H) + var/list/G_gases = G.gases + for(var/I in G_gases) + if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen) + continue + G_gases[I] = 0 + GAS_GARBAGE_COLLECT(G.gases) + O.air_update_turf() + for(var/obj/machinery/atmospherics/components/unary/U in O) + if(!U.welded) + U.welded = TRUE + U.update_icon() + U.visible_message("[U] sealed shut!") + for(var/mob/living/L in O) + L.ExtinguishMob() + for(var/obj/item/Item in O) + Item.extinguish() + +/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target) + if(istype(mover) && (mover.pass_flags & PASSGLASS)) + return TRUE + . = ..() + +#undef ALUMINUM_FOAM +#undef IRON_FOAM +#undef RESIN_FOAM diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index e8e833890b..79deac475b 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -1,329 +1,328 @@ -///////////////////////////////////////////// -//// SMOKE SYSTEMS -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke - name = "smoke" - icon = 'icons/effects/96x96.dmi' - icon_state = "smoke" - pixel_x = -32 - pixel_y = -32 - opacity = 0 - layer = FLY_LAYER - anchored = TRUE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - animate_movement = 0 - var/amount = 4 - var/lifetime = 5 - var/opaque = 1 //whether the smoke can block the view when in enough amount - - -/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16) - if(alpha == 0) //Handle already transparent case - return - if(frames == 0) - frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". - var/step = alpha / frames - for(var/i = 0, i < frames, i++) - alpha -= step - if(alpha < 160) - set_opacity(0) //if we were blocking view, we aren't now because we're fading out - stoplag() - -/obj/effect/particle_effect/smoke/Initialize() - . = ..() - create_reagents(500) - START_PROCESSING(SSobj, src) - - -/obj/effect/particle_effect/smoke/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/effect/particle_effect/smoke/proc/kill_smoke() - STOP_PROCESSING(SSobj, src) - INVOKE_ASYNC(src, .proc/fade_out) - QDEL_IN(src, 10) - -/obj/effect/particle_effect/smoke/process() - lifetime-- - if(lifetime < 1) - kill_smoke() - return 0 - for(var/mob/living/L in range(0,src)) - smoke_mob(L) - return 1 - -/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C) - if(!istype(C)) - return 0 - if(lifetime<1) - return 0 - if(C.internal != null || C.has_smoke_protection()) - return 0 - if(C.smoke_delay) - return 0 - C.smoke_delay++ - addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10) - return 1 - -/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C) - if(C) - C.smoke_delay = 0 - -/obj/effect/particle_effect/smoke/proc/spread_smoke() - var/turf/t_loc = get_turf(src) - if(!t_loc) - return - var/list/newsmokes = list() - for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) - var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke! - if(foundsmoke) - continue - for(var/mob/living/L in T) - smoke_mob(L) - var/obj/effect/particle_effect/smoke/S = new type(T) - reagents.copy_to(S, reagents.total_volume) - S.setDir(pick(GLOB.cardinals)) - S.amount = amount-1 - S.add_atom_colour(color, FIXED_COLOUR_PRIORITY) - S.lifetime = lifetime - if(S.amount>0) - if(opaque) - S.set_opacity(TRUE) - newsmokes.Add(S) - - if(newsmokes.len) - spawn(1) //the smoke spreads rapidly but not instantly - for(var/obj/effect/particle_effect/smoke/SM in newsmokes) - SM.spread_smoke() - - -/datum/effect_system/smoke_spread - var/amount = 10 - effect_type = /obj/effect/particle_effect/smoke - -/datum/effect_system/smoke_spread/set_up(radius = 5, loca) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - amount = radius - -/datum/effect_system/smoke_spread/start() - if(holder) - location = get_turf(holder) - var/obj/effect/particle_effect/smoke/S = new effect_type(location) - S.amount = amount - if(S.amount) - S.spread_smoke() - - -///////////////////////////////////////////// -// Bad smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/bad - lifetime = 8 - -/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M) - if(..()) - M.drop_all_held_items() - M.adjustOxyLoss(1) - M.emote("cough") - return 1 - -/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target) - if(istype(mover, /obj/item/projectile/beam)) - var/obj/item/projectile/beam/B = mover - B.damage = (B.damage/2) - return 1 - - - -/datum/effect_system/smoke_spread/bad - effect_type = /obj/effect/particle_effect/smoke/bad - -///////////////////////////////////////////// -// Nanofrost smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/freezing - name = "nanofrost smoke" - color = "#B2FFFF" - opaque = 0 - -/datum/effect_system/smoke_spread/freezing - effect_type = /obj/effect/particle_effect/smoke/freezing - var/blast = 0 - var/temperature = 2 - var/weldvents = TRUE - var/distcheck = TRUE - -/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A) - if(isopenturf(A)) - var/turf/open/T = A - if(T.air) - var/datum/gas_mixture/G = T.air - if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air - G.temperature = temperature - T.air_update_turf() - for(var/obj/effect/hotspot/H in T) - qdel(H) - var/list/G_gases = G.gases - if(G_gases[/datum/gas/plasma]) - G.assert_gas(/datum/gas/nitrogen) - G_gases[/datum/gas/nitrogen][MOLES] += (G_gases[/datum/gas/plasma][MOLES]) - G_gases[/datum/gas/plasma][MOLES] = 0 - G.garbage_collect() - if (weldvents) - for(var/obj/machinery/atmospherics/components/unary/U in T) - if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber. - U.welded = TRUE - U.update_icon() - U.visible_message("[U] was frozen shut!") - for(var/mob/living/L in T) - L.ExtinguishMob() - for(var/obj/item/Item in T) - Item.extinguish() - -/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0) - ..() - blast = blast_radius - -/datum/effect_system/smoke_spread/freezing/start() - if(blast) - for(var/turf/T in RANGE_TURFS(blast, location)) - Chilled(T) - ..() - -/datum/effect_system/smoke_spread/freezing/decon - temperature = 293.15 - distcheck = FALSE - weldvents = FALSE - - -///////////////////////////////////////////// -// Sleep smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/sleeping - color = "#9C3636" - lifetime = 10 - -/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M) - if(..()) - M.Sleeping(200) - M.emote("cough") - return 1 - -/datum/effect_system/smoke_spread/sleeping - effect_type = /obj/effect/particle_effect/smoke/sleeping - -///////////////////////////////////////////// -// Chem smoke -///////////////////////////////////////////// - -/obj/effect/particle_effect/smoke/chem - lifetime = 10 - - -/obj/effect/particle_effect/smoke/chem/process() - if(..()) - var/turf/T = get_turf(src) - var/fraction = 1/initial(lifetime) - for(var/atom/movable/AM in T) - if(AM.type == src.type) - continue - if(T.intact && AM.level == 1) //hidden under the floor - continue - reagents.reaction(AM, TOUCH, fraction) - - reagents.reaction(T, TOUCH, fraction) - return 1 - -/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M) - if(lifetime<1) - return 0 - if(!istype(M)) - return 0 - var/mob/living/carbon/C = M - if(C.internal != null || C.has_smoke_protection()) - return 0 - var/fraction = 1/initial(lifetime) - reagents.copy_to(C, fraction*reagents.total_volume) - reagents.reaction(M, INGEST, fraction) - return 1 - - - -/datum/effect_system/smoke_spread/chem - var/obj/chemholder - effect_type = /obj/effect/particle_effect/smoke/chem - -/datum/effect_system/smoke_spread/chem/New() - ..() - chemholder = new /obj() - var/datum/reagents/R = new/datum/reagents(500) - chemholder.reagents = R - R.my_atom = chemholder - -/datum/effect_system/smoke_spread/chem/Destroy() - qdel(chemholder) - chemholder = null - return ..() - -/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - amount = radius - carry.copy_to(chemholder, carry.total_volume) - - if(!silent) - var/contained = "" - for(var/reagent in carry.reagent_list) - contained += " [reagent] " - if(contained) - contained = "\[[contained]\]" - - var/where = "[AREACOORD(location)]" - if(carry.my_atom.fingerprintslast) - var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) - var/more = "" - if(M) - more = "[ADMIN_LOOKUPFLW(M)] " - message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].") - log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].") - else - message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.") - log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") - - -/datum/effect_system/smoke_spread/chem/start() - var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) - if(holder) - location = get_turf(holder) - var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location) - - if(chemholder.reagents.total_volume > 1) // can't split 1 very well - chemholder.reagents.copy_to(S, chemholder.reagents.total_volume) - - if(mixcolor) - S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with - S.amount = amount - if(S.amount) - S.spread_smoke() //calling process right now so the smoke immediately attacks mobs. - - -///////////////////////////////////////////// -// Transparent smoke -///////////////////////////////////////////// - -//Same as the base type, but the smoke produced is not opaque -/datum/effect_system/smoke_spread/transparent - effect_type = /obj/effect/particle_effect/smoke/transparent - -/obj/effect/particle_effect/smoke/transparent - opaque = FALSE +///////////////////////////////////////////// +//// SMOKE SYSTEMS +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke + name = "smoke" + icon = 'icons/effects/96x96.dmi' + icon_state = "smoke" + pixel_x = -32 + pixel_y = -32 + opacity = 0 + layer = FLY_LAYER + anchored = TRUE + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + animate_movement = 0 + var/amount = 4 + var/lifetime = 5 + var/opaque = 1 //whether the smoke can block the view when in enough amount + + +/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16) + if(alpha == 0) //Handle already transparent case + return + if(frames == 0) + frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame". + var/step = alpha / frames + for(var/i = 0, i < frames, i++) + alpha -= step + if(alpha < 160) + set_opacity(0) //if we were blocking view, we aren't now because we're fading out + stoplag() + +/obj/effect/particle_effect/smoke/Initialize() + . = ..() + create_reagents(500) + START_PROCESSING(SSobj, src) + + +/obj/effect/particle_effect/smoke/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/effect/particle_effect/smoke/proc/kill_smoke() + STOP_PROCESSING(SSobj, src) + INVOKE_ASYNC(src, .proc/fade_out) + QDEL_IN(src, 10) + +/obj/effect/particle_effect/smoke/process() + lifetime-- + if(lifetime < 1) + kill_smoke() + return 0 + for(var/mob/living/L in range(0,src)) + smoke_mob(L) + return 1 + +/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C) + if(!istype(C)) + return 0 + if(lifetime<1) + return 0 + if(C.internal != null || C.has_smoke_protection()) + return 0 + if(C.smoke_delay) + return 0 + C.smoke_delay++ + addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10) + return 1 + +/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C) + if(C) + C.smoke_delay = 0 + +/obj/effect/particle_effect/smoke/proc/spread_smoke() + var/turf/t_loc = get_turf(src) + if(!t_loc) + return + var/list/newsmokes = list() + for(var/turf/T in t_loc.GetAtmosAdjacentTurfs()) + var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke! + if(foundsmoke) + continue + for(var/mob/living/L in T) + smoke_mob(L) + var/obj/effect/particle_effect/smoke/S = new type(T) + reagents.copy_to(S, reagents.total_volume) + S.setDir(pick(GLOB.cardinals)) + S.amount = amount-1 + S.add_atom_colour(color, FIXED_COLOUR_PRIORITY) + S.lifetime = lifetime + if(S.amount>0) + if(opaque) + S.set_opacity(TRUE) + newsmokes.Add(S) + + if(newsmokes.len) + spawn(1) //the smoke spreads rapidly but not instantly + for(var/obj/effect/particle_effect/smoke/SM in newsmokes) + SM.spread_smoke() + + +/datum/effect_system/smoke_spread + var/amount = 10 + effect_type = /obj/effect/particle_effect/smoke + +/datum/effect_system/smoke_spread/set_up(radius = 5, loca) + if(isturf(loca)) + location = loca + else + location = get_turf(loca) + amount = radius + +/datum/effect_system/smoke_spread/start() + if(holder) + location = get_turf(holder) + var/obj/effect/particle_effect/smoke/S = new effect_type(location) + S.amount = amount + if(S.amount) + S.spread_smoke() + + +///////////////////////////////////////////// +// Bad smoke +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke/bad + lifetime = 8 + +/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M) + if(..()) + M.drop_all_held_items() + M.adjustOxyLoss(1) + M.emote("cough") + return 1 + +/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target) + if(istype(mover, /obj/item/projectile/beam)) + var/obj/item/projectile/beam/B = mover + B.damage = (B.damage/2) + return 1 + + + +/datum/effect_system/smoke_spread/bad + effect_type = /obj/effect/particle_effect/smoke/bad + +///////////////////////////////////////////// +// Nanofrost smoke +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke/freezing + name = "nanofrost smoke" + color = "#B2FFFF" + opaque = 0 + +/datum/effect_system/smoke_spread/freezing + effect_type = /obj/effect/particle_effect/smoke/freezing + var/blast = 0 + var/temperature = 2 + var/weldvents = TRUE + var/distcheck = TRUE + +/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A) + if(isopenturf(A)) + var/turf/open/T = A + if(T.air) + var/datum/gas_mixture/G = T.air + if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air + G.temperature = temperature + T.air_update_turf() + for(var/obj/effect/hotspot/H in T) + qdel(H) + var/list/G_gases = G.gases + if(G_gases[/datum/gas/plasma]) + G_gases[/datum/gas/nitrogen] += (G_gases[/datum/gas/plasma]) + G_gases[/datum/gas/plasma] = 0 + GAS_GARBAGE_COLLECT(G.gases) + if (weldvents) + for(var/obj/machinery/atmospherics/components/unary/U in T) + if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber. + U.welded = TRUE + U.update_icon() + U.visible_message("[U] was frozen shut!") + for(var/mob/living/L in T) + L.ExtinguishMob() + for(var/obj/item/Item in T) + Item.extinguish() + +/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0) + ..() + blast = blast_radius + +/datum/effect_system/smoke_spread/freezing/start() + if(blast) + for(var/turf/T in RANGE_TURFS(blast, location)) + Chilled(T) + ..() + +/datum/effect_system/smoke_spread/freezing/decon + temperature = 293.15 + distcheck = FALSE + weldvents = FALSE + + +///////////////////////////////////////////// +// Sleep smoke +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke/sleeping + color = "#9C3636" + lifetime = 10 + +/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M) + if(..()) + M.Sleeping(200) + M.emote("cough") + return 1 + +/datum/effect_system/smoke_spread/sleeping + effect_type = /obj/effect/particle_effect/smoke/sleeping + +///////////////////////////////////////////// +// Chem smoke +///////////////////////////////////////////// + +/obj/effect/particle_effect/smoke/chem + lifetime = 10 + + +/obj/effect/particle_effect/smoke/chem/process() + if(..()) + var/turf/T = get_turf(src) + var/fraction = 1/initial(lifetime) + for(var/atom/movable/AM in T) + if(AM.type == src.type) + continue + if(T.intact && AM.level == 1) //hidden under the floor + continue + reagents.reaction(AM, TOUCH, fraction) + + reagents.reaction(T, TOUCH, fraction) + return 1 + +/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M) + if(lifetime<1) + return 0 + if(!istype(M)) + return 0 + var/mob/living/carbon/C = M + if(C.internal != null || C.has_smoke_protection()) + return 0 + var/fraction = 1/initial(lifetime) + reagents.copy_to(C, fraction*reagents.total_volume) + reagents.reaction(M, INGEST, fraction) + return 1 + + + +/datum/effect_system/smoke_spread/chem + var/obj/chemholder + effect_type = /obj/effect/particle_effect/smoke/chem + +/datum/effect_system/smoke_spread/chem/New() + ..() + chemholder = new /obj() + var/datum/reagents/R = new/datum/reagents(500) + chemholder.reagents = R + R.my_atom = chemholder + +/datum/effect_system/smoke_spread/chem/Destroy() + qdel(chemholder) + chemholder = null + return ..() + +/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE) + if(isturf(loca)) + location = loca + else + location = get_turf(loca) + amount = radius + carry.copy_to(chemholder, carry.total_volume) + + if(!silent) + var/contained = "" + for(var/reagent in carry.reagent_list) + contained += " [reagent] " + if(contained) + contained = "\[[contained]\]" + + var/where = "[AREACOORD(location)]" + if(carry.my_atom.fingerprintslast) + var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast) + var/more = "" + if(M) + more = "[ADMIN_LOOKUPFLW(M)] " + message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].") + log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].") + else + message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.") + log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") + + +/datum/effect_system/smoke_spread/chem/start() + var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list) + if(holder) + location = get_turf(holder) + var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location) + + if(chemholder.reagents.total_volume > 1) // can't split 1 very well + chemholder.reagents.copy_to(S, chemholder.reagents.total_volume) + + if(mixcolor) + S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with + S.amount = amount + if(S.amount) + S.spread_smoke() //calling process right now so the smoke immediately attacks mobs. + + +///////////////////////////////////////////// +// Transparent smoke +///////////////////////////////////////////// + +//Same as the base type, but the smoke produced is not opaque +/datum/effect_system/smoke_spread/transparent + effect_type = /obj/effect/particle_effect/smoke/transparent + +/obj/effect/particle_effect/smoke/transparent + opaque = FALSE diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 12a72685bb..7e8094c9e7 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -170,7 +170,7 @@ if(!victim.client || !istype(victim)) return to_chat(victim, "You feel fast!") - victim.add_trait(TRAIT_GOTTAGOREALLYFAST, "yellow_orb") + ADD_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb") sleep(duration) - victim.remove_trait(TRAIT_GOTTAGOREALLYFAST, "yellow_orb") + REMOVE_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb") to_chat(victim, "You slow down.") diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index b1bb3e6b4d..65395d534a 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -1,6 +1,6 @@ #define CELSIUS_TO_KELVIN(T_K) ((T_K) + T0C) -#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT]) / (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT] + (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT] / CELSIUS_TO_KELVIN(TEMP_O))) +#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma]) / (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma] + (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen] / CELSIUS_TO_KELVIN(TEMP_O))) #define OPTIMAL_TEMP_K_PLA_BURN_RATIO(PRESSURE_P,PRESSURE_O,TEMP_O) (CELSIUS_TO_KELVIN(TEMP_O) * PLASMA_OXYGEN_FULLBURN * (PRESSURE_P) / (PRESSURE_O)) /obj/effect/spawner/newbomb @@ -19,12 +19,10 @@ var/obj/item/tank/internals/plasma/PT = new(V) var/obj/item/tank/internals/oxygen/OT = new(V) - PT.air_contents.assert_gas(/datum/gas/plasma) - PT.air_contents.gases[/datum/gas/plasma][MOLES] = pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p)) + PT.air_contents.gases[/datum/gas/plasma] = pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p)) PT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_p) - OT.air_contents.assert_gas(/datum/gas/oxygen) - OT.air_contents.gases[/datum/gas/oxygen][MOLES] = pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o)) + OT.air_contents.gases[/datum/gas/oxygen] = pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o)) OT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_o) V.tank_one = PT diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 9314faab27..3fbbab087f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -109,6 +109,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder! + /obj/item/Initialize() materials = typelist("materials", materials) @@ -256,7 +257,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) can_handle_hot = TRUE else if(C.gloves && (C.gloves.max_heat_protection_temperature > 360)) can_handle_hot = TRUE - else if(C.has_trait(TRAIT_RESISTHEAT) || C.has_trait(TRAIT_RESISTHEATHANDS)) + else if(HAS_TRAIT(C, TRAIT_RESISTHEAT) || HAS_TRAIT(C, TRAIT_RESISTHEATHANDS)) can_handle_hot = TRUE if(can_handle_hot) @@ -449,10 +450,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) return 0 /obj/item/proc/eyestab(mob/living/carbon/M, mob/living/carbon/user) - if(user.has_trait(TRAIT_PACIFISM)) + if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [M]!") return - if(user.has_trait(TRAIT_CLUMSY) && prob(50)) + if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) M = user var/is_human_victim = 0 var/obj/item/bodypart/affecting = M.get_bodypart(BODY_ZONE_HEAD) @@ -523,7 +524,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) M.adjust_blurriness(15) if(M.stat != DEAD) to_chat(M, "Your eyes start to bleed profusely!") - if(!(M.has_trait(TRAIT_BLIND) || M.has_trait(TRAIT_NEARSIGHT))) + if(!(HAS_TRAIT(M, TRAIT_BLIND) || HAS_TRAIT(M, TRAIT_NEARSIGHT))) to_chat(M, "You become nearsighted!") M.become_nearsighted(EYE_DAMAGE) if(prob(50)) diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index 7881c277ff..38d64be99c 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -161,13 +161,18 @@ RLD user.visible_message("[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..") return (BRUTELOSS) -/obj/item/construction/rcd/verb/toggle_window_type() - set name = "Toggle Window Type" +/obj/item/construction/rcd/verb/toggle_window_type_verb() + set name = "RCD : Toggle Window Type" set category = "Object" - set src in usr // What does this do? + set src in view(1) + if(!usr.canUseTopic(src, BE_CLOSE)) + return + + toggle_window_type(usr) + +/obj/item/construction/rcd/proc/toggle_window_type(mob/user) var/window_type_name - if (window_type == /obj/structure/window/fulltile) window_type = /obj/structure/window/reinforced/fulltile window_type_name = "reinforced glass" @@ -175,17 +180,14 @@ RLD window_type = /obj/structure/window/fulltile window_type_name = "glass" - to_chat(usr, "You change \the [src]'s window mode to [window_type_name].") + to_chat(user, "You change \the [src]'s window mode to [window_type_name].") -/obj/item/construction/rcd/verb/change_airlock_access() - set name = "Change Airlock Access" - set category = "Object" - set src in usr +/obj/item/construction/rcd/verb/change_airlock_access(mob/user) - if (!ishuman(usr) && !usr.has_unlimited_silicon_privilege) - return ..(usr) + if (!ishuman(user) && !user.has_unlimited_silicon_privilege) + return - var/t1 = text("") + var/t1 = "" if(use_one_access) @@ -216,24 +218,23 @@ RLD t1 += "
\n" - var/datum/browser/popup = new(usr, "airlock_electronics", "Access Control", 900, 500) + var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500) popup.set_content(t1) - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() - onclose(usr, "airlock") + onclose(user, "rcd_access") /obj/item/construction/rcd/Topic(href, href_list) ..() if (usr.stat || usr.restrained()) return if (href_list["close"]) - usr << browse(null, "window=airlock") + usr << browse(null, "window=rcd_access") return if (href_list["access"]) toggle_access(href_list["access"]) - - change_airlock_access() + change_airlock_access(usr) /obj/item/construction/rcd/proc/toggle_access(acc) if (acc == "all") @@ -253,16 +254,77 @@ RLD if (!conf_access.len) conf_access = null -/obj/item/construction/rcd/verb/change_airlock_setting() - set name = "Change Airlock Setting" - set category = "Object" - set src in usr +/obj/item/construction/rcd/proc/get_airlock_image(airlock_type) + var/obj/machinery/door/airlock/proto = airlock_type + var/ic = initial(proto.icon) + var/mutable_appearance/MA = mutable_appearance(ic, "closed") + if(!initial(proto.glass)) + MA.overlays += "fill_closed" + //Not scaling these down to button size because they look horrible then, instead just bumping up radius. + return MA - var/airlockcat = input(usr, "Select whether the airlock is solid or glass.") in list("Solid", "Glass") +/obj/item/construction/rcd/proc/check_menu(mob/living/user) + if(!istype(user)) + return FALSE + if(user.incapacitated() || !user.Adjacent(src)) + return FALSE + return TRUE + +/obj/item/construction/rcd/proc/change_airlock_setting(mob/user) + if(!user) + return + + var/list/solid_or_glass_choices = list( + "Solid" = get_airlock_image(/obj/machinery/door/airlock), + "Glass" = get_airlock_image(/obj/machinery/door/airlock/glass) + ) + + var/list/solid_choices = list( + "Standard" = get_airlock_image(/obj/machinery/door/airlock), + "Public" = get_airlock_image(/obj/machinery/door/airlock/public), + "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering), + "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos), + "Security" = get_airlock_image(/obj/machinery/door/airlock/security), + "Command" = get_airlock_image(/obj/machinery/door/airlock/command), + "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical), + "Research" = get_airlock_image(/obj/machinery/door/airlock/research), + "Freezer" = get_airlock_image(/obj/machinery/door/airlock/freezer), + "Science" = get_airlock_image(/obj/machinery/door/airlock/science), + "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology), + "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining), + "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance), + "External" = get_airlock_image(/obj/machinery/door/airlock/external), + "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external), + "Airtight Hatch" = get_airlock_image(/obj/machinery/door/airlock/hatch), + "Maintenance Hatch" = get_airlock_image(/obj/machinery/door/airlock/maintenance_hatch) + ) + + var/list/glass_choices = list( + "Standard" = get_airlock_image(/obj/machinery/door/airlock/glass), + "Public" = get_airlock_image(/obj/machinery/door/airlock/public/glass), + "Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering/glass), + "Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos/glass), + "Security" = get_airlock_image(/obj/machinery/door/airlock/security/glass), + "Command" = get_airlock_image(/obj/machinery/door/airlock/command/glass), + "Medical" = get_airlock_image(/obj/machinery/door/airlock/medical/glass), + "Research" = get_airlock_image(/obj/machinery/door/airlock/research/glass), + "Science" = get_airlock_image(/obj/machinery/door/airlock/science/glass), + "Virology" = get_airlock_image(/obj/machinery/door/airlock/virology/glass), + "Mining" = get_airlock_image(/obj/machinery/door/airlock/mining/glass), + "Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/glass), + "External" = get_airlock_image(/obj/machinery/door/airlock/external/glass), + "External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external/glass) + ) + + var/airlockcat = show_radial_menu(user, src, solid_or_glass_choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockcat) if("Solid") if(advanced_airlock_setting == 1) - var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Freezer", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance", "Airtight Hatch", "Maintenance Hatch") + var/airlockpaint = show_radial_menu(user, src, solid_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockpaint) if("Standard") airlock_type = /obj/machinery/door/airlock @@ -305,7 +367,9 @@ RLD if("Glass") if(advanced_airlock_setting == 1) - var/airlockpaint = input(usr, "Select the type of the airlock.") in list("Standard", "Public", "Engineering", "Atmospherics", "Security", "Command", "Medical", "Research", "Science", "Virology", "Mining", "Maintenance", "External", "External Maintenance") + var/airlockpaint = show_radial_menu(user, src , glass_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE) + if(!check_menu(user)) + return switch(airlockpaint) if("Standard") airlock_type = /obj/machinery/door/airlock/glass @@ -356,8 +420,8 @@ RLD playsound(src.loc, 'sound/machines/click.ogg', 50, 1) return TRUE -/obj/item/construction/rcd/New() - ..() +/obj/item/construction/rcd/Initialize() + . = ..() GLOB.rcd_list += src /obj/item/construction/rcd/Destroy() @@ -366,19 +430,46 @@ RLD /obj/item/construction/rcd/attack_self(mob/user) ..() - switch(mode) - if(1) - mode = 2 - to_chat(user, "You change RCD's mode to 'Airlock'.") - if(2) - mode = 3 - to_chat(user, "You change RCD's mode to 'Deconstruct'.") - if(3) - mode = 4 - to_chat(user, "You change RCD's mode to 'Grilles & Windows'.") - if(4) - mode = 1 - to_chat(user, "You change RCD's mode to 'Floor & Walls'.") + var/list/choices = list( + "Airlock" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"), + "Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"), + "Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"), + "Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor") + ) + if(mode == RCD_AIRLOCK) + choices += list( + "Change Access" = image(icon = 'icons/mob/radial.dmi', icon_state = "access"), + "Change Airlock Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlocktype") + ) + else if(mode == RCD_WINDOWGRILLE) + choices += list( + "Change Window Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "windowtype") + ) + var/choice = show_radial_menu(user,src,choices, custom_check = CALLBACK(src,.proc/check_menu,user)) + if(!check_menu(user)) + return + switch(choice) + if("Floors & Walls") + mode = RCD_FLOORWALL + if("Airlock") + mode = RCD_AIRLOCK + if("Deconstruct") + mode = RCD_DECONSTRUCT + if("Grilles & Windows") + mode = RCD_WINDOWGRILLE + if("Change Access") + change_airlock_access(user) + return + if("Change Airlock Type") + change_airlock_setting(user) + return + if("Change Window Type") + toggle_window_type(user) + return + else + return + playsound(src, 'sound/effects/pop.ogg', 50, 0) + to_chat(user, "You change RCD's mode to '[choice]'.") /obj/item/construction/rcd/proc/target_check(atom/A, mob/user) // only returns true for stuff the device can actually work with if((isturf(A) && A.density && mode==RCD_DECONSTRUCT) || (isturf(A) && !A.density) || (istype(A, /obj/machinery/door/airlock) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/grille) || (istype(A, /obj/structure/window) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/girder)) diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index bc1b128c69..cea8165e02 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -14,13 +14,14 @@ w_class = WEIGHT_CLASS_NORMAL var/max_amount = 90 var/active = FALSE - actions_types = list(/datum/action/item_action/rcl) + actions_types = list(/datum/action/item_action/rcl_col,/datum/action/item_action/rcl_gui) var/list/colors = list("red", "yellow", "green", "blue", "pink", "orange", "cyan", "white") var/current_color_index = 1 var/ghetto = FALSE lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' var/datum/component/mobhook + var/datum/radial_menu/persistent/wiring_gui_menu /obj/item/twohanded/rcl/attackby(obj/item/W, mob/user) if(istype(W, /obj/item/stack/cable_coil)) @@ -85,7 +86,8 @@ /obj/item/twohanded/rcl/Destroy() QDEL_NULL(loaded) last = null - setActive(FALSE, null) // setactive(FALSE) removes mobhook + QDEL_NULL(mobhook) + QDEL_NULL(wiring_gui_menu) return ..() /obj/item/twohanded/rcl/update_icon() @@ -115,20 +117,28 @@ if(loaded) QDEL_NULL(loaded) loaded = null + QDEL_NULL(wiring_gui_menu) unwield(user) - setActive(wielded, user) + active = wielded return TRUE return FALSE +/obj/item/twohanded/rcl/pickup(mob/user) + ..() + getMobhook(user) + + + /obj/item/twohanded/rcl/dropped(mob/wearer) ..() if(mobhook) - setActive(FALSE, mobhook.parent) + active = FALSE + QDEL_NULL(mobhook) last = null /obj/item/twohanded/rcl/attack_self(mob/user) ..() - setActive(wielded, user) + active = wielded if(!active) last = null else if(!last) @@ -137,17 +147,24 @@ last = C break -/obj/item/twohanded/rcl/proc/setActive(toggle, mob/user) - active = toggle - if (active && user) - if (mobhook && mobhook.parent != user) +obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook) + if(to_hook) + if(mobhook && mobhook.parent != to_hook) QDEL_NULL(mobhook) if (!mobhook) - mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger))) + mobhook = to_hook.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger))) else QDEL_NULL(mobhook) /obj/item/twohanded/rcl/proc/trigger(mob/user) + if(active) + layCable(user) + if(wiring_gui_menu) //update the wire options as you move + wiringGuiUpdate(user) + + +//previous contents of trigger(), lays cable each time the player moves +/obj/item/twohanded/rcl/proc/layCable(mob/user) if(!isturf(user.loc)) return if(is_empty(user, 0)) @@ -156,7 +173,7 @@ if(prob(2) && ghetto) //Give ghetto RCLs a 2% chance to jam, requiring it to be reactviated manually. to_chat(user, "[src]'s wires jam!") - setActive(FALSE, user) + active = FALSE return else if(last) @@ -179,6 +196,91 @@ is_empty(user) //If we've run out, display message update_icon() +//searches the current tile for a stub cable of the same colour +/obj/item/twohanded/rcl/proc/findLinkingCable(mob/user) + var/turf/T + if(!isturf(user.loc)) + return + + T = get_turf(user) + if(T.intact || !T.can_have_cabling()) + return + + for(var/obj/structure/cable/C in T) + if(!C) + continue + if(C.cable_color != GLOB.cable_colors[colors[current_color_index]]) + continue + if(C.d1 == 0) + return C + break + return + + +/obj/item/twohanded/rcl/proc/wiringGuiGenerateChoices(mob/user) + var/fromdir = 0 + var/obj/structure/cable/linkingCable = findLinkingCable(user) + if(linkingCable) + fromdir = linkingCable.d2 + + var/list/wiredirs = list("1","5","4","6","2","10","8","9") + for(var/icondir in wiredirs) + var/dirnum = text2num(icondir) + var/cablesuffix = "[min(fromdir,dirnum)]-[max(fromdir,dirnum)]" + if(fromdir == dirnum) //cables can't loop back on themselves + cablesuffix = "invalid" + var/image/img = image(icon = 'icons/mob/radial.dmi', icon_state = "cable_[cablesuffix]") + img.color = GLOB.cable_colors[colors[current_color_index]] + wiredirs[icondir] = img + return wiredirs + +/obj/item/twohanded/rcl/proc/showWiringGui(mob/user) + var/list/choices = wiringGuiGenerateChoices(user) + + wiring_gui_menu = show_radial_menu_persistent(user, src , choices, select_proc = CALLBACK(src, .proc/wiringGuiReact, user), radius = 42) + +/obj/item/twohanded/rcl/proc/wiringGuiUpdate(mob/user) + if(!wiring_gui_menu) + return + + wiring_gui_menu.entry_animation = FALSE //stop the open anim from playing each time we update + var/list/choices = wiringGuiGenerateChoices(user) + + wiring_gui_menu.change_choices(choices,FALSE) + + +//Callback used to respond to interactions with the wiring menu +/obj/item/twohanded/rcl/proc/wiringGuiReact(mob/living/user,choice) + if(!choice) //close on a null choice (the center button) + QDEL_NULL(wiring_gui_menu) + return + + choice = text2num(choice) + + if(!isturf(user.loc)) + return + if(is_empty(user, 0)) + to_chat(user, "\The [src] is empty!") + return + + var/turf/T = get_turf(user) + if(T.intact || !T.can_have_cabling()) + return + + loaded.item_color = colors[current_color_index] + + var/obj/structure/cable/linkingCable = findLinkingCable(user) + if(linkingCable) + if(choice != linkingCable.d2) + loaded.cable_join(linkingCable, user, FALSE, choice) + last = null + else + last = loaded.place_turf(get_turf(src), user, choice) + + is_empty(user) //If we've run out, display message + + wiringGuiUpdate(user) + /obj/item/twohanded/rcl/pre_loaded/Initialize() //Comes preloaded with cable, for testing stuff . = ..() @@ -192,12 +294,21 @@ update_icon() /obj/item/twohanded/rcl/ui_action_click(mob/user, action) - if(istype(action, /datum/action/item_action/rcl)) + if(istype(action, /datum/action/item_action/rcl_col)) current_color_index++; if (current_color_index > colors.len) current_color_index = 1 var/cwname = colors[current_color_index] to_chat(user, "Color changed to [cwname]!") + if(loaded) + loaded.item_color= colors[current_color_index] + if(wiring_gui_menu) + wiringGuiUpdate(user) + else if(istype(action, /datum/action/item_action/rcl_gui)) + if(wiring_gui_menu) //The menu is already open, close it + QDEL_NULL(wiring_gui_menu) + else //open the menu + showWiringGui(user) /obj/item/twohanded/rcl/ghetto actions_types = list() diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm index 41ddc22106..0549ebc474 100644 --- a/code/game/objects/items/RPD.dm +++ b/code/game/objects/items/RPD.dm @@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list( //make sure what we're clicking is valid for the current category var/static/list/make_pipe_whitelist if(!make_pipe_whitelist) - make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe)) + make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe, /obj/structure/window, /obj/structure/grille)) var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist)) . = FALSE diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index ab877ff97a..699efaac2e 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -59,7 +59,7 @@ /obj/item/areaeditor/blueprints/attack_self(mob/user) . = ..() if(!legend) - var/area/A = get_area() + var/area/A = get_area(user) if(get_area_type() == AREA_STATION) . += "According to \the [src], you are now in \"[html_encode(A.name)]\".
" . += "" @@ -140,12 +140,10 @@ legend = FALSE -/obj/item/areaeditor/proc/get_area() - var/turf/T = get_turf(usr) - var/area/A = T.loc - return A -/obj/item/areaeditor/proc/get_area_type(area/A = get_area()) +/obj/item/areaeditor/proc/get_area_type(area/A) + if(!A) + A = get_area(usr) if(A.outdoors) return AREA_SPACE var/list/SPECIALS = list( @@ -183,7 +181,7 @@ return "" /obj/item/areaeditor/proc/edit_area() - var/area/A = get_area() + var/area/A = get_area(usr) var/prevname = "[A.name]" var/str = stripped_input(usr,"New area name:", "Area Creation", "", MAX_NAME_LEN) if(!str || !length(str) || str==prevname) //cancel diff --git a/code/game/objects/items/body_egg.dm b/code/game/objects/items/body_egg.dm index a8f5894b7c..80fc0f43fd 100644 --- a/code/game/objects/items/body_egg.dm +++ b/code/game/objects/items/body_egg.dm @@ -16,7 +16,7 @@ /obj/item/organ/body_egg/Insert(var/mob/living/carbon/M, special = 0) ..() - owner.add_trait(TRAIT_XENO_HOST, TRAIT_GENERIC) + ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) START_PROCESSING(SSobj, src) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/AddInfectionImages, owner) @@ -24,7 +24,7 @@ /obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0) STOP_PROCESSING(SSobj, src) if(owner) - owner.remove_trait(TRAIT_XENO_HOST, TRAIT_GENERIC) + REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC) owner.med_hud_set_status() INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner) ..() diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 30b1ca3399..96bbe759ca 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -105,7 +105,7 @@ if(isturf(A)) return - if(istype(A,/obj/item/storage/lockbox)) + if(istype(A,/obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod)) A.emag_act(user) uses = max(uses - 1, 0) if(!uses) diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm index f7c37715aa..344e7c5472 100644 --- a/code/game/objects/items/chrono_eraser.dm +++ b/code/game/objects/items/chrono_eraser.dm @@ -248,9 +248,8 @@ /obj/effect/chrono_field/return_air() //we always have nominal air and temperature var/datum/gas_mixture/GM = new - GM.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen) - GM.gases[/datum/gas/oxygen][MOLES] = MOLES_O2STANDARD - GM.gases[/datum/gas/nitrogen][MOLES] = MOLES_N2STANDARD + GM.gases[/datum/gas/oxygen] = MOLES_O2STANDARD + GM.gases[/datum/gas/nitrogen] = MOLES_N2STANDARD GM.temperature = T20C return GM diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 1ad7974fc1..d64f5b57b8 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -102,7 +102,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM icon_state = "cigoff" throw_speed = 0.5 item_state = "cigoff" - container_type = INJECTABLE w_class = WEIGHT_CLASS_TINY body_parts_covered = null grind_results = list() @@ -123,8 +122,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/cigarette/Initialize() . = ..() - create_reagents(chem_volume) - reagents.set_reacting(FALSE) // so it doesn't react until you light it + create_reagents(chem_volume, INJECTABLE | NO_REACT) // so it doesn't react until you light it if(list_reagents) reagents.add_reagent_list(list_reagents) if(starts_lit) @@ -184,7 +182,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM qdel(src) return // allowing reagents to react after being lit - reagents.set_reacting(TRUE) + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) reagents.handle_reactions() icon_state = icon_on item_state = icon_on @@ -325,7 +323,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM list_reagents = list("space_drugs" = 15, "lipolicide" = 35) /obj/item/clothing/mask/cigarette/rollie/mindbreaker - list_reagents = list("mindbreaker" = 35, "lipolicide" = 15) + list_reagents = list("mindbreaker" = 35, "lipolicide" = 15) /obj/item/cigbutt/roach name = "roach" @@ -720,8 +718,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/vape/Initialize(mapload, param_color) . = ..() - create_reagents(chem_volume) - reagents.set_reacting(FALSE) // so it doesn't react until you light it + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) reagents.add_reagent("nicotine", 50) if(!icon_state) if(!param_color) @@ -790,13 +787,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(reagents.total_volume > 0) to_chat(user, "You empty [src] of all reagents.") reagents.clear_reagents() - return /obj/item/clothing/mask/vape/equipped(mob/user, slot) if(slot == SLOT_WEAR_MASK) if(!screw) to_chat(user, "You start puffing on the vape.") - reagents.set_reacting(TRUE) + DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) START_PROCESSING(SSobj, src) else //it will not start if the vape is opened. to_chat(user, "You need to close the cap first!") @@ -804,7 +800,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM /obj/item/clothing/mask/vape/dropped(mob/user) var/mob/living/carbon/C = user if(C.get_item_by_slot(SLOT_WEAR_MASK) == src) - reagents.set_reacting(FALSE) + ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT) STOP_PROCESSING(SSobj, src) /obj/item/clothing/mask/vape/proc/hand_reagents()//had to rename to avoid duplicate error diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 26f8a73cb3..99d6c874e8 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -68,6 +68,8 @@ var/pre_noise = FALSE var/post_noise = FALSE + var/datum/team/gang/gang //For marking territory. + var/gang_tag_delay = 30 //this is the delay for gang mode tag applications on anything that gang = true on. /obj/item/toy/crayon/suicide_act(mob/user) user.visible_message("[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!") @@ -252,7 +254,7 @@ cost = 0 if(ishuman(user)) var/mob/living/carbon/human/H = user - if (H.has_trait(TRAIT_TAGGER)) + if (HAS_TRAIT(H, TRAIT_TAGGER)) cost *= 0.5 var/charges_used = use_charges(user, cost) if(!charges_used) @@ -288,6 +290,13 @@ else if(drawing in numerals) temp = "number" + // If a gang member is using a gang spraycan, it'll behave differently + var/gang_mode = FALSE + if(gang && user.mind && user.mind.has_antag_datum(/datum/antagonist/gang)) //Heres a check. + gang_mode = TRUE // No more runtimes if a non-gang member sprays a gang can, it just works like normal cans. + // discontinue if the area isn't valid for tagging because gang "honour" + if(gang_mode && (!can_claim_for_gang(user, target))) + return var/graf_rot if(drawing in oriented) @@ -310,20 +319,22 @@ clicky = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2) if(!instant) - to_chat(user, "You start drawing a [temp] on the [target.name]...") + to_chat(user, "You start drawing a [temp] on the [target.name]...") if(pre_noise) audible_message("You hear spraying.") playsound(user.loc, 'sound/effects/spray.ogg', 5, 1, 5) - var/takes_time = !instant + var/takes_time = !instant //For order purposes, since I'm maximum bad. + if(gang_mode) + takes_time = TRUE var/wait_time = 50 if(paint_mode == PAINT_LARGE_HORIZONTAL) wait_time *= 3 - if(takes_time) - if(!do_after(user, 50, target = target)) + if(takes_time) //This is what deteremines the time it takes to spray a tag in gang mode. 50 is Default. + if(!do_after(user, gang_tag_delay, target = target)) //25 is a good number, but we have gang_tag_delay var now. return if(length(text_buffer)) @@ -332,26 +343,34 @@ var/list/turf/affected_turfs = list() + if(actually_paints) - switch(paint_mode) - if(PAINT_NORMAL) - var/obj/effect/decal/cleanable/crayon/C = new(target, paint_color, drawing, temp, graf_rot) - C.add_hiddenprint(user) - C.pixel_x = clickx - C.pixel_y = clicky - affected_turfs += target - if(PAINT_LARGE_HORIZONTAL) - var/turf/left = locate(target.x-1,target.y,target.z) - var/turf/right = locate(target.x+1,target.y,target.z) - if(is_type_in_list(left, validSurfaces) && is_type_in_list(right, validSurfaces)) - var/obj/effect/decal/cleanable/crayon/C = new(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON) + if(gang_mode) + // Double check it wasn't tagged in the meanwhile. + if(!can_claim_for_gang(user, target)) + return + tag_for_gang(user, target) + affected_turfs += target + else + switch(paint_mode) + if(PAINT_NORMAL) + var/obj/effect/decal/cleanable/crayon/C = new(target, paint_color, drawing, temp, graf_rot) C.add_hiddenprint(user) - affected_turfs += left - affected_turfs += right + C.pixel_x = clickx + C.pixel_y = clicky affected_turfs += target - else - to_chat(user, "There isn't enough space to paint!") - return + if(PAINT_LARGE_HORIZONTAL) + var/turf/left = locate(target.x-1,target.y,target.z) + var/turf/right = locate(target.x+1,target.y,target.z) + if(is_type_in_list(left, validSurfaces) && is_type_in_list(right, validSurfaces)) + var/obj/effect/decal/cleanable/crayon/C = new(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON) + C.add_hiddenprint(user) + affected_turfs += left + affected_turfs += right + affected_turfs += target + else + to_chat(user, "There isn't enough space to paint!") + return if(!instant) to_chat(user, "You finish drawing \the [temp].") @@ -373,6 +392,52 @@ reagents.trans_to(t, ., volume_multiplier) check_empty(user) + +//////////////Gang mode stuff///////////////// +/obj/item/toy/crayon/proc/can_claim_for_gang(mob/user, atom/target) + // Check area validity. + // Reject space, player-created areas, and non-station z-levels. + var/area/A = get_area(target) + if(!A || (!is_station_level(A.z)) || !A.valid_territory) + to_chat(user, "[A] is unsuitable for tagging.") + return FALSE + + var/spraying_over = FALSE + for(var/G in target) + var/obj/effect/decal/cleanable/crayon/gang/gangtag = G + if(istype(gangtag)) + var/datum/antagonist/gang/GA = user.mind.has_antag_datum(/datum/antagonist/gang) + if(gangtag.gang != GA.gang) + spraying_over = TRUE + break + + var/occupying_gang = territory_claimed(A, user) + if(occupying_gang && !spraying_over) + to_chat(user, "[A] has already been tagged by the [occupying_gang] gang! You must get rid of or spray over the old tag first!") + return FALSE + + // If you pass the gauntlet of checks, you're good to proceed + return TRUE + +/obj/item/toy/crayon/proc/territory_claimed(area/territory, mob/user) + for(var/datum/team/gang/G in GLOB.gangs) + if(territory.type in (G.territories|G.new_territories)) + . = G.name + break + +/obj/item/toy/crayon/proc/tag_for_gang(mob/user, atom/target) + //Delete any old markings on this tile, including other gang tags + for(var/obj/effect/decal/cleanable/crayon/old_marking in target) + qdel(old_marking) + + var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang) + var/area/territory = get_area(target) + + new /obj/effect/decal/cleanable/crayon/gang(target,G.gang,"graffiti",0,user) // Heres the gang tag. + to_chat(user, "You tagged [territory] for your gang!") +/////////////////Gang end//////////////////// + + /obj/item/toy/crayon/attack(mob/M, mob/user) if(edible && (M == user)) to_chat(user, "You take a bite of the [src.name]. Delicious!") @@ -524,6 +589,7 @@ is_capped = TRUE self_contained = FALSE // Don't disappear when they're empty can_change_colour = TRUE + gang = TRUE //Gang check is true for all things upon the honored hierarchy of spraycans, except those that are FALSE. validSurfaces = list(/turf/open/floor, /turf/closed/wall) reagent_contents = list("welding_fuel" = 1, "ethanol" = 1) @@ -669,6 +735,7 @@ icon_capped = "deathcan2_cap" icon_uncapped = "deathcan2" use_overlays = FALSE + gang = FALSE volume_multiplier = 25 charges = 100 @@ -683,6 +750,7 @@ icon_capped = "clowncan2_cap" icon_uncapped = "clowncan2" use_overlays = FALSE + gang = FALSE reagent_contents = list("lube" = 1, "banana" = 1) volume_multiplier = 5 @@ -695,6 +763,7 @@ icon_capped = "mimecan_cap" icon_uncapped = "mimecan" use_overlays = FALSE + gang = FALSE can_change_colour = FALSE paint_color = "#FFFFFF" //RGB @@ -703,6 +772,26 @@ post_noise = FALSE reagent_contents = list("nothing" = 1, "mutetoxin" = 1) +/obj/item/toy/crayon/spraycan/gang + charges = 20 // Charges back to 20, which is the default value for them. + gang = TRUE + gang_tag_delay = 15 //Its 50% faster than a regular spraycan, for tagging. After-all they did spend points/meet the boss. + + pre_noise = FALSE + post_noise = TRUE // Its even more stealthy just a tad. + +/obj/item/toy/crayon/spraycan/gang/Initialize(loc, datum/team/gang/G) + ..() + if(G) + gang = G + paint_color = G.color + update_icon() + +/obj/item/toy/crayon/spraycan/gang/examine(mob/user) + . = ..() + if(user.mind && user.mind.has_antag_datum(/datum/antagonist/gang) || isobserver(user)) + to_chat(user, "This spraycan has been specially modified with a stage 2 nozzle kit, making it faster.") + #undef RANDOM_GRAFFITI #undef RANDOM_LETTER #undef RANDOM_NUMBER diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index ba4a0ffae8..55e75b3992 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -444,7 +444,7 @@ /obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H) var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain) - return (!H.suiciding && !(H.has_trait(TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain) + return (!H.suiciding && !(HAS_TRAIT(H, TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain) /obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H) if(req_defib) @@ -585,7 +585,7 @@ shock_touching(30, H) var/failed - if (H.suiciding || (H.has_trait(TRAIT_NOCLONE))) + if (H.suiciding || (HAS_TRAIT(H, TRAIT_NOCLONE))) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile." else if (H.hellbound) failed = "[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile." diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 7d3d36c5b2..48b21d58bd 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -358,9 +358,9 @@ GLOBAL_LIST_EMPTY(PDAs) if (total_moles) for(var/id in env_gases) - var/gas_level = env_gases[id][MOLES]/total_moles + var/gas_level = env_gases[id]/total_moles if(gas_level > 0) - dat += "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_level*100, 0.01)]%It really is that easy! Good luck! - +