Merge remote-tracking branch 'upstream/master' into RCDMEMES

This commit is contained in:
BurgerLua
2019-06-10 16:40:10 -07:00
496 changed files with 9991 additions and 6589 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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"

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
@@ -72,6 +130,10 @@
#define TRAIT_CROCRIN_IMMUNE "crocin_immune"
#define TRAIT_NYMPHO "nymphomania"
#define TRAIT_MASO "masochism"
#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"
@@ -94,4 +156,3 @@
#define STASIS_MUTE "stasis"
#define GENETICS_SPELL "genetics_spell"
#define EYES_COVERED "eyes_covered"
#define CULT_EYES "cult_eyes"

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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),

View File

@@ -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,

View File

@@ -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") + "")

View File

@@ -109,5 +109,7 @@ 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,
"" = 3
))

View File

@@ -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

View File

@@ -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

View File

@@ -64,7 +64,7 @@
to_chat(user, "<span class='warning'>You're too exhausted.</span>") // CIT CHANGE - ditto
return // CIT CHANGE - ditto
if(force && user.has_trait(TRAIT_PACIFISM))
if(force && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return

View File

@@ -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)

View File

@@ -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"

View File

@@ -42,7 +42,7 @@
lose_text = "<span class='notice'>You feel smart again.</span>"
/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")
..()

View File

@@ -13,11 +13,11 @@
lose_text = "<span class='notice'>You suddenly remember how to speak.</span>"
/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
@@ -121,7 +121,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
@@ -183,11 +183,11 @@
lose_text = "<span class='notice'>You feel in control of your hands again.</span>"
/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
@@ -198,9 +198,9 @@
lose_text = "<span class='notice'>You no longer feel compelled to not harm.</span>"
/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)
..()

View File

@@ -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, "<span class='warning'>[codeword]</span>")

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -156,8 +156,7 @@
next += slave.parent
/datum/component/storage/proc/attack_self(datum/source, mob/M)
if(locked)
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
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, "<span class='warning'>[parent] seems to be locked!</span>")
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, "<span class='warning'>[parent] seems to be locked!</span>")
if(check_locked(null, M, TRUE))
return FALSE
A.add_fingerprint(M)
to_chat(M, "<span class='notice'>You start dumping out [parent].</span>")
@@ -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, "<span class='warning'>[parent] seems to be locked!</span>")
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, "<span class='warning'>[host] seems to be locked!</span>")
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, "<span class='warning'>[parent] seems to be locked!</span>")
/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, "<span class='warning'>[parent] seems to be locked!</span>")
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, "<span class='warning'>[parent] seems to be locked!</span>")
if(check_locked(source, user, TRUE))
return
var/atom/A = parent

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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, "<span class='notice'>Your vision slowly returns...</span>")
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, "<span class='notice'>You can finally focus your eyes on distant objects.</span>")
M.cure_nearsighted(EYE_DAMAGE)
M.blur_eyes(10)

View File

@@ -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, "<span class='userdanger'>You go blind!</span>")
M.become_blind(EYE_DAMAGE)
else

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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, "<span class ='warning'>You club yourself over the head with [src].</span>")
user.Knockdown(60)
if(ishuman(user))

View File

@@ -125,3 +125,11 @@
/datum/mood_event/surgery
description = "<span class='boldwarning'>HE'S CUTTING ME OPEN!!</span>\n"
mood_change = -8
/datum/mood_event/sad_empath
description = "<span class='warning'>Someone seems upset...</span>\n"
mood_change = -2
timeout = 600
/datum/mood_event/sad_empath/add_effects(mob/sadtarget)
description = "<span class='warning'>[sadtarget.name] seems upset...</span>\n"

View File

@@ -75,3 +75,27 @@
description = "<span class='nicegreen'>There is something soothing about this music.</span>\n"
mood_change = 3
timeout = 600
/datum/mood_event/betterhug
description = "<span class='nicegreen'>Someone was very nice to me.</span>\n"
mood_change = 3
timeout = 3000
/datum/mood_event/betterhug/add_effects(mob/friend)
description = "<span class='nicegreen'>[friend.name] was very nice to me.</span>\n"
/datum/mood_event/besthug
description = "<span class='nicegreen'>Someone is great to be around, they make me feel so happy!</span>\n"
mood_change = 5
timeout = 3000
/datum/mood_event/besthug/add_effects(mob/friend)
description = "<span class='nicegreen'>[friend.name] is great to be around, [friend.p_they()] makes me feel so happy!</span>\n"
/datum/mood_event/happy_empath
description = "<span class='warning'>Someone seems happy!</span>\n"
mood_change = 2
timeout = 600
/datum/mood_event/happy_empath/add_effects(var/mob/happytarget)
description = "<span class='warning'>[happytarget.name]'s happiness is infectious!</span>\n"

View File

@@ -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.

View File

@@ -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())

View File

@@ -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")

View File

@@ -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

View File

@@ -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, "<i><font color=#800080>We can faintly sense an outsider trying to communicate through the hivemind...</font></i>")
if(LINGHIVE_LING)
if (user.has_trait(CHANGELING_HIVEMIND_MUTE))
if (HAS_TRAIT(user, CHANGELING_HIVEMIND_MUTE))
to_chat(user, "<span class='warning'>The poison in the air hinders our ability to interact with the hivemind.</span>")
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))

View File

@@ -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)

View File

@@ -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 = "<span class='danger'>Things far away from you start looking blurry.</span>"

View File

@@ -35,6 +35,14 @@
lose_text = "<span class='danger'>You no longer feel like drinking would ease your pain.</span>"
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 = "<span class='notice'>You feel in tune with those around you.</span>"
lose_text = "<span class='danger'>You feel isolated from others.</span>"
/datum/quirk/freerunning
name = "Freerunning"
desc = "You're great at quick moves! You can climb tables more quickly."
@@ -43,6 +51,15 @@
gain_text = "<span class='notice'>You feel lithe on your feet!</span>"
lose_text = "<span class='danger'>You feel clumsy again.</span>"
/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 = "<span class='notice'>You want to hug someone.</span>"
lose_text = "<span class='danger'>You no longer feel compelled to hug others.</span>"
mood_quirk = TRUE
/datum/quirk/jolly
name = "Jolly"
desc = "You sometimes just feel happy, for no reason at all."

View File

@@ -93,3 +93,12 @@
gain_text = "<span class='notice'>You feel more prudish.</span>"
lose_text = "<span class='notice'>You don't feel as prudish as before.</span>"
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 = "<span class='notice'>Your ass rivals those of golems.</span>"
lose_text = "<span class='notice'>Your butt feels more squishy and slappable.</span>"

View File

@@ -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))

View File

@@ -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, "<span class='notice'>It has [reagents.total_volume] unit\s left.</span>")
else

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -1,3 +1,8 @@
#define ARCADE_WEIGHT_TRICK 4
#define ARCADE_WEIGHT_USELESS 2
#define ARCADE_WEIGHT_RARE 1
/obj/machinery/computer/arcade
name = "random arcade"
desc = "random arcade machine"
@@ -6,55 +11,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_USELESS,
/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 +90,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 +141,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 +191,7 @@
if(turtle > 0)
turtle--
sleep(10)
sleep(turn_speed)
enemy_hp -= attackamt
arcade_action(usr)
@@ -185,7 +204,7 @@
updateUsrDialog()
turtle++
sleep(10)
sleep(turn_speed)
player_mp -= pointamt
player_hp += healamt
blocked = TRUE
@@ -202,7 +221,7 @@
turtle--
updateUsrDialog()
sleep(10)
sleep(turn_speed)
arcade_action(usr)
if (href_list["close"])
@@ -211,10 +230,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 +279,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)

View File

@@ -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)

View File

@@ -450,7 +450,7 @@
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
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 = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return

View File

@@ -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

View File

@@ -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

View File

@@ -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("<span class='danger'>[user] headbutts the airlock.</span>", \

View File

@@ -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 = "<font class='bad'>Unable to locate valid genetic data.</font>"
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 = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return

View File

@@ -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

View File

@@ -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
. = ..()

View File

@@ -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

View File

@@ -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(..())

View File

@@ -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)

View File

@@ -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, "<span class='warning'>You don't want to harm other living beings!</span>")
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, "<span class='warning'>You don't want to harm other living beings!</span>")
return
if(selected.action(target,params))

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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, "<span class='warning'>You hit [src] but bounce off it!</span>")
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("<span class='danger'>[U] sealed shut!</span>")
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, "<span class='warning'>You hit [src] but bounce off it!</span>")
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("<span class='danger'>[U] sealed shut!</span>")
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

View File

@@ -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("<span class='danger'>[U] was frozen shut!</span>")
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("<span class='danger'>[U] was frozen shut!</span>")
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

View File

@@ -170,7 +170,7 @@
if(!victim.client || !istype(victim))
return
to_chat(victim, "<span class='notice'>You feel fast!</span>")
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, "<span class='notice'>You slow down.</span>")

View File

@@ -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

View File

@@ -256,7 +256,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 +449,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, "<span class='warning'>You don't want to harm [M]!</span>")
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 +523,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
M.adjust_blurriness(15)
if(M.stat != DEAD)
to_chat(M, "<span class='danger'>Your eyes start to bleed profusely!</span>")
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, "<span class='danger'>You become nearsighted!</span>")
M.become_nearsighted(EYE_DAMAGE)
if(prob(50))

View File

@@ -161,13 +161,18 @@ RLD
user.visible_message("<span class='suicide'>[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..</span>")
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, "<span class='notice'>You change \the [src]'s window mode to [window_type_name].</span>")
to_chat(user, "<span class='notice'>You change \the [src]'s window mode to [window_type_name].</span>")
/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 += "<p><a href='?src=[REF(src)];close=1'>Close</a></p>\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, "<span class='notice'>You change RCD's mode to 'Airlock'.</span>")
if(2)
mode = 3
to_chat(user, "<span class='notice'>You change RCD's mode to 'Deconstruct'.</span>")
if(3)
mode = 4
to_chat(user, "<span class='notice'>You change RCD's mode to 'Grilles & Windows'.</span>")
if(4)
mode = 1
to_chat(user, "<span class='notice'>You change RCD's mode to 'Floor & Walls'.</span>")
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, "<span class='notice'>You change RCD's mode to '[choice]'.</span>")
/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))

View File

@@ -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, "<span class='warning'>[src]'s wires jam!</span>")
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, "<span class='warning'>\The [src] is empty!</span>")
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()

View File

@@ -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

View File

@@ -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)
. += "<p>According to \the [src], you are now in <b>\"[html_encode(A.name)]\"</b>.</p>"
. += "<p><a href='?src=[REF(src)];edit_area=1'>Change area name</a></p>"
@@ -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

View File

@@ -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)
..()

View File

@@ -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)

View File

@@ -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

View File

@@ -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, "<span class='notice'>You empty [src] of all reagents.</span>")
reagents.clear_reagents()
return
/obj/item/clothing/mask/vape/equipped(mob/user, slot)
if(slot == SLOT_WEAR_MASK)
if(!screw)
to_chat(user, "<span class='notice'>You start puffing on the vape.</span>")
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, "<span class='warning'>You need to close the cap first!</span>")
@@ -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

View File

@@ -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("<span class='suicide'>[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!</span>")
@@ -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, "<span class='notice'>You start drawing a [temp] on the [target.name]...</span>")
to_chat(user, "<span class='notice'>You start drawing a [temp] on the [target.name]...</span>")
if(pre_noise)
audible_message("<span class='notice'>You hear spraying.</span>")
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, "<span class='warning'>There isn't enough space to paint!</span>")
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, "<span class='warning'>There isn't enough space to paint!</span>")
return
if(!instant)
to_chat(user, "<span class='notice'>You finish drawing \the [temp].</span>")
@@ -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, "<span class='warning'>[A] is unsuitable for tagging.</span>")
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, "<span class='danger'>[A] has already been tagged by the [occupying_gang] gang! You must get rid of or spray over the old tag first!</span>")
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, "<span class='notice'>You tagged [territory] for your gang!</span>")
/////////////////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

View File

@@ -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 = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile.</span>"
else if (H.hellbound)
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile.</span>"

View File

@@ -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)]%<br>"
dat += "[GLOB.meta_gas_names[id]]: [round(gas_level*100, 0.01)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<br>"

View File

@@ -52,7 +52,7 @@
add_fingerprint(user)
if(istype(M) && on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))
if((user.has_trait(TRAIT_CLUMSY) || user.has_trait(TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!user.IsAdvancedToolUser())
@@ -86,7 +86,7 @@
else
user.visible_message("<span class='warning'>[user] directs [src] to [M]'s eyes.</span>", \
"<span class='danger'>You direct [src] to [M]'s eyes.</span>")
if(M.stat == DEAD || (M.has_trait(TRAIT_BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
to_chat(user, "<span class='warning'>[M]'s pupils don't react to the light!</span>")
else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-ray vision
to_chat(user, "<span class='danger'>[M]'s pupils give an eerie glow!</span>")

View File

@@ -54,7 +54,7 @@
/obj/item/instrument/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/musicaltuner))
var/mob/living/carbon/human/H = user
if (H.has_trait(TRAIT_MUSICIAN))
if (HAS_TRAIT(H, TRAIT_MUSICIAN))
if (!tune_time)
H.visible_message("[H] tunes the [src] to perfection!", "<span class='notice'>You tune the [src] to perfection!</span>")
tune_time = 300

View File

@@ -69,7 +69,7 @@
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if(user.has_trait(TRAIT_NOGUNS))
if(HAS_TRAIT(user, TRAIT_NOGUNS))
to_chat(user, "<span class='warning'>Your fingers can't press the button!</span>")
return
if(ishuman(user))

View File

@@ -95,7 +95,7 @@ SLIME SCANNER
/obj/item/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
// Clumsiness/brain damage check
if ((user.has_trait(TRAIT_CLUMSY) || user.has_trait(TRAIT_DUMB)) && prob(50))
if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50))
to_chat(user, "<span class='notice'>You stupidly try to analyze the floor's vitals!</span>")
user.visible_message("<span class='warning'>[user] has analyzed the floor's vitals!</span>")
var/msg = "<span class='info'>*---------*\nAnalyzing results for The floor:\n\tOverall status: <b>Healthy</b>\n"
@@ -127,7 +127,7 @@ SLIME SCANNER
var/brute_loss = M.getBruteLoss()
var/mob_status = (M.stat == DEAD ? "<span class='alert'><b>Deceased</b></span>" : "<b>[round(M.health/M.maxHealth,0.01)*100] % healthy</b>")
if(M.has_trait(TRAIT_FAKEDEATH) && !advanced)
if(HAS_TRAIT(M, TRAIT_FAKEDEATH) && !advanced)
mob_status = "<span class='alert'><b>Deceased</b></span>"
oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss
@@ -199,10 +199,10 @@ SLIME SCANNER
msg += "\t<span class='info'><b>==EAR STATUS==</b></span>\n"
if(istype(ears))
var/healthy = TRUE
if(C.has_trait(TRAIT_DEAF, GENETIC_MUTATION))
if(HAS_TRAIT_FROM(C, TRAIT_DEAF, GENETIC_MUTATION))
healthy = FALSE
msg += "\t<span class='alert'>Subject is genetically deaf.</span>\n"
else if(C.has_trait(TRAIT_DEAF))
else if(HAS_TRAIT(C, TRAIT_DEAF))
healthy = FALSE
msg += "\t<span class='alert'>Subject is deaf.</span>\n"
else
@@ -220,10 +220,10 @@ SLIME SCANNER
msg += "\t<span class='info'><b>==EYE STATUS==</b></span>\n"
if(istype(eyes))
var/healthy = TRUE
if(C.has_trait(TRAIT_BLIND))
if(HAS_TRAIT(C, TRAIT_BLIND))
msg += "\t<span class='alert'>Subject is blind.</span>\n"
healthy = FALSE
if(C.has_trait(TRAIT_NEARSIGHT))
if(HAS_TRAIT(C, TRAIT_NEARSIGHT))
msg += "\t<span class='alert'>Subject is nearsighted.</span>\n"
healthy = FALSE
if(eyes.eye_damage > 30)
@@ -290,7 +290,7 @@ SLIME SCANNER
msg += "<span class='info'>Body temperature: [round(M.bodytemperature-T0C,0.1)] &deg;C ([round(M.bodytemperature*1.8-459.67,0.1)] &deg;F)</span>\n"
// Time of death
if(M.tod && (M.stat == DEAD || ((M.has_trait(TRAIT_FAKEDEATH)) && !advanced)))
if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced)))
msg += "<span class='info'>Time of Death:</span> [M.tod]\n"
var/tdelta = round(world.time - M.timeofdeath)
if(tdelta < (DEFIB_TIME_LIMIT * 10))
@@ -428,39 +428,38 @@ SLIME SCANNER
if(total_moles)
var/list/env_gases = environment.gases
environment.assert_gases(arglist(GLOB.hardcoded_gases))
var/o2_concentration = env_gases[/datum/gas/oxygen][MOLES]/total_moles
var/n2_concentration = env_gases[/datum/gas/nitrogen][MOLES]/total_moles
var/co2_concentration = env_gases[/datum/gas/carbon_dioxide][MOLES]/total_moles
var/plasma_concentration = env_gases[/datum/gas/plasma][MOLES]/total_moles
var/o2_concentration = env_gases[/datum/gas/oxygen]/total_moles
var/n2_concentration = env_gases[/datum/gas/nitrogen]/total_moles
var/co2_concentration = env_gases[/datum/gas/carbon_dioxide]/total_moles
var/plasma_concentration = env_gases[/datum/gas/plasma]/total_moles
if(abs(n2_concentration - N2STANDARD) < 20)
to_chat(user, "<span class='info'>Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='info'>Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)</span>")
else
to_chat(user, "<span class='alert'>Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='alert'>Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)</span>")
if(abs(o2_concentration - O2STANDARD) < 2)
to_chat(user, "<span class='info'>Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='info'>Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)</span>")
else
to_chat(user, "<span class='alert'>Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='alert'>Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)</span>")
if(co2_concentration > 0.01)
to_chat(user, "<span class='alert'>CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='alert'>CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)</span>")
else
to_chat(user, "<span class='info'>CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='info'>CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)</span>")
if(plasma_concentration > 0.005)
to_chat(user, "<span class='alert'>Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='alert'>Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)</span>")
else
to_chat(user, "<span class='info'>Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma][MOLES], 0.01)] mol)</span>")
to_chat(user, "<span class='info'>Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)</span>")
environment.garbage_collect()
GAS_GARBAGE_COLLECT(environment.gases)
for(var/id in env_gases)
if(id in GLOB.hardcoded_gases)
continue
var/gas_concentration = env_gases[id][MOLES]/total_moles
to_chat(user, "<span class='alert'>[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id][MOLES], 0.01)] mol)</span>")
var/gas_concentration = env_gases[id]/total_moles
to_chat(user, "<span class='alert'>[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id], 0.01)] mol)</span>")
to_chat(user, "<span class='info'>Temperature: [round(environment.temperature-T0C, 0.01)] &deg;C ([round(environment.temperature, 0.01)] K)</span>")
/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
@@ -550,8 +549,8 @@ SLIME SCANNER
var/list/cached_gases = air_contents.gases
for(var/id in cached_gases)
var/gas_concentration = cached_gases[id][MOLES]/total_moles
to_chat(user, "<span class='notice'>[cached_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id][MOLES], 0.01)] mol)</span>")
var/gas_concentration = cached_gases[id]/total_moles
to_chat(user, "<span class='notice'>[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id], 0.01)] mol)</span>")
to_chat(user, "<span class='notice'>Temperature: [round(temperature - T0C,0.01)] &deg;C ([round(temperature, 0.01)] K)</span>")
else

View File

@@ -31,7 +31,7 @@
/obj/item/dnainjector/proc/inject(mob/living/carbon/M, mob/user)
prepare()
if(M.has_dna() && !M.has_trait(TRAIT_RADIMMUNE) && !M.has_trait(TRAIT_NOCLONE))
if(M.has_dna() && !HAS_TRAIT(M, TRAIT_RADIMMUNE) && !HAS_TRAIT(M, TRAIT_NOCLONE))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
for(var/datum/mutation/human/HM in remove_mutations)
@@ -313,7 +313,7 @@
to_chat(user, "<span class='notice'>You can't modify [M]'s DNA while [M.p_theyre()] dead.</span>")
return FALSE
if(M.has_dna() && !(M.has_trait(TRAIT_NOCLONE)))
if(M.has_dna() && !(HAS_TRAIT(M, TRAIT_NOCLONE)))
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
var/endtime = world.time+duration

View File

@@ -15,7 +15,6 @@
attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
dog_fashion = /datum/dog_fashion/back
resistance_flags = FIRE_PROOF
container_type = AMOUNT_VISIBLE
var/max_water = 50
var/last_use = 1
var/chem = "water"
@@ -56,7 +55,7 @@
/obj/item/extinguisher/Initialize()
. = ..()
create_reagents(max_water)
create_reagents(max_water, AMOUNT_VISIBLE)
reagents.add_reagent(chem, max_water)

View File

@@ -205,7 +205,7 @@
//Transfer 5% of current tank air contents to turf
var/datum/gas_mixture/air_transfer = ptank.air_contents.remove_ratio(release_amount)
if(air_transfer.gases[/datum/gas/plasma])
air_transfer.gases[/datum/gas/plasma][MOLES] *= 5
air_transfer.gases[/datum/gas/plasma] *= 5
target.assume_air(air_transfer)
//Burn it based on transfered gas
target.hotspot_expose((ptank.air_contents.temperature*2) + 380,500)

Some files were not shown because too many files have changed in this diff Show More