diff --git a/_maps/RandomRuins/SpaceRuins/spacehermit.dmm b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm index 8113c586ff..dd7e700146 100644 --- a/_maps/RandomRuins/SpaceRuins/spacehermit.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacehermit.dmm @@ -145,9 +145,6 @@ "aE" = ( /turf/open/floor/plating/asteroid/airless, /area/ruin/powered) -"aF" = ( -/turf/open/floor/plating/asteroid, -/area/ruin/powered) "aG" = ( /obj/structure/sink/puddle, /turf/open/floor/plating/asteroid, @@ -241,7 +238,7 @@ /turf/closed/mineral/random/low_chance/earth_like, /area/ruin/powered) "bb" = ( -/turf/closed/mineral/random/earth_like, +/turf/closed/mineral/random/no_caves/earth_like, /area/ruin/powered) "bc" = ( /obj/item/circuitboard/machine/circuit_imprinter, @@ -1137,7 +1134,7 @@ ao ao ak af -aF +am bb bb bb @@ -1189,7 +1186,7 @@ an an ae ae -aF +am bb bb bb @@ -1223,8 +1220,8 @@ bb bb bb ba -aF -aF +am +am ba ba ba @@ -1241,7 +1238,7 @@ ar af at at -aF +am bb fp bb @@ -1275,10 +1272,10 @@ bb bb bb ad -aF -aF -aF -aF +am +am +am +am ba aH aJ @@ -1286,13 +1283,13 @@ aL bb bb aT -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am aR bb bb @@ -1328,23 +1325,23 @@ bb bb ad au -aF +am aB -aF -aF -aF -aF -aF +am +am +am +am +am ba bb -aF -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am +am bg bb fp @@ -1384,19 +1381,19 @@ bs aC bC WH -aF -aF -aF +am +am +am ba bb bb -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am bb bb bb @@ -1432,23 +1429,23 @@ bb bb ad ax -aF +am aD -aF -aF -aF -aF +am +am +am +am bb bb bb aU bd -aF -aF +am +am bl bm -aF -aF +am +am bb bb bb @@ -1484,20 +1481,20 @@ bb bb ad ay -aF -aF -aF +am +am +am aG -aF -aF +am +am bb bb ba av be -aF -aF -aF +am +am +am bn bo bo @@ -1535,24 +1532,24 @@ bb bb bb ba -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am bb bb bb bc bf -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am br bb bb @@ -1590,22 +1587,22 @@ bb bb bb bb -aF -aF -aF -aF -aF +am +am +am +am +am bb bb -aF -aF -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am +am +am bb bb bb @@ -1642,21 +1639,21 @@ bb bb bb bb -aF -aF -aF -aF -aF +am +am +am +am +am aN -aF -aF -aF -aF +am +am +am +am aR -aF -aF -aF -aF +am +am +am +am bb bb fp @@ -1695,22 +1692,22 @@ bb bb bb ba -aF -aF -aF +am +am +am ba ba -aF -aF -aF -aF -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am +am +am +am +am ba ba ba @@ -1752,16 +1749,16 @@ ba aK ba ba -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am bp -aF -aF +am +am aR ba ba @@ -1805,15 +1802,15 @@ ba fp ba aP -aF -aF -aF -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am +am +am +am aR ba ba @@ -1858,15 +1855,15 @@ ba ba aQ aP -aF -aF +am +am aR -aF -aF -aF -aF +am +am +am +am bb -aF +am ba ba aZ @@ -1910,12 +1907,12 @@ ba ba ba ba -aF -aF -aF -aF +am +am +am +am aP -aF +am bg bb bb @@ -1962,12 +1959,12 @@ bb bb ba ba -aF -aF -aF -aF -aF -aF +am +am +am +am +am +am aS bb fp @@ -2015,11 +2012,11 @@ bb bb ba bg -aF -aF -aF -aF -aF +am +am +am +am +am aS bb fp @@ -2066,12 +2063,12 @@ bb bb fp ba -aF -aF +am +am bj -aF -aF -aF +am +am +am aS fp bb @@ -2120,9 +2117,9 @@ ba ba aS bi -aF -aF -aF +am +am +am aS aS bb @@ -2171,10 +2168,10 @@ ba aZ ba aS -aF -aF -aF -aF +am +am +am +am aS aS ba diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 3b2ee52e24..ab83534102 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -44066,7 +44066,6 @@ /area/science/misc_lab) "cbe" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer, /turf/open/floor/plasteel/white, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 61ed3edba7..9a738f12ee 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -126146,7 +126146,6 @@ /area/quartermaster/storage) "hic" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer, /turf/open/floor/plasteel/white/side{ @@ -127145,7 +127144,6 @@ /area/ai_monitored/turret_protected/aisat_interior) "qhc" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer, /turf/open/floor/plasteel/white/side{ diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 3eaad62714..abdf574918 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -33907,7 +33907,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/item/integrated_electronics/analyzer, /obj/machinery/computer/security/telescreen/circuitry{ pixel_y = 30 }, diff --git a/_maps/map_files/LambdaStation/lambda.dmm b/_maps/map_files/LambdaStation/lambda.dmm index 6d1469d483..a307026453 100644 --- a/_maps/map_files/LambdaStation/lambda.dmm +++ b/_maps/map_files/LambdaStation/lambda.dmm @@ -1556,7 +1556,6 @@ dir = 8 }, /obj/structure/table, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_circuit_printer, /turf/open/floor/plasteel/dark, /area/science/nanite) diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index e6eddb2777..9294516092 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -81886,7 +81886,6 @@ /area/maintenance/aft) "gRS" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_circuit_printer, /turf/open/floor/plasteel/white, /area/science/circuit) @@ -82471,7 +82470,6 @@ /turf/open/floor/plasteel/white, /area/science/circuit) "ohj" = ( -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer, /obj/structure/table/reinforced, diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm index 8a951881f9..9f79e3ecba 100644 --- a/_maps/map_files/OmegaStation/OmegaStation.dmm +++ b/_maps/map_files/OmegaStation/OmegaStation.dmm @@ -26358,7 +26358,6 @@ dir = 8 }, /obj/item/integrated_circuit_printer, -/obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer, /obj/effect/turf_decal/tile/neutral, diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index bdbce36c9c..0ccbf1623b 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -27443,7 +27443,6 @@ /area/science/explab) "bmZ" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/machinery/magnetic_controller{ autolink = 1; pixel_x = -28; @@ -60715,7 +60714,6 @@ /area/maintenance/department/crew_quarters/dorms) "vmG" = ( /obj/structure/table/reinforced, -/obj/item/integrated_electronics/analyzer, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index e75f832df3..53348b3467 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -179,7 +179,7 @@ // #define SPEECH_FORCED 7 #define COMSIG_MOB_ANTAG_ON_GAIN "mob_antag_on_gain" //from base of /datum/antagonist/on_gain(): (antag_datum) -#define COMSIG_MOB_SPELL_CAST_CHECK "mob_spell_cast_check" //called from base of /obj/effect/proc_holder/spell/cast_check(): (spell) +#define COMSIG_MOB_SPELL_CAN_CAST "mob_spell_can_cast" //called from base of /obj/effect/proc_holder/spell/can_cast(): (spell) // /mob/living signals #define COMSIG_LIVING_REGENERATE_LIMBS "living_regenerate_limbs" //from base of /mob/living/regenerate_limbs(): (noheal, excluded_limbs) @@ -190,6 +190,7 @@ #define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: () #define COMSIG_LIVING_REVIVE "living_revive" //from base of mob/living/revive() (full_heal, admin_revive) #define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login" //sent when a mob/login() finishes: (client) +#define COMSIG_MOB_CLIENT_LOGOUT "comsig_mob_client_logout" //sent when a mob/logout() starts: (client) #define COMSIG_MOB_CLIENT_MOVE "comsig_mob_client_move" //sent when client/Move() finishes with no early returns: (client, direction, n, oldloc) #define COMSIG_LIVING_GUN_PROCESS_FIRE "living_gun_process_fire" //from base of /obj/item/gun/proc/process_fire(): (atom/target, params, zone_override) // This returns flags as defined for block in __DEFINES/combat.dm! @@ -242,12 +243,14 @@ #define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user) #define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args) #define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable) +#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays) // THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm! #define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) #define COMSIG_ITEM_RUN_BLOCK "run_block" //from base of obj/item/run_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) // /obj/item/clothing signals #define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): () +#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet) // /obj/item/implant signals #define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): () diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index f4954f8f05..fd50b8b70d 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -1,13 +1,5 @@ /*ALL DEFINES RELATED TO INVENTORY OBJECTS, MANAGEMENT, ETC, GO HERE*/ -//ITEM INVENTORY WEIGHT, FOR w_class -#define WEIGHT_CLASS_TINY 1 //Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money -#define WEIGHT_CLASS_SMALL 2 //Pockets can hold small and tiny items, ex: Flashlight, Multitool, Grenades, GPS Device -#define WEIGHT_CLASS_NORMAL 3 //Standard backpacks can carry tiny, small & normal items, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets -#define WEIGHT_CLASS_BULKY 4 //Items that can be weilded or equipped but not stored in a normal bag, ex: Defibrillator, Backpack, Space Suits -#define WEIGHT_CLASS_HUGE 5 //Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons - Can not fit in Boh -#define WEIGHT_CLASS_GIGANTIC 6 //Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh - //Inventory depth: limits how many nested storage items you can access directly. //1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc #define INVENTORY_DEPTH 3 diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 55bfcaff79..4be0985fbc 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -67,6 +67,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define iscatperson(A) (ishumanbasic(A) && istype(A.dna.species, /datum/species/human/felinid) ) #define isdwarf(A) (is_species(A, /datum/species/dwarf)) #define isdullahan(A) (is_species(A, /datum/species/dullahan)) +#define isvampire(A) (is_species(A,/datum/species/vampire)) // Citadel specific species #define isipcperson(A) (is_species(A, /datum/species/ipc)) @@ -263,4 +264,4 @@ GLOBAL_LIST_INIT(glass_sheet_types, typecacheof(list( #define isblobmonster(O) (istype(O, /mob/living/simple_animal/hostile/blob)) -#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs)) \ No newline at end of file +#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs)) diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers_planes.dm similarity index 90% rename from code/__DEFINES/layers.dm rename to code/__DEFINES/layers_planes.dm index 35947b320e..d0f9f8bc28 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers_planes.dm @@ -129,11 +129,20 @@ #define HUD_PLANE 21 #define HUD_LAYER 21 #define HUD_RENDER_TARGET "HUD_PLANE" -#define ABOVE_HUD_PLANE 22 -#define ABOVE_HUD_LAYER 22 + +#define VOLUMETRIC_STORAGE_BOX_PLANE 23 +#define VOLUMETRIC_STORAGE_BOX_LAYER 23 +#define VOLUMETRIC_STORAGE_BOX_RENDER_TARGET "VOLUME_STORAGE_BOX_PLANE" + +#define VOLUMETRIC_STORAGE_ITEM_PLANE 24 +#define VOLUMETRIC_STORAGE_ITEM_LAYER 24 +#define VOLUMETRIC_STORAGE_ITEM_RENDER_TARGET "VOLUME_STORAGE_ITEM_PLANE" + +#define ABOVE_HUD_PLANE 25 +#define ABOVE_HUD_LAYER 25 #define ABOVE_HUD_RENDER_TARGET "ABOVE_HUD_PLANE" -#define SPLASHSCREEN_LAYER 23 -#define SPLASHSCREEN_PLANE 23 +#define SPLASHSCREEN_LAYER 30 +#define SPLASHSCREEN_PLANE 30 #define SPLASHSCREEN_RENDER_TARGET "SPLASHSCREEN_PLANE" diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm index bc1e6f7d5f..4d40474a3c 100644 --- a/code/__DEFINES/movespeed_modification.dm +++ b/code/__DEFINES/movespeed_modification.dm @@ -59,6 +59,7 @@ #define MOVESPEED_ID_SPECIES "SPECIES_SPEED_MOD" +#define MOVESPEED_ID_SMALL_STRIDE "SMALL_STRIDE" #define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG" #define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY" #define MOVESPEED_ID_SHRINK_RAY "SHRUNKEN_SPEED_MODIFIER" diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm new file mode 100644 index 0000000000..b4240455fe --- /dev/null +++ b/code/__DEFINES/storage.dm @@ -0,0 +1,47 @@ +// storage_flags variable on /datum/component/storage + +// Storage limits. These can be combined (and usually are combined). +/// Check max_items and contents.len when trying to insert +#define STORAGE_LIMIT_MAX_ITEMS (1<<0) +/// Check max_combined_w_class. +#define STORAGE_LIMIT_COMBINED_W_CLASS (1<<1) +/// Use the new volume system. Will automatically force rendering to use the new volume/baystation scaling UI so this is kind of incompatible with stuff like stack storage etc etc. +#define STORAGE_LIMIT_VOLUME (1<<2) +/// Use max_w_class +#define STORAGE_LIMIT_MAX_W_CLASS (1<<3) + +#define STORAGE_FLAGS_LEGACY_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_VOLUME_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) + +//ITEM INVENTORY WEIGHT, FOR w_class +/// Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money +#define WEIGHT_CLASS_TINY 1 +/// Pockets can hold small and tiny items, ex: Flashlight, Multitool, Grenades, GPS Device +#define WEIGHT_CLASS_SMALL 2 +/// Standard backpacks can carry tiny, small & normal items, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets +#define WEIGHT_CLASS_NORMAL 3 +/// Items that can be weilded or equipped but not stored in a normal bag, ex: Defibrillator, Backpack, Space Suits +#define WEIGHT_CLASS_BULKY 4 +/// Usually represents objects that require two hands to operate, ex: Shotgun, Two Handed Melee Weapons - Can not fit in Boh +#define WEIGHT_CLASS_HUGE 5 +/// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh +#define WEIGHT_CLASS_GIGANTIC 6 + +/// Macro for automatically getting the volume of an item from its w_class. +#define AUTO_SCALE_VOLUME(w_class) (2 ** w_class) +/// Macro for automatically getting the volume of a storage item from its max_w_class and max_combined_w_class. +#define AUTO_SCALE_STORAGE_VOLUME(w_class, max_combined_w_class) (AUTO_SCALE_VOLUME(w_class) * (max_combined_w_class / w_class)) + +// UI defines +/// Size of volumetric box icon +#define VOLUMETRIC_STORAGE_BOX_ICON_SIZE 32 +/// Size of EACH left/right border icon for volumetric boxes +#define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1 +/// Minimum pixels an item must have in volumetric scaled storage UI +#define MINIMUM_PIXELS_PER_ITEM 6 +/// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups. +#define MAXIMUM_VOLUMETRIC_ITEMS 256 +/// How much padding to give between items +#define VOLUMETRIC_STORAGE_ITEM_PADDING 1 +/// How much padding to give to edges +#define VOLUMETRIC_STORAGE_EDGE_PADDING 1 diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index f16b566b00..a34b3ce67c 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -550,6 +550,27 @@ for(var/thing in flat_list) .[thing] = TRUE +/proc/deep_list2params(list/deep_list) + var/list/L = list() + for(var/i in deep_list) + var/key = i + if(isnum(key)) + L += "[key]" + continue + if(islist(key)) + key = deep_list2params(key) + else if(!istext(key)) + key = "[REF(key)]" + L += "[key]" + var/value = deep_list[key] + if(!isnull(value)) + if(islist(value)) + value = deep_list2params(value) + else if(!(istext(key) || isnum(key))) + value = "[REF(value)]" + L["[key]"] = "[value]" + return list2params(L) + //Picks from the list, with some safeties, and returns the "default" arg if it fails #define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 38e25b04c5..0c45a746d8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -89,6 +89,14 @@ INVOKE_ASYNC(GLOBAL_PROC, /proc/init_ref_coin_values) //so the current procedure doesn't sleep because of UNTIL() + for(var/path in subtypesof(/area/holodeck)) + var/area/holodeck/A = path + var/list/compatibles = initial(A.compatible_holodeck_comps) + if(!compatibles || initial(A.abstract_type) == path) + continue + for(var/comp in compatibles) + LAZYADD(GLOB.holodeck_areas_prototypes[comp], A) + //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. /proc/init_subtypes(prototype, list/L) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 7a62d7ba1c..86e72501f8 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -215,7 +215,8 @@ "ipc_antenna" = "None", "flavor_text" = "", "meat_type" = "Mammalian", - "body_model" = body_model + "body_model" = body_model, + "body_size" = RESIZE_DEFAULT_SIZE )) /proc/random_hair_style(gender) diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index e416396991..7cbfbd040a 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -513,7 +513,7 @@ if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED) SSticker.show_roundend_report(owner.client, FALSE) -/datum/action/report/IsAvailable() +/datum/action/report/IsAvailable(silent = FALSE) return 1 /datum/action/report/Topic(href,href_list) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index a9f2750ce2..afa858afb7 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1563,3 +1563,16 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) if(channels_to_use.len) world.TgsChatBroadcast() + +//Checks to see if either the victim has a garlic necklace or garlic in their blood +/proc/blood_sucking_checks(var/mob/living/carbon/target, check_neck, check_blood) + //Bypass this if the target isnt carbon. + if(!iscarbon(target)) + return TRUE + if(check_neck) + if(istype(target.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace)) + return FALSE + if(check_blood) + if(target.reagents.has_reagent(/datum/reagent/consumable/garlic)) + return FALSE + return TRUE diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 5367322d8e..f0c854c398 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -249,5 +249,11 @@ GLOBAL_LIST_INIT(bitfields, list( "COMBAT_FLAG_SOFT_STAMCRIT" = COMBAT_FLAG_SOFT_STAMCRIT, "COMBAT_FLAG_INTENTIONALLY_RESTING" = COMBAT_FLAG_INTENTIONALLY_RESTING, "COMBAT_FLAG_RESISTING_REST" = COMBAT_FLAG_RESISTING_REST + ), + "storage_flags" = list( + "STORAGE_LIMIT_MAX_ITEMS" = STORAGE_LIMIT_MAX_ITEMS, + "STORAGE_LIMIT_MAX_W_CLASS" = STORAGE_LIMIT_MAX_W_CLASS, + "STORAGE_LIMIT_COMBINED_W_CLASS" = STORAGE_LIMIT_COMBINED_W_CLASS, + "STORAGE_LIMIT_VOLUME" = STORAGE_LIMIT_VOLUME ) )) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index fb8863ebe7..bcf35859c3 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -50,3 +50,5 @@ GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area) GLOBAL_LIST_EMPTY(all_abstract_markers) GLOBAL_LIST_EMPTY(stationroom_landmarks) //List of all spawns for stationrooms + +GLOBAL_LIST_EMPTY(holodeck_areas_prototypes) //List of holodeck area prototypes per holodeck computer type \ No newline at end of file diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 490f0aa0f0..328e008f10 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -367,7 +367,7 @@ blood_display.hud = src infodisplay += blood_display - vamprank_display = new /obj/screen/bloodsucker/rank_counter // Vampire Rank + vamprank_display = new /obj/screen/bloodsucker/rank_counter // Bloodsucker Rank vamprank_display.hud = src infodisplay += vamprank_display diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index f5eb8535a5..4ed286eb08 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -210,20 +210,6 @@ user.swap_hand(held_index) return TRUE -/obj/screen/close - name = "close" - layer = ABOVE_HUD_LAYER - plane = ABOVE_HUD_PLANE - icon_state = "backpack_close" - -/obj/screen/close/Initialize(mapload, new_master) - . = ..() - master = new_master - -/obj/screen/close/Click() - var/datum/component/storage/S = master - S.hide_from(usr) - return TRUE /obj/screen/drop name = "drop" @@ -406,30 +392,6 @@ else icon_state = "act_rest0" -/obj/screen/storage - name = "storage" - icon_state = "block" - screen_loc = "7,7 to 10,8" - layer = HUD_LAYER - plane = HUD_PLANE - -/obj/screen/storage/Initialize(mapload, new_master) - . = ..() - master = new_master - -/obj/screen/storage/Click(location, control, params) - if(world.time <= usr.next_move) - return TRUE - if(usr.incapacitated()) - return TRUE - if (ismecha(usr.loc)) // stops inventory actions in a mech - return TRUE - if(master) - var/obj/item/I = usr.get_active_held_item() - if(I) - master.attackby(null, I, usr, params) - return TRUE - /obj/screen/throw_catch name = "throw/catch" icon = 'icons/mob/screen_midnight.dmi' diff --git a/code/_onclick/hud/screen_objects/storage.dm b/code/_onclick/hud/screen_objects/storage.dm new file mode 100644 index 0000000000..db287565f2 --- /dev/null +++ b/code/_onclick/hud/screen_objects/storage.dm @@ -0,0 +1,110 @@ +/obj/screen/storage + name = "storage" + var/insertion_click = FALSE + +/obj/screen/storage/Initialize(mapload, new_master) + . = ..() + master = new_master + +/obj/screen/storage/Click(location, control, params) + if(!insertion_click) + return ..() + if(world.time <= usr.next_move) + return TRUE + if(usr.incapacitated()) + return TRUE + if (ismecha(usr.loc)) // stops inventory actions in a mech + return TRUE + if(master) + var/obj/item/I = usr.get_active_held_item() + if(I) + master.attackby(null, I, usr, params) + return TRUE + +/obj/screen/storage/boxes + name = "storage" + icon_state = "block" + screen_loc = "7,7 to 10,8" + layer = HUD_LAYER + plane = HUD_PLANE + insertion_click = TRUE + +/obj/screen/storage/close + name = "close" + layer = ABOVE_HUD_LAYER + plane = ABOVE_HUD_PLANE + icon_state = "backpack_close" + +/obj/screen/storage/close/Click() + var/datum/component/storage/S = master + S.close(usr) + return TRUE + +/obj/screen/storage/left + icon_state = "storage_start" + insertion_click = TRUE + +/obj/screen/storage/right + icon_state = "storage_end" + insertion_click = TRUE + +/obj/screen/storage/continuous + icon_state = "storage_continue" + insertion_click = TRUE + +/obj/screen/storage/volumetric_box + icon_state = "stored_continue" + var/obj/item/our_item + +/obj/screen/storage/volumetric_box/Initialize(mapload, new_master, our_item) + src.our_item = our_item + return ..() + +/obj/screen/storage/volumetric_box/Destroy() + our_item = null + return ..() + +/obj/screen/storage/volumetric_box/Click(location, control, params) + return our_item.Click(location, control, params) + +/obj/screen/storage/volumetric_box/center + icon_state = "stored_continue" + var/obj/screen/storage/stored_left/left + var/obj/screen/storage/stored_right/right + var/pixel_size + +/obj/screen/storage/volumetric_box/center/Initialize(mapload, new_master, our_item) + left = new(null, src, our_item) + right = new(null, src, our_item) + return ..() + +/obj/screen/storage/volumetric_box/center/Destroy() + QDEL_NULL(left) + QDEL_NULL(right) + return ..() + +/obj/screen/storage/volumetric_box/center/proc/on_screen_objects() + return list(src, left, right) + +/** + * Sets the size of this box screen object and regenerates its left/right borders. This includes the actual border's size! + */ +/obj/screen/storage/volumetric_box/center/proc/set_pixel_size(pixels) + if(pixel_size == pixels) + return + pixel_size = pixels + cut_overlays() + //our icon size is 32 pixels. + transform = matrix((pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE, 0, 0, 0, 1, 0) + left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + add_overlay(left) + add_overlay(right) + +/obj/screen/storage/stored_left + icon_state = "stored_start" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM // Yes I know RESET_TRANSFORM is in APPEARANCE_UI but we're hard-asserting this incase someone changes it. + +/obj/screen/storage/stored_right + icon_state = "stored_end" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index f846c9c79e..b0e1d39d9a 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -131,7 +131,7 @@ I.do_stagger_action(src, user) if(I.force) apply_damage(totitemdamage, I.damtype) //CIT CHANGE - replaces I.force with totitemdamage - if(I.damtype == BRUTE && !HAS_TRAIT(src, TRAIT_NOMARROW)) + if(I.damtype == BRUTE) if(prob(33)) I.add_mob_blood(src) var/turf/location = get_turf(src) diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index f253bc543d..f11093cba7 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -449,3 +449,27 @@ key_mode = KEY_MODE_TEXT value_mode = VALUE_MODE_FLAG config_entry_value = list(GEN_VISIBLE_NO_CLOTHES, GEN_VISIBLE_NO_UNDIES, GEN_VISIBLE_NEVER) //refer to cit_helpers for all toggles. + +//Body size configs, the feature will be disabled if both min and max have the same value. +/datum/config_entry/number/body_size_min + config_entry_value = RESIZE_DEFAULT_SIZE + min_val = 0.1 //to avoid issues with zeros and negative values. + max_val = RESIZE_DEFAULT_SIZE + +/datum/config_entry/number/body_size_max + config_entry_value = RESIZE_DEFAULT_SIZE + min_val = RESIZE_DEFAULT_SIZE + +//Pun-Pun movement slowdown given to characters with a body size smaller than this value, +//to compensate for their smaller hitbox. +//To disable, just make sure the value is lower than 'body_size_min' +/datum/config_entry/number/threshold_body_size_slowdown + config_entry_value = RESIZE_DEFAULT_SIZE * 0.85 + min_val = 0 + max_val = RESIZE_DEFAULT_SIZE + +//multiplicative slowdown multiplier. See 'dna.update_body_size' for the operation. +//doesn't apply to floating or crawling mobs +/datum/config_entry/number/body_size_slowdown_multiplier + config_entry_value = 0.25 + min_val = 0.1 //To encourage folks to disable the slowdown through the above config instead. diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm index 8b068e5d67..3243a8d8c8 100644 --- a/code/controllers/subsystem/dcs.dm +++ b/code/controllers/subsystem/dcs.dm @@ -38,11 +38,17 @@ PROCESSING_SUBSYSTEM_DEF(dcs) if(istext(key)) value = arguments[key] if(!(istext(key) || isnum(key))) - key = REF(key) + if(islist(key)) // CITADEL EDIT + key = deep_list2params(key) + else + key = REF(key) key = "[key]" // Key is stringified so numbers dont break things if(!isnull(value)) if(!(istext(value) || isnum(value))) - value = REF(value) + if(islist(value)) // CITADEL EDIT + value = deep_list2params(value) + else + value = REF(value) named_arguments["[key]"] = value else fullid += "[key]" diff --git a/code/controllers/subsystem/fail2topic.dm b/code/controllers/subsystem/fail2topic.dm index 02e7bc7aab..78c4807c3f 100644 --- a/code/controllers/subsystem/fail2topic.dm +++ b/code/controllers/subsystem/fail2topic.dm @@ -21,9 +21,6 @@ SUBSYSTEM_DEF(fail2topic) DropFirewallRule() // Clear the old bans if any still remain - if (world.system_type == UNIX && enabled) - enabled = FALSE - subsystem_log("DISABLED - UNIX systems are not supported.") if(!enabled) flags |= SS_NO_FIRE can_fire = FALSE @@ -90,7 +87,10 @@ SUBSYSTEM_DEF(fail2topic) fail_counts -= ip rate_limiting -= ip - . = shell("netsh advfirewall firewall add rule name=\"[rule_name]\" dir=in interface=any action=block remoteip=[ip]") + if (world.system_type == UNIX) + . = shell("iptables -A [rule_name] -s [ip] -j DROP") + else + . = shell("netsh advfirewall firewall add rule name=\"[rule_name]\" dir=in interface=any action=block remoteip=[ip]") if (.) subsystem_log("Failed to ban [ip]. Exit code: [.].") @@ -105,7 +105,10 @@ SUBSYSTEM_DEF(fail2topic) active_bans = list() - . = shell("netsh advfirewall firewall delete rule name=\"[rule_name]\"") + if (world.system_type == UNIX) + . = shell("iptables -F [rule_name]") //Let's just assume that folks running linux are smart enough to have a dedicated chain configured for this. + else + . = shell("netsh advfirewall firewall delete rule name=\"[rule_name]\"") if (.) subsystem_log("Failed to drop firewall rule. Exit code: [.].") diff --git a/code/controllers/subsystem/processing/circuit.dm b/code/controllers/subsystem/processing/circuit.dm index 880e7a16a8..4fdc9ad806 100644 --- a/code/controllers/subsystem/processing/circuit.dm +++ b/code/controllers/subsystem/processing/circuit.dm @@ -86,7 +86,6 @@ PROCESSING_SUBSYSTEM_DEF(circuit) circuit_fabricator_recipe_list["Tools"] = list( /obj/item/integrated_electronics/wirer, /obj/item/integrated_electronics/debugger, - /obj/item/integrated_electronics/analyzer, /obj/item/integrated_electronics/detailer, /obj/item/card/data, /obj/item/card/data/full_color, diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm index 7d72951278..a202afd905 100644 --- a/code/controllers/subsystem/vote.dm +++ b/code/controllers/subsystem/vote.dm @@ -763,7 +763,7 @@ SUBSYSTEM_DEF(vote) remove_from_client() Remove(owner) -/datum/action/vote/IsAvailable() +/datum/action/vote/IsAvailable(silent = FALSE) return 1 /datum/action/vote/proc/remove_from_client() diff --git a/code/datums/action.dm b/code/datums/action.dm index 6c08a33f33..f2f93ac40d 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -6,13 +6,15 @@ /datum/action var/name = "Generic Action" var/desc = null - var/obj/target = null + var/atom/target = null var/check_flags = 0 var/required_mobility_flags = MOBILITY_USE var/processing = FALSE var/obj/screen/movable/action_button/button = null var/buttontooltipstyle = "" var/transparent_when_unavailable = TRUE + var/use_target_appearance = FALSE + var/list/target_appearance_matrix //if set, will be used to transform the target button appearance as an arglist. var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon @@ -88,14 +90,14 @@ /datum/action/proc/Trigger() if(!IsAvailable()) return FALSE - if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, src) & COMPONENT_ACTION_BLOCK_TRIGGER) + if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, target) & COMPONENT_ACTION_BLOCK_TRIGGER) return FALSE return TRUE /datum/action/proc/Process() return -/datum/action/proc/IsAvailable() +/datum/action/proc/IsAvailable(silent = FALSE) if(!owner) return FALSE var/mob/living/L = owner @@ -116,29 +118,42 @@ return TRUE /datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE) - if(button) - if(!status_only) - button.name = name - button.desc = desc - if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND) - var/list/settings = owner.hud_used.get_action_buttons_icons() - if(button.icon != settings["bg_icon"]) - button.icon = settings["bg_icon"] - if(button.icon_state != settings["bg_state"]) - button.icon_state = settings["bg_state"] - else - if(button.icon != button_icon) - button.icon = button_icon - if(button.icon_state != background_icon_state) - button.icon_state = background_icon_state + if(!button) + return + if(!status_only) + button.name = name + button.desc = desc + if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND) + var/list/settings = owner.hud_used.get_action_buttons_icons() + if(button.icon != settings["bg_icon"]) + button.icon = settings["bg_icon"] + if(button.icon_state != settings["bg_state"]) + button.icon_state = settings["bg_state"] + else + if(button.icon != button_icon) + button.icon = button_icon + if(button.icon_state != background_icon_state) + button.icon_state = background_icon_state + if(!use_target_appearance) ApplyIcon(button, force) - if(!IsAvailable()) - button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0) - else - button.color = rgb(255,255,255,255) - return 1 + else if(target && button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid. + var/mutable_appearance/M = new(target) + M.layer = FLOAT_LAYER + M.plane = FLOAT_PLANE + if(target_appearance_matrix) + var/list/L = target_appearance_matrix + M.transform = matrix(L[1], L[2], L[3], L[4], L[5], L[6]) + button.cut_overlays() + button.add_overlay(M) + button.appearance_cache = target.appearance + + if(!IsAvailable(TRUE)) + button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0) + else + button.color = rgb(255,255,255,255) + return 1 /datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE) if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force)) @@ -165,6 +180,7 @@ /datum/action/item_action check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS button_icon_state = null + use_target_appearance = TRUE // If you want to override the normal icon being the item // then change this to an icon state @@ -188,23 +204,6 @@ I.ui_action_click(owner, src) return 1 -/datum/action/item_action/ApplyIcon(obj/screen/movable/action_button/current_button, force) - if(button_icon && button_icon_state) - // If set, use the custom icon that we set instead - // of the item appearence - ..() - else if(target && current_button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid. - var/obj/item/I = target - var/old_layer = I.layer - var/old_plane = I.plane - I.layer = FLOAT_LAYER //AAAH - I.plane = FLOAT_PLANE //^ what that guy said - current_button.cut_overlays() - current_button.add_overlay(I) - I.layer = old_layer - I.plane = old_plane - current_button.appearance_cache = I.appearance - /datum/action/item_action/toggle_light name = "Toggle Light" @@ -308,7 +307,7 @@ icon_icon = 'icons/mob/actions/actions_items.dmi' button_icon_state = "vortex_recall" -/datum/action/item_action/vortex_recall/IsAvailable() +/datum/action/item_action/vortex_recall/IsAvailable(silent = FALSE) if(istype(target, /obj/item/hierophant_club)) var/obj/item/hierophant_club/H = target if(H.teleporting) @@ -320,7 +319,7 @@ background_icon_state = "bg_clock" buttontooltipstyle = "clockcult" -/datum/action/item_action/clock/IsAvailable() +/datum/action/item_action/clock/IsAvailable(silent = FALSE) if(!is_servant_of_ratvar(owner)) return 0 return ..() @@ -329,7 +328,7 @@ name = "Create Judicial Marker" desc = "Allows you to create a stunning Judicial Marker at any location in view. Click again to disable." -/datum/action/item_action/clock/toggle_visor/IsAvailable() +/datum/action/item_action/clock/toggle_visor/IsAvailable(silent = FALSE) if(!is_servant_of_ratvar(owner)) return 0 if(istype(target, /obj/item/clothing/glasses/judicial_visor)) @@ -408,7 +407,7 @@ /datum/action/item_action/jetpack_stabilization name = "Toggle Jetpack Stabilization" -/datum/action/item_action/jetpack_stabilization/IsAvailable() +/datum/action/item_action/jetpack_stabilization/IsAvailable(silent = FALSE) var/obj/item/tank/jetpack/J = target if(!istype(J) || !J.on) return 0 @@ -465,7 +464,7 @@ /datum/action/item_action/organ_action check_flags = AB_CHECK_CONSCIOUS -/datum/action/item_action/organ_action/IsAvailable() +/datum/action/item_action/organ_action/IsAvailable(silent = FALSE) var/obj/item/organ/I = target if(!I.owner) return 0 @@ -634,32 +633,32 @@ return FALSE if(target) var/obj/effect/proc_holder/S = target - S.Click() + S.Trigger(usr) return TRUE -/datum/action/spell_action/IsAvailable() +/datum/action/spell_action/IsAvailable(silent = FALSE) if(!target) return FALSE return TRUE /datum/action/spell_action/spell -/datum/action/spell_action/spell/IsAvailable() +/datum/action/spell_action/spell/IsAvailable(silent = FALSE) if(!target) return FALSE var/obj/effect/proc_holder/spell/S = target if(owner) - return S.can_cast(owner, FALSE, TRUE) + return S.can_cast(owner, FALSE, silent) return FALSE /datum/action/spell_action/alien -/datum/action/spell_action/alien/IsAvailable() +/datum/action/spell_action/alien/IsAvailable(silent = FALSE) if(!target) return FALSE var/obj/effect/proc_holder/alien/ab = target if(owner) - return ab.cost_check(ab.check_turf,owner,1) + return ab.cost_check(ab.check_turf,owner,silent) return FALSE @@ -701,7 +700,7 @@ button.maptext_width = 24 button.maptext_height = 12 -/datum/action/cooldown/IsAvailable() +/datum/action/cooldown/IsAvailable(silent = FALSE) return next_use_time <= world.time /datum/action/cooldown/proc/StartCooldown() diff --git a/code/datums/components/crafting/recipes/recipes_clothing.dm b/code/datums/components/crafting/recipes/recipes_clothing.dm index ba47b64b97..b9e3c379b4 100644 --- a/code/datums/components/crafting/recipes/recipes_clothing.dm +++ b/code/datums/components/crafting/recipes/recipes_clothing.dm @@ -294,3 +294,12 @@ /obj/item/bedsheet/cosmos = 1) time = 60 category = CAT_CLOTHING + + +/datum/crafting_recipe/garlic_necklace + name = "Garlic Necklace" + result = /obj/item/clothing/neck/garlic_necklace + reqs = list(/obj/item/reagent_containers/food/snacks/grown/garlic = 15, + /obj/item/stack/cable_coil = 10) + time = 100 //Takes awhile to put all the garlics on the coil and knot it. + category = CAT_CLOTHING diff --git a/code/datums/components/phantomthief.dm b/code/datums/components/phantomthief.dm index ede222d001..57ab75f7a3 100644 --- a/code/datums/components/phantomthief.dm +++ b/code/datums/components/phantomthief.dm @@ -1,8 +1,8 @@ //This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack. /datum/component/wearertargeting/phantomthief - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS - signals = list(COMSIG_LIVING_COMBAT_ENABLED) + dupe_mode = COMPONENT_DUPE_ALLOWED + signals = list(COMSIG_LIVING_COMBAT_ENABLED, COMSIG_LIVING_COMBAT_DISABLED) proctype = .proc/handlefilterstuff var/filter_x var/filter_y @@ -19,8 +19,8 @@ filter_color = _color valid_slots = _valid_slots -/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(datum/source, mob/user, combatmodestate) - if(!combatmodestate) +/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(mob/living/user, was_forced = FALSE) + if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE)) user.remove_filter("phantomthief") else user.add_filter("phantomthief", 4, list(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, color = filter_color)) diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm index 4c8f1b4c97..e044a59668 100644 --- a/code/datums/components/storage/concrete/_concrete.dm +++ b/code/datums/components/storage/concrete/_concrete.dm @@ -60,7 +60,7 @@ _contents_limbo = null if(_user_limbo) for(var/i in _user_limbo) - show_to(i) + ui_show(i) _user_limbo = null /datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE) diff --git a/code/datums/components/storage/concrete/emergency.dm b/code/datums/components/storage/concrete/emergency.dm index 348821a913..faaeada13d 100644 --- a/code/datums/components/storage/concrete/emergency.dm +++ b/code/datums/components/storage/concrete/emergency.dm @@ -18,7 +18,7 @@ return . = COMPONENT_NO_ATTACK_HAND if(!check_locked(source, user, TRUE)) - show_to(user) + ui_show(user) A.do_jiggle() if(rustle_sound) playsound(A, "rustle", 50, 1, -5) diff --git a/code/datums/components/storage/concrete/rped.dm b/code/datums/components/storage/concrete/rped.dm index 2f95466238..d919828e8e 100644 --- a/code/datums/components/storage/concrete/rped.dm +++ b/code/datums/components/storage/concrete/rped.dm @@ -3,6 +3,7 @@ allow_quick_gather = TRUE allow_quick_empty = TRUE click_gather = TRUE + storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = 100 max_items = 100 diff --git a/code/datums/components/storage/concrete/stack.dm b/code/datums/components/storage/concrete/stack.dm index 1f0c44c650..a3f1e526a0 100644 --- a/code/datums/components/storage/concrete/stack.dm +++ b/code/datums/components/storage/concrete/stack.dm @@ -1,6 +1,7 @@ //Stack-only storage. /datum/component/storage/concrete/stack display_numerical_stacking = TRUE + storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT var/max_combined_stack_amount = 300 max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = WEIGHT_CLASS_NORMAL * 14 diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index ea72a8a6dd..4100942fec 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -21,9 +21,16 @@ var/locked = FALSE //when locked nothing can see inside or use it. - var/max_w_class = WEIGHT_CLASS_SMALL //max size of objects that will fit. - var/max_combined_w_class = 14 //max combined sizes of objects that will fit. - var/max_items = 7 //max number of objects that will fit. + /// Storage flags, including what kinds of limiters we use for how many items we can hold + var/storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT + /// Max w_class we can hold. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS] and [STORAGE_LIMIT_VOLUME] + var/max_w_class = WEIGHT_CLASS_SMALL + /// Max combined w_class. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS] + var/max_combined_w_class = WEIGHT_CLASS_SMALL * 7 + /// Max items we can hold. Applies to [STORAGE_LIMIT_MAX_ITEMS] + var/max_items = 7 + /// Max volume we can hold. Applies to [STORAGE_LIMIT_VOLUME]. Auto scaled on New() if unset. + var/max_volume var/emp_shielded = FALSE @@ -39,8 +46,17 @@ var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number. - var/obj/screen/storage/boxes //storage display object - var/obj/screen/close/closer //close button object + /// "legacy"/default view mode's storage "boxes" + var/obj/screen/storage/boxes/ui_boxes + /// New volumetric storage display mode's left side + var/obj/screen/storage/left/ui_left + /// New volumetric storage display mode's center 'blocks' + var/obj/screen/storage/continuous/ui_continuous + /// The close button, used in all modes. Frames right side in volumetric mode. + var/obj/screen/storage/close/ui_close + /// Associative list of list(item = screen object) for volumetric storage item screen blocks + var/list/ui_item_blocks + var/current_maxscreensize var/allow_big_nesting = FALSE //allow storage objects of the same or greater size. @@ -68,9 +84,6 @@ return COMPONENT_INCOMPATIBLE if(master) change_master(master) - boxes = new(null, src) - closer = new(null, src) - orient2hud() RegisterSignal(parent, COMSIG_CONTAINS_STORAGE, .proc/on_check) RegisterSignal(parent, COMSIG_IS_STORAGE_LOCKED, .proc/check_locked) @@ -111,8 +124,15 @@ /datum/component/storage/Destroy() close_all() - QDEL_NULL(boxes) - QDEL_NULL(closer) + QDEL_NULL(ui_boxes) + QDEL_NULL(ui_close) + QDEL_NULL(ui_continuous) + QDEL_NULL(ui_left) + // DO NOT USE QDEL_LIST_ASSOC. + if(ui_item_blocks) + for(var/i in ui_item_blocks) + qdel(ui_item_blocks[i]) //qdel the screen object not the item + ui_item_blocks.Cut() LAZYCLEARLIST(is_using) return ..() @@ -286,7 +306,7 @@ if(!_target) _target = get_turf(parent) if(usr) - hide_from(usr) + ui_hide(usr) var/list/contents = contents() var/atom/real_location = real_location() for(var/obj/item/I in contents) @@ -300,106 +320,8 @@ if(check_locked()) close_all() -/datum/component/storage/proc/_process_numerical_display() - . = list() - for(var/obj/item/I in accessible_items()) - if(QDELETED(I)) - continue - if(!.[I.type]) - .[I.type] = new /datum/numbered_display(I, 1) - else - var/datum/numbered_display/ND = .[I.type] - ND.number++ - . = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE) - -//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing. -/datum/component/storage/proc/orient2hud(mob/user, maxcolumns) - var/list/accessible_contents = accessible_items() - var/adjusted_contents = length(accessible_contents) - - //Numbered contents display - var/list/datum/numbered_display/numbered_contents - if(display_numerical_stacking) - numbered_contents = _process_numerical_display() - adjusted_contents = numbered_contents.len - - var/columns = CLAMP(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) - var/rows = CLAMP(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) - standard_orient_objs(rows, columns, numbered_contents) - -//This proc draws out the inventory and places the items on it. It uses the standard position. -/datum/component/storage/proc/standard_orient_objs(rows, cols, list/obj/item/numerical_display_contents) - boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" - var/cx = screen_start_x - var/cy = screen_start_y - if(islist(numerical_display_contents)) - for(var/type in numerical_display_contents) - var/datum/numbered_display/ND = numerical_display_contents[type] - ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE - ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" - ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" - ND.sample_object.layer = ABOVE_HUD_LAYER - ND.sample_object.plane = ABOVE_HUD_PLANE - cx++ - if(cx - screen_start_x >= cols) - cx = screen_start_x - cy++ - if(cy - screen_start_y >= rows) - break - else - for(var/obj/O in accessible_items()) - if(QDELETED(O)) - continue - O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" - O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" - O.maptext = "" - O.layer = ABOVE_HUD_LAYER - O.plane = ABOVE_HUD_PLANE - cx++ - if(cx - screen_start_x >= cols) - cx = screen_start_x - cy++ - if(cy - screen_start_y >= rows) - break - closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]" - -/datum/component/storage/proc/show_to(mob/M, set_screen_size = TRUE) - if(!M.client) - return FALSE - var/list/cview = getviewsize(M.client.view) - var/maxallowedscreensize = cview[1]-8 - if(set_screen_size) - current_maxscreensize = maxallowedscreensize - else if(current_maxscreensize) - maxallowedscreensize = current_maxscreensize - if(M.active_storage != src && (M.stat == CONSCIOUS)) - for(var/obj/item/I in accessible_items()) - if(I.on_found(M)) - return FALSE - if(M.active_storage) - M.active_storage.hide_from(M) - orient2hud(M, (isliving(M) ? maxallowedscreensize : 7)) - M.client.screen |= boxes - M.client.screen |= closer - M.client.screen |= accessible_items() - M.active_storage = src - LAZYOR(is_using, M) - return TRUE - -/datum/component/storage/proc/hide_from(mob/M) - if(!M.client) - return TRUE - var/atom/real_location = real_location() - M.client.screen -= boxes - M.client.screen -= closer - M.client.screen -= real_location.contents - if(M.active_storage == src) - M.active_storage = null - LAZYREMOVE(is_using, M) - return TRUE - /datum/component/storage/proc/close(mob/M) - hide_from(M) + ui_hide(M) /datum/component/storage/proc/close_all() . = FALSE @@ -418,25 +340,6 @@ var/datum/component/storage/concrete/master = master() master.emp_act(source, severity) -//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. -//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. -/datum/component/storage/proc/orient_objs(tx, ty, mx, my) - var/atom/real_location = real_location() - var/cx = tx - var/cy = ty - boxes.screen_loc = "[tx]:,[ty] to [mx],[my]" - for(var/obj/O in real_location) - if(QDELETED(O)) - continue - O.screen_loc = "[cx],[cy]" - O.layer = ABOVE_HUD_LAYER - O.plane = ABOVE_HUD_PLANE - cx++ - if(cx > mx) - cx = tx - cy-- - closer.screen_loc = "[mx+1],[my]" - //Resets something that is being removed from storage. /datum/component/storage/proc/_removal_reset(atom/movable/thing) if(!istype(thing)) @@ -448,6 +351,9 @@ /datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing) _removal_reset(thing) + if(LAZYACCESS(ui_item_blocks, thing)) + qdel(ui_item_blocks[thing]) + ui_item_blocks -= thing refresh_mob_views() //Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted @@ -462,7 +368,7 @@ /datum/component/storage/proc/refresh_mob_views() var/list/seeing = can_see_contents() for(var/i in seeing) - show_to(i) + ui_show(i) return TRUE /datum/component/storage/proc/can_see_contents() @@ -559,7 +465,7 @@ A.add_fingerprint(M) if(!force && (check_locked(null, M) || !M.CanReach(parent, view_only = TRUE))) return FALSE - show_to(M, !ghost) + ui_show(M, !ghost) /datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M) if(isitem(O)) @@ -587,10 +493,6 @@ if(M && !stop_messages) host.add_fingerprint(M) return FALSE - if(real_location.contents.len >= max_items) - if(!stop_messages) - to_chat(M, "[host] is full, make some space!") - return FALSE //Storage item is full if(length(can_hold)) if(!is_type_in_typecache(I, can_hold)) if(!stop_messages) @@ -600,17 +502,34 @@ if(!stop_messages) to_chat(M, "[host] cannot hold [I]!") return FALSE - if(I.w_class > max_w_class) - if(!stop_messages) - to_chat(M, "[I] is too big for [host]!") - return FALSE - var/sum_w_class = I.w_class - for(var/obj/item/_I in real_location) - sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it. - if(sum_w_class > max_combined_w_class) - if(!stop_messages) - to_chat(M, "[I] won't fit in [host], make some space!") - return FALSE + // STORAGE LIMITS + if(storage_flags & STORAGE_LIMIT_MAX_ITEMS) + if(real_location.contents.len >= max_items) + if(!stop_messages) + to_chat(M, "[host] has too many things in it, make some space!") + return FALSE //Storage item is full + if(storage_flags & STORAGE_LIMIT_MAX_W_CLASS) + if(I.w_class > max_w_class) + if(!stop_messages) + to_chat(M, "[I] is too long for [host]!") + return FALSE + if(storage_flags & STORAGE_LIMIT_COMBINED_W_CLASS) + var/sum_w_class = I.w_class + for(var/obj/item/_I in real_location) + sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it. + if(sum_w_class > max_combined_w_class) + if(!stop_messages) + to_chat(M, "[I] won't fit in [host], make some space!") + return FALSE + if(storage_flags & STORAGE_LIMIT_VOLUME) + var/sum_volume = I.get_w_volume() + for(var/obj/item/_I in real_location) + sum_volume += _I.get_w_volume() + if(sum_volume > get_max_volume()) + if(!stop_messages) + to_chat(M, "[I] is too spacious to fit in [host], make some space!") + return FALSE + ///////////////// if(isitem(host)) var/obj/item/IP = host var/datum/component/storage/STR_I = I.GetComponent(/datum/component/storage) @@ -742,7 +661,7 @@ if(A.loc == user) . = COMPONENT_NO_ATTACK_HAND if(!check_locked(source, user, TRUE)) - show_to(user) + ui_show(user) A.do_jiggle() /datum/component/storage/proc/signal_on_pickup(datum/source, mob/user) @@ -761,7 +680,7 @@ return do_quick_empty(loctarget) /datum/component/storage/proc/signal_hide_attempt(datum/source, mob/target) - return hide_from(target) + return ui_hide(target) /datum/component/storage/proc/on_alt_click(datum/source, mob/user) if(!isliving(user) || !user.CanReach(parent)) @@ -790,7 +709,7 @@ user.visible_message("[user] draws [I] from [parent]!", "You draw [I] from [parent].") return TRUE -/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source) +/datum/component/storage/proc/action_trigger(datum/action/source, obj/target) gather_mode_switch(source.owner) return COMPONENT_ACTION_BLOCK_TRIGGER @@ -803,3 +722,9 @@ to_chat(user, "[parent] now picks up all items in a tile at once.") if(COLLECT_ONE) to_chat(user, "[parent] now picks up one item at a time.") + +/** + * Gets our max volume + */ +/datum/component/storage/proc/get_max_volume() + return max_volume || AUTO_SCALE_STORAGE_VOLUME(max_w_class, max_combined_w_class) diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm new file mode 100644 index 0000000000..c1c049dfd3 --- /dev/null +++ b/code/datums/components/storage/ui.dm @@ -0,0 +1,293 @@ +/** + * Generates a list of numbered_display datums for the numerical display system. + */ +/datum/component/storage/proc/_process_numerical_display() + . = list() + for(var/obj/item/I in accessible_items()) + if(QDELETED(I)) + continue + if(!.[I.type]) + .[I.type] = new /datum/numbered_display(I, 1) + else + var/datum/numbered_display/ND = .[I.type] + ND.number++ + . = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE) + +/** + * Orients all objects in legacy mode, and returns the objects to show to the user. + */ +/datum/component/storage/proc/orient2hud_legacy(mob/user, maxcolumns) + . = list() + var/list/accessible_contents = accessible_items() + var/adjusted_contents = length(accessible_contents) + + //Numbered contents display + var/list/datum/numbered_display/numbered_contents + if(display_numerical_stacking) + numbered_contents = _process_numerical_display() + adjusted_contents = numbered_contents.len + + var/columns = CLAMP(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) + var/rows = CLAMP(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) + + // First, boxes. + ui_boxes = get_ui_boxes() + ui_boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+columns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_boxes + // Then, closer. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + columns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]" + . += ui_close + // Then orient the actual items. + var/cx = screen_start_x + var/cy = screen_start_y + if(islist(numbered_contents)) + for(var/type in numbered_contents) + var/datum/numbered_display/ND = numbered_contents[type] + ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE + ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" + ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" + ND.sample_object.layer = ABOVE_HUD_LAYER + ND.sample_object.plane = ABOVE_HUD_PLANE + . += ND.sample_object + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + else + for(var/obj/O in accessible_items()) + if(QDELETED(O)) + continue + O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" + O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" + O.maptext = "" + O.layer = ABOVE_HUD_LAYER + O.plane = ABOVE_HUD_PLANE + . += O + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + +/** + * Orients all objects in .. volumetric mode. Does not support numerical display! + */ +/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns) + . = list() + + // Generate ui_item_blocks for missing ones and render+orient. + var/list/atom/contents = accessible_items() + // our volume + var/our_volume = get_max_volume() + var/horizontal_pixels = (maxcolumns * world.icon_size) - (VOLUMETRIC_STORAGE_EDGE_PADDING * 2) + var/max_horizontal_pixels = horizontal_pixels * screen_max_rows + // sigh loopmania time + var/used = 0 + // define outside for performance + var/volume + var/list/volume_by_item = list() + var/list/percentage_by_item = list() + for(var/obj/item/I in contents) + volume = I.get_w_volume() + used += volume + volume_by_item[I] = volume + percentage_by_item[I] = volume / get_max_volume() + var/padding_pixels = ((length(percentage_by_item) - 1) * VOLUMETRIC_STORAGE_ITEM_PADDING) + VOLUMETRIC_STORAGE_EDGE_PADDING * 2 + var/min_pixels = (MINIMUM_PIXELS_PER_ITEM * length(percentage_by_item)) + padding_pixels + // do the check for fallback for when someone has too much gamer gear + if((min_pixels) > (max_horizontal_pixels + 4)) // 4 pixel grace zone + to_chat(user, "[parent] was showed to you in legacy mode due to your items overrunning the three row limit! Consider not carrying too much or bugging a maintainer to raise this limit!") + return orient2hud_legacy(user, maxcolumns) + // after this point we are sure we can somehow fit all items into our max number of rows. + + // determine rows + var/rows = CLAMP(CEILING(min_pixels / horizontal_pixels, 1), 1, screen_max_rows) + + var/overrun = FALSE + if(used > our_volume) + // congratulations we are now in overrun mode. everything will be crammed to minimum storage pixels. + to_chat(user, "[parent] rendered in overrun mode due to more items inside than the maximum volume supports.") + overrun = TRUE + + // how much we are using + var/using_horizontal_pixels = horizontal_pixels * rows + + // item padding + using_horizontal_pixels -= padding_pixels + + // define outside for marginal performance boost + var/obj/item/I + // start at this pixel from screen_start_x. + var/current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + var/row = 1 + + LAZYINITLIST(ui_item_blocks) + + for(var/i in percentage_by_item) + I = i + var/percent = percentage_by_item[I] + if(!ui_item_blocks[I]) + ui_item_blocks[I] = new /obj/screen/storage/volumetric_box/center(null, src, I) + var/obj/screen/storage/volumetric_box/center/B = ui_item_blocks[I] + var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM) + var/addrow = FALSE + if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1)) + pixels_to_use = horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING + addrow = TRUE + + // now that we have pixels_to_use, place our thing and add it to the returned list. + + B.screen_loc = I.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + VOLUMETRIC_STORAGE_ITEM_PADDING, 1)],[screen_start_y+row-1]:[screen_pixel_y]" + // add the used pixels to pixel after we place the object + current_pixel += pixels_to_use + VOLUMETRIC_STORAGE_ITEM_PADDING + + // set various things + B.set_pixel_size(pixels_to_use) + B.layer = VOLUMETRIC_STORAGE_BOX_LAYER + B.plane = VOLUMETRIC_STORAGE_BOX_PLANE + B.name = I.name + + I.mouse_opacity = MOUSE_OPACITY_ICON + I.maptext = "" + I.layer = VOLUMETRIC_STORAGE_ITEM_LAYER + I.plane = VOLUMETRIC_STORAGE_ITEM_PLANE + + // finally add our things. + . += B.on_screen_objects() + . += I + + // go up a row if needed + if(addrow) + row++ + current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + + // Then, continuous section. + ui_continuous = get_ui_continuous() + ui_continuous.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+maxcolumns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_continuous + // Then, left. + ui_left = get_ui_left() + ui_left.screen_loc = "[screen_start_x]:[screen_pixel_x - 2],[screen_start_y]:[screen_pixel_y] to [screen_start_x]:[screen_pixel_x - 2],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_left + // Then, closer, which is also our right element. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y + row - 1]:[screen_pixel_y]" + . += ui_close + +/** + * Shows our UI to a mob. + */ +/datum/component/storage/proc/ui_show(mob/M, set_screen_size = TRUE) + if(!M.client) + return FALSE + var/list/cview = getviewsize(M.client.view) + // in tiles + var/maxallowedscreensize = cview[1]-8 + if(set_screen_size) + current_maxscreensize = maxallowedscreensize + else if(current_maxscreensize) + maxallowedscreensize = current_maxscreensize + // we got screen size, register signal + RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_logout, override = TRUE) + if(M.active_storage != src) + if(M.active_storage) + M.active_storage.ui_hide(M) + M.active_storage = src + LAZYOR(is_using, M) + if(volumetric_ui()) + //new volumetric ui bay-style + M.client.screen |= orient2hud_volumetric(M, maxallowedscreensize) + else + //old ui + M.client.screen |= orient2hud_legacy(M, maxallowedscreensize) + return TRUE + +/** + * VV hooked to ensure no lingering screen objects. + */ +/datum/component/storage/vv_edit_var(var_name, var_value) + var/list/old + if(var_name == NAMEOF(src, storage_flags)) + old = is_using.Copy() + for(var/i in is_using) + ui_hide(i) + . = ..() + if(old) + for(var/i in old) + ui_show(i) + +/** + * Proc triggered by signal to ensure logging out clients don't linger. + */ +/datum/component/storage/proc/on_logout(datum/source, client/C) + ui_hide(source) + +/** + * Hides our UI from a mob + */ +/datum/component/storage/proc/ui_hide(mob/M) + if(!M.client) + return TRUE + UnregisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT) + M.client.screen -= list(ui_boxes, ui_close, ui_left, ui_continuous) + get_ui_item_objects_hide() + if(M.active_storage == src) + M.active_storage = null + LAZYREMOVE(is_using, M) + return TRUE + +/** + * Returns TRUE if we are using volumetric UI instead of box UI + */ +/datum/component/storage/proc/volumetric_ui() + var/atom/real_location = real_location() + return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking + +/** + * Gets the ui item objects to ui_hide. + */ +/datum/component/storage/proc/get_ui_item_objects_hide() + if(!volumetric_ui()) + var/atom/real_location = real_location() + return real_location.contents + else + . = list() + for(var/i in ui_item_blocks) + // get both the box and the item + . += ui_item_blocks[i] + . += i + +/** + * Gets our ui_boxes, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_boxes() + if(!ui_boxes) + ui_boxes = new(null, src) + return ui_boxes + +/** + * Gets our ui_left, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_left() + if(!ui_left) + ui_left = new(null, src) + return ui_left + +/** + * Gets our ui_close, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_close() + if(!ui_close) + ui_close = new(null, src) + return ui_close + +/** + * Gets our ui_continuous, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_continuous() + if(!ui_continuous) + ui_continuous = new(null, src) + return ui_continuous diff --git a/code/datums/components/virtual_reality.dm b/code/datums/components/virtual_reality.dm index 9239d4c565..56e06e3582 100644 --- a/code/datums/components/virtual_reality.dm +++ b/code/datums/components/virtual_reality.dm @@ -176,7 +176,7 @@ /** *The following procs simply acts as hooks for quit(), since components do not use callbacks anymore */ -/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source) +/datum/component/virtual_reality/proc/action_trigger(datum/action/source, obj/target) quit() return COMPONENT_ACTION_BLOCK_TRIGGER diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm index 8eda936bb7..c31139dcd7 100644 --- a/code/datums/dash_weapon.dm +++ b/code/datums/dash_weapon.dm @@ -19,7 +19,7 @@ dashing_item = dasher holder = user -/datum/action/innate/dash/IsAvailable() +/datum/action/innate/dash/IsAvailable(silent = FALSE) if(current_charges > 0) return TRUE else diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 2fffde8271..60e9382353 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -41,6 +41,7 @@ /datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0) if(!istype(destination)) return + var/old_size = destination.dna.features["body_size"] destination.dna.unique_enzymes = unique_enzymes destination.dna.uni_identity = uni_identity destination.dna.blood_type = blood_type @@ -56,6 +57,8 @@ if(transfer_SE) destination.dna.mutation_index = mutation_index + destination.dna.update_body_size(old_size) + SEND_SIGNAL(destination, COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, src, transfer_SE) /datum/dna/proc/copy_dna(datum/dna/new_dna) @@ -368,7 +371,9 @@ /mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures) if(newfeatures) + var/old_size = dna.features["body_size"] dna.features = newfeatures + dna.update_body_size(old_size) if(mrace) var/datum/species/newrace = new mrace.type @@ -644,3 +649,15 @@ gib() else set_species(/datum/species/dullahan) + +/datum/dna/proc/update_body_size(old_size) + if(!holder || features["body_size"] == old_size) + return + holder.resize = features["body_size"] / old_size + holder.update_transform() + var/danger = CONFIG_GET(number/threshold_body_size_slowdown) + if(features["body_size"] < danger) + var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier) + holder.add_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE, TRUE, 100, NONE, TRUE, slowdown, ALL, FLOATING|CRAWLING) + else if(old_size < danger) + holder.remove_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE) diff --git a/code/datums/elements/polychromic.dm b/code/datums/elements/polychromic.dm new file mode 100644 index 0000000000..1c438c86c5 --- /dev/null +++ b/code/datums/elements/polychromic.dm @@ -0,0 +1,187 @@ +#define POLYCHROMIC_ALTCLICK (1<<0) +#define POLYCHROMIC_ACTION (1<<1) +#define POLYCHROMIC_NO_HELD (1<<2) +#define POLYCHROMIC_NO_WORN (1<<3) + +/datum/element/polychromic + element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH + id_arg_index = 3 + var/overlays_states //A list or a number of states. In the latter case, the atom icon_state/item_state will be used followed by a number. + var/list/colors_by_atom = list() //list of color strings or mutable appearances, depending on the above variable. + var/icon_file + var/worn_file //used in place of items' held or mob overlay icons if present. + var/list/overlays_names //wrap numbers into text strings please. + var/list/actions_by_atom = list() + var/poly_flags + var/static/list/suits_with_helmet_typecache = typecacheof(list(/obj/item/clothing/suit/hooded, /obj/item/clothing/suit/space/hardsuit)) + var/list/helmet_by_suit = list() //because poly winter coats exist. + var/list/suit_by_helmet = list() //Idem. + +/datum/element/polychromic/Attach(datum/target, list/colors, states, _flags = POLYCHROMIC_ACTION|POLYCHROMIC_NO_HELD, _icon, _worn, list/names = list("Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary")) + . = ..() + var/make_appearances = islist(states) + var/states_len = make_appearances ? length(states) : states + var/names_len = length(names) + if(!states_len || !names_len || colors_by_atom[target] || !isatom(target)) + return ELEMENT_INCOMPATIBLE + var/atom/A = target + + overlays_states = states + icon_file = _icon + worn_file = _worn + poly_flags = _flags + + var/mut_icon = icon_file || A.icon + var/list/L = list() + for(var/I in 1 to states_len) + var/col = LAZYACCESS(colors, I) || "#FFFFFF" + L += make_appearances ? mutable_appearance(mut_icon, overlays_states[I], color = col) : col + colors_by_atom[A] = L + + RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays) + + if(_flags & POLYCHROMIC_ALTCLICK) + RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/on_examine) + RegisterSignal(A, COMSIG_CLICK_ALT, .proc/set_color) + + if(!overlays_names && names) //generate + overlays_names = names + var/diff = states_len - names_len + if(diff > 0) + for(var/i in 1 to diff) + overlays_names += "[names_len + i]°" + else if(diff < 0) + overlays_names.len += diff + + if(isitem(A)) + if(_flags & POLYCHROMIC_ACTION) + RegisterSignal(A, COMSIG_ITEM_EQUIPPED, .proc/grant_user_action) + RegisterSignal(A, COMSIG_ITEM_DROPPED, .proc/remove_user_action) + if(!(_flags & POLYCHROMIC_NO_WORN) || !(_flags & POLYCHROMIC_NO_HELD)) + A.AddElement(/datum/element/update_icon_updates_onmob) + RegisterSignal(A, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays) + if(suits_with_helmet_typecache[A.type]) + RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet) + else if(_flags & POLYCHROMIC_ACTION && ismob(A)) //in the event mob update icon procs are ever standarized. + var/datum/action/polychromic/P = new(A) + RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action) + actions_by_atom[A] = P + P.Grant(A) + + A.update_icon() //apply the overlays. + +/datum/element/polychromic/Detach(atom/A) + . = ..() + colors_by_atom -= A + var/datum/action/polychromic/P = actions_by_atom[A] + if(P) + actions_by_atom -= A + qdel(P) + UnregisterSignal(A, list(COMSIG_PARENT_EXAMINE, COMSIG_CLICK_ALT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_SUIT_MADE_HELMET)) + if(isitem(A)) + var/obj/item/clothing/head/H = helmet_by_suit[A] + if(H) + UnregisterSignal(H, list(COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_PARENT_QDELETING)) + helmet_by_suit -= A + suit_by_helmet -= H + colors_by_atom -= H + if(!QDELETED(H)) + H.update_icon() //removing the overlays + if(!(poly_flags & POLYCHROMIC_NO_WORN) || !(poly_flags & POLYCHROMIC_NO_HELD)) + A.RemoveElement(/datum/element/update_icon_updates_onmob) + if(!QDELETED(A) && ismob(A.loc)) + var/mob/M = A.loc + if(!(poly_flags & POLYCHROMIC_NO_HELD) && M.is_holding(A)) + M.update_inv_hands() + else if(!(poly_flags & POLYCHROMIC_NO_WORN)) + M.regenerate_icons() + if(!QDELETED(A)) + A.update_icon() //removing the overlays + +/datum/element/polychromic/proc/apply_overlays(atom/source, list/overlays) + var/list/L = colors_by_atom[source] + var/f_icon = icon_file || source.icon + if(isnum(overlays_states)) + for(var/i in 1 to overlays_states) + overlays += mutable_appearance(f_icon, "[source.icon_state]-[i]", color = L[i]) + else + overlays += colors_by_atom[source] + +/datum/element/polychromic/proc/apply_worn_overlays(obj/item/source, isinhands, icon, used_state, style_flags, list/overlays) + if(poly_flags & (isinhands ? POLYCHROMIC_NO_HELD : POLYCHROMIC_NO_WORN)) + return + var/f_icon = worn_file || icon + var/list/L = colors_by_atom[source] + + if(isnum(overlays_states)) + for(var/i in 1 to overlays_states) + overlays += mutable_appearance(f_icon, "[used_state]-[i]", color = L[i]) + else + for(var/i in 1 to length(overlays_states)) + var/mutable_appearance/M = L[i] + overlays += mutable_appearance(f_icon, overlays_states[i], color = M.color) + +/datum/element/polychromic/proc/set_color(atom/source, mob/user) + var/choice = input(user,"Polychromic options", "Recolor [source]") as null|anything in overlays_names + if(!choice || QDELETED(source) || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY)) + return + var/index = overlays_names.Find(choice) + var/list/L = colors_by_atom[source] + if(!L) // Ummmmmh. + return + var/mutable_appearance/M = L[index] + var/old_color = istype(M) ? M.color : M + var/ncolor = input(user, "Polychromic options", "Choose [choice] Color", old_color) as color|null + if(!ncolor || QDELETED(source) || !colors_by_atom[source] || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY)) + return + ncolor = sanitize_hexcolor(ncolor, 6, TRUE, old_color) + if(istype(M)) + M.color = ncolor + else + L[index] = ncolor + + source.update_icon() + return TRUE + +/datum/element/polychromic/proc/grant_user_action(atom/source, mob/user, slot) + if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED || slot == SLOT_HANDCUFFED || slot == SLOT_GENERC_DEXTROUS_STORAGE) + return + var/datum/action/polychromic/P = actions_by_atom[source] + if(!P) + P = new (source) + P.name = "Modify [source]'\s Colors" + actions_by_atom[source] = P + P.check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS + RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action) + P.Grant(user) + +/datum/element/polychromic/proc/remove_user_action(atom/source, mob/user) + var/datum/action/polychromic/P = actions_by_atom[source] + P?.Remove(user) + +/datum/element/polychromic/proc/activate_action(datum/action/source, atom/target) + set_color(target, source.owner) + +/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list) + examine_list += "Alt-click to recolor it." + +/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H) + suit_by_helmet[H] = source + helmet_by_suit[source] = H + colors_by_atom[H] = colors_by_atom[source] + RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays) + RegisterSignal(H, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays) + RegisterSignal(H, COMSIG_PARENT_QDELETING, .proc/unregister_helmet) + +/datum/element/polychromic/proc/unregister_helmet(atom/source) + var/obj/item/clothing/suit/S = suit_by_helmet[source] + suit_by_helmet -= source + helmet_by_suit -= S + colors_by_atom -= source + +/datum/action/polychromic + name = "Modify Polychromic Colors" + background_icon_state = "bg_polychromic" + use_target_appearance = TRUE + button_icon_state = null + target_appearance_matrix = list(0.8,0,0,0,0.8,0) diff --git a/code/datums/elements/spellcasting.dm b/code/datums/elements/spellcasting.dm index a917108bf1..877bcdbcd3 100644 --- a/code/datums/elements/spellcasting.dm +++ b/code/datums/elements/spellcasting.dm @@ -12,7 +12,7 @@ RegisterSignal(target, COMSIG_ITEM_EQUIPPED, .proc/on_equip) RegisterSignal(target, COMSIG_ITEM_DROPPED, .proc/on_drop) else if(ismob(target)) - RegisterSignal(target, COMSIG_MOB_SPELL_CAST_CHECK, .proc/on_cast) + RegisterSignal(target, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast) stacked_spellcasting_by_user[target]++ else return ELEMENT_INCOMPATIBLE @@ -21,24 +21,24 @@ /datum/element/spellcasting/Detach(datum/target) . = ..() - UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_MOB_SPELL_CAST_CHECK)) + UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_MOB_SPELL_CAN_CAST)) if(users_by_item[target]) var/mob/user = users_by_item[target] stacked_spellcasting_by_user[user]-- if(!stacked_spellcasting_by_user[user]) stacked_spellcasting_by_user -= user - UnregisterSignal(user, COMSIG_MOB_SPELL_CAST_CHECK) + UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST) else if(ismob(target)) stacked_spellcasting_by_user[target]-- if(!stacked_spellcasting_by_user[target]) stacked_spellcasting_by_user -= target /datum/element/spellcasting/proc/on_equip(datum/source, mob/equipper, slot) - if(!(slot in cast_slots)) + if(!(cast_slots & slotdefine2slotbit(slot))) return users_by_item[source] = equipper if(!stacked_spellcasting_by_user[equipper]) - RegisterSignal(equipper, COMSIG_MOB_SPELL_CAST_CHECK, .proc/on_cast) + RegisterSignal(equipper, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast) stacked_spellcasting_by_user[equipper]++ /datum/element/spellcasting/proc/on_drop(datum/source, mob/user) @@ -48,7 +48,7 @@ stacked_spellcasting_by_user[user]-- if(!stacked_spellcasting_by_user[user]) stacked_spellcasting_by_user -= user - UnregisterSignal(user, COMSIG_MOB_SPELL_CAST_CHECK) + UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST) /datum/element/spellcasting/proc/on_cast(mob/caster, obj/effect/proc_holder/spell) return cast_flags diff --git a/code/datums/elements/update_icon_updates_onmob.dm b/code/datums/elements/update_icon_updates_onmob.dm index ca0e8b1641..5c71547f62 100644 --- a/code/datums/elements/update_icon_updates_onmob.dm +++ b/code/datums/elements/update_icon_updates_onmob.dm @@ -5,7 +5,7 @@ . = ..() if(!istype(target, /obj/item)) return ELEMENT_INCOMPATIBLE - RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob) + RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob, override = TRUE) /datum/element/update_icon_updates_onmob/proc/update_onmob(obj/item/target) if(ismob(target.loc)) diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 6b0981665d..c46a03a986 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -128,7 +128,7 @@ // Can most things breathe? if(trace_gases) continue - if(A_gases[/datum/gas/oxygen] >= 16) + if(A_gases[/datum/gas/oxygen] <= 16) continue if(A_gases[/datum/gas/plasma]) continue diff --git a/code/game/area/areas/holodeck.dm b/code/game/area/areas/holodeck.dm index d32091f98b..75ed2b656c 100644 --- a/code/game/area/areas/holodeck.dm +++ b/code/game/area/areas/holodeck.dm @@ -6,6 +6,8 @@ hidden = TRUE var/obj/machinery/computer/holodeck/linked + var/list/compatible_holodeck_comps + var/abstract_type = /area/holodeck var/restricted = 0 // if true, program goes on emag list /* @@ -53,6 +55,8 @@ */ /area/holodeck/rec_center name = "\improper Recreational Holodeck" + compatible_holodeck_comps = list(/obj/machinery/computer/holodeck) + abstract_type = /area/holodeck/rec_center /area/holodeck/rec_center/offline name = "Holodeck - Offline" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 266d5b5bb5..44a891e24a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -584,11 +584,8 @@ stoplag(1) qdel(progress) to_chat(user, "You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.") - STR.orient2hud(user) - src_object.orient2hud(user) if(user.active_storage) //refresh the HUD to show the transfered contents - user.active_storage.close(user) - user.active_storage.show_to(user) + user.active_storage.ui_show(user) return TRUE /atom/proc/get_dumping_location(obj/item/storage/source,mob/user) diff --git a/code/game/gamemodes/bloodsucker/bloodsucker.dm b/code/game/gamemodes/bloodsucker/bloodsucker.dm index 9515d6063c..bb776d7bc0 100644 --- a/code/game/gamemodes/bloodsucker/bloodsucker.dm +++ b/code/game/gamemodes/bloodsucker/bloodsucker.dm @@ -9,8 +9,14 @@ var/list/vassal_allowed_antags = list(/datum/antagonist/brother, /datum/antagonist/traitor, /datum/antagonist/traitor/internal_affairs, /datum/antagonist/survivalist, \ /datum/antagonist/rev, /datum/antagonist/nukeop, /datum/antagonist/pirate, /datum/antagonist/cult, /datum/antagonist/abductee, /datum/antagonist/valentine, /datum/antagonist/heartbreaker,) // The antags you're allowed to be if turning Vassal. -/proc/isvamp(mob/living/M) - return istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/bloodsucker) + +/proc/AmBloodsucker(mob/living/M, falseIfInDisguise = FALSE) + if(!M.mind) + return FALSE + // No Datum + if(!M.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) + return FALSE + return TRUE /datum/game_mode/bloodsucker name = "bloodsucker" @@ -70,49 +76,27 @@ // Gamemode is all done being set up. We have all our Vamps. We now pick objectives and let them know what's happening. /datum/game_mode/bloodsucker/post_setup() - // Sunlight (Creating Bloodsuckers manually will check to create this, too) check_start_sunlight() - // Vamps for(var/datum/mind/bloodsucker in bloodsuckers) - // spawn() --> Run block of code but game continues on past it. - // sleep() --> Run block of code and freeze code there (including whoever called us) until it's resolved. - - //Clean Bloodsucker Species (racist?) - //clean_invalid_species(bloodsucker) - // TO-DO !!! - - // Add Bloodsucker Antag Datum (or remove from list on Fail) - if (!make_bloodsucker(bloodsucker)) + if(!make_bloodsucker(bloodsucker)) bloodsuckers -= bloodsucker - - // NOTE: Hunters are done in ..() parent proc - return ..() -// Checking for ACTUALLY Dead Vamps -/datum/game_mode/bloodsucker/are_special_antags_dead() - // Bloodsucker not Final Dead - for(var/datum/mind/bloodsucker in bloodsuckers) - if(!bloodsucker.AmFinalDeath()) - return FALSE - return TRUE - - // Init Sunlight (called from datum_bloodsucker.on_gain(), in case game mode isn't even Bloodsucker /datum/game_mode/proc/check_start_sunlight() // Already Sunlight (and not about to cancel) - if (istype(bloodsucker_sunlight) && !bloodsucker_sunlight.cancel_me) + if(istype(bloodsucker_sunlight) && !bloodsucker_sunlight.cancel_me) return bloodsucker_sunlight = new () // End Sun (last bloodsucker removed) /datum/game_mode/proc/check_cancel_sunlight() // No Sunlight - if (!istype(bloodsucker_sunlight)) + if(!istype(bloodsucker_sunlight)) return - if (bloodsuckers.len <= 0) + if(bloodsuckers.len <= 0) bloodsucker_sunlight.cancel_me = TRUE qdel(bloodsucker_sunlight) bloodsucker_sunlight = null @@ -151,43 +135,37 @@ // Not High Enough if(creator) var/datum/antagonist/bloodsucker/creator_bloodsucker = creator.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - if(!istype(creator_bloodsucker) || creator_bloodsucker.vamplevel < BLOODSUCKER_LEVEL_TO_EMBRACE) + if(!istype(creator_bloodsucker) || creator_bloodsucker.bloodsucker_level < BLOODSUCKER_LEVEL_TO_EMBRACE) to_chat(creator, "Your blood is too thin to turn this corpse!") return FALSE return TRUE /datum/game_mode/proc/make_bloodsucker(datum/mind/bloodsucker, datum/mind/creator = null) // NOTE: This is a game_mode/proc, NOT a game_mode/bloodsucker/proc! We need to access this function despite the game mode. - if (!can_make_bloodsucker(bloodsucker)) + if(!can_make_bloodsucker(bloodsucker)) return FALSE - // Create Datum: Fledgling var/datum/antagonist/bloodsucker/A // [FLEDGLING] - if (creator) + if(creator) A = new (bloodsucker) A.creator = creator bloodsucker.add_antag_datum(A) // Log message_admins("[bloodsucker] has become a Bloodsucker, and was created by [creator].") log_admin("[bloodsucker] has become a Bloodsucker, and was created by [creator].") - // [MASTER] else A = bloodsucker.add_antag_datum(ANTAG_DATUM_BLOODSUCKER) - - return TRUE - /datum/game_mode/proc/remove_bloodsucker(datum/mind/bloodsucker) bloodsucker.remove_antag_datum(ANTAG_DATUM_BLOODSUCKER) - /datum/game_mode/proc/clean_invalid_species(datum/mind/bloodsucker) // Only checking for Humans here - if (!ishuman(bloodsucker.current) || !bloodsucker.current.client) + if(!ishuman(bloodsucker.current) || !bloodsucker.current.client) return var/am_valid = TRUE var/mob/living/carbon/human/H = bloodsucker.current @@ -202,7 +180,7 @@ // everyone will wonder why you're a human with Plasma clothes (jk they'll know you're antag) // Convert to HUMAN (along with ID and PDA) - if (!am_valid) + if(!am_valid) H.set_species(/datum/species/human) H.real_name = H.client.prefs.custom_names["human"] var/obj/item/card/id/ID = H.wear_id?.GetID() @@ -211,12 +189,13 @@ ID.update_label() -/datum/game_mode/proc/can_make_vassal(mob/living/target, datum/mind/creator, display_warning=TRUE)//, check_antag_or_loyal=FALSE) +/datum/game_mode/proc/can_make_vassal(mob/living/target, datum/mind/creator, display_warning = TRUE)//, check_antag_or_loyal=FALSE) // Not Correct Type: Abort - if (!iscarbon(target) || !creator) + if(!iscarbon(target) || !creator) return FALSE - if (target.stat > UNCONSCIOUS) + if(target.stat > UNCONSCIOUS) return FALSE + // Check Overdose: Am I even addicted to blood? Do I even have any in me? //if (!target.reagents.addiction_list || !target.reagents.reagent_list) //message_admins("DEBUG2: can_make_vassal() Abort: No reagents") @@ -233,23 +212,23 @@ //message_admins("DEBUG4: can_make_vassal() Abort: No Blood") // return 0 // No Mind! - if (!target.mind || !target.mind.key) - if (display_warning) + if(!target.mind || !target.mind.key) + if(display_warning) to_chat(creator, "[target] isn't self-aware enough to be made into a Vassal.") return FALSE // Already MY Vassal var/datum/antagonist/vassal/V = target.mind.has_antag_datum(ANTAG_DATUM_VASSAL) - if (istype(V) && V.master) - if (V.master.owner == creator) - if (display_warning) + if(istype(V) && V.master) + if(V.master.owner == creator) + if(display_warning) to_chat(creator, "[target] is already your loyal Vassal!") else - if (display_warning) + if(display_warning) to_chat(creator, "[target] is the loyal Vassal of another Bloodsucker!") return FALSE // Already Antag or Loyal (Vamp Hunters count as antags) - if (target.mind.enslaved_to || AmInvalidAntag(target.mind)) //!VassalCheckAntagValid(target.mind, check_antag_or_loyal)) // HAS_TRAIT(target, TRAIT_MINDSHIELD, "implant") || - if (display_warning) + if(target.mind.enslaved_to || AmInvalidAntag(target.mind)) //!VassalCheckAntagValid(target.mind, check_antag_or_loyal)) // HAS_TRAIT(target, TRAIT_MINDSHIELD, "implant") || + if(display_warning) to_chat(creator, "[target] resists the power of your blood to dominate their mind!") return FALSE return TRUE @@ -268,24 +247,24 @@ return FALSE // Does even ONE antag appear in this mind that isn't in the list? Then FAIL! for(var/datum/antagonist/antag_datum in M.antag_datums) - if (!(antag_datum.type in vassal_allowed_antags)) // vassal_allowed_antags is a list stored in the game mode, above. + if(!(antag_datum.type in vassal_allowed_antags)) // vassal_allowed_antags is a list stored in the game mode, above. //message_admins("DEBUG VASSAL: Found Invalid: [antag_datum] // [antag_datum.type]") return TRUE //message_admins("DEBUG VASSAL: Valid Antags! (total of [M.antag_datums.len])") // WHEN YOU DELETE THE ABOVE: Remove the 3 second timer on converting the vassal too. return FALSE -/datum/game_mode/proc/make_vassal(mob/living/target, datum/mind/creator) - if (!can_make_vassal(target,creator)) +/datum/game_mode/proc/make_vassal(var/mob/living/target, var/datum/mind/creator) + if(!can_make_vassal(target, creator)) return FALSE // Make Vassal - var/datum/antagonist/vassal/V = new (target.mind) + var/datum/antagonist/vassal/V = new(target.mind) var/datum/antagonist/bloodsucker/B = creator.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) V.master = B target.mind.add_antag_datum(V, V.master.get_team()) // Update Bloodsucker Title (we're a daddy now) B.SelectTitle(am_fledgling = FALSE) // Only works if you have no title yet. - // Log + // Log it message_admins("[target] has become a Vassal, and is enslaved to [creator].") log_admin("[target] has become a Vassal, and is enslaved to [creator].") return TRUE diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 648c227c0a..bc0fec68ba 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -144,6 +144,8 @@ return FALSE if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding. return FALSE + if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker + return FALSE if(clonemind.active) //somebody is using that mind if( ckey(clonemind.key)!=ckey ) return FALSE @@ -159,8 +161,6 @@ mess = TRUE update_icon() return FALSE - if(isvamp(clonemind)) //If the mind is a bloodsucker - return FALSE attempting = TRUE //One at a time!! countdown.start() diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index 0f5e51215d..d01f7e3e40 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -57,7 +57,7 @@ var/turf/target = locate(target_x, target_y, z) ghost.forceMove(target) -/obj/machinery/launchpad/proc/isAvailable() +/obj/machinery/launchpad/proc/isAvailable(silent = FALSE) if(stat & NOPOWER) return FALSE if(panel_open) @@ -198,7 +198,7 @@ QDEL_NULL(briefcase) return ..() -/obj/machinery/launchpad/briefcase/isAvailable() +/obj/machinery/launchpad/briefcase/isAvailable(silent = FALSE) if(closed) return FALSE return ..() diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index d79fba7172..cef0b86c34 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -2,6 +2,7 @@ icon = 'icons/effects/landmarks_static.dmi' icon_state = "random_loot" layer = OBJ_LAYER + var/spawn_on_turf = TRUE var/lootcount = 1 //how many items will be spawned var/lootdoubles = TRUE //if the same item can be spawned twice var/list/loot //a list of possible items to spawn e.g. list(/obj/item, /obj/structure, /obj/effect) @@ -10,7 +11,7 @@ /obj/effect/spawner/lootdrop/Initialize(mapload) ..() if(loot && loot.len) - var/turf/T = get_turf(src) + var/atom/A = spawn_on_turf ? get_turf(src) : loc var/loot_spawned = 0 while((lootcount-loot_spawned) && loot.len) var/lootspawn = pickweight(loot) @@ -18,7 +19,7 @@ loot.Remove(lootspawn) if(lootspawn) - var/atom/movable/spawned_loot = new lootspawn(T) + var/atom/movable/spawned_loot = new lootspawn(A) if (!fan_out_items) if (pixel_x != 0) spawned_loot.pixel_x = pixel_x @@ -449,6 +450,7 @@ /obj/effect/spawner/lootdrop/low_loot_toilet name = "random low toilet spawner" lootcount = 1 + spawn_on_turf = FALSE //Note this is out of a 100 - Meaning the number you see is also the percent its going to pick that //This is ment for "low" loot that anyone could fine in a toilet, for better gear use high loot toilet loot = list("" = 30, @@ -458,41 +460,42 @@ /obj/item/clothing/glasses/sunglasses/blindfold = 4, /obj/item/clothing/glasses/sunglasses = 1, /obj/item/toy/plush/random = 5, - /obj/effect/spawner/lootdrop/gloves = 5, - /obj/effect/spawner/lootdrop/glowstick = 5, - /obj/effect/spawner/lootdrop/coin = 3, - /obj/effect/spawner/lootdrop/cig_packs = 10, - /obj/effect/spawner/lootdrop/cigars_cases = 2, - /obj/effect/spawner/lootdrop/space_cash = 5, + /obj/effect/spawner/lootdrop/gloves/no_turf = 5, + /obj/effect/spawner/lootdrop/glowstick/no_turf = 5, + /obj/effect/spawner/lootdrop/coin/no_turf = 3, + /obj/effect/spawner/lootdrop/cig_packs/no_turf = 10, + /obj/effect/spawner/lootdrop/cigars_cases/no_turf = 2, + /obj/effect/spawner/lootdrop/space_cash/no_turf = 5, /obj/item/reagent_containers/food/snacks/grown/cannabis = 5, /obj/item/storage/pill_bottle/dice = 5, /obj/item/toy/cards/deck = 5, - /obj/effect/spawner/lootdrop/druggie_pill = 5 + /obj/effect/spawner/lootdrop/druggie_pill/no_turf = 5 ) /obj/effect/spawner/lootdrop/prison_loot_toilet name = "random prison toilet spawner" lootcount = 1 + spawn_on_turf = FALSE //Note this is out of a 100 - Meaning the number you see is also the percent its going to pick that //This is ment for "prison" loot that is rather rare and ment for "prisoners if they get a crowbar to fine, or sec. loot = list("" = 10, /obj/item/lighter = 5, /obj/item/poster/random_contraband = 5, /obj/item/clothing/glasses/sunglasses = 5, - /obj/effect/spawner/lootdrop/coin = 5, - /obj/effect/spawner/lootdrop/cig_packs = 10, - /obj/effect/spawner/lootdrop/cigars_cases = 5, + /obj/effect/spawner/lootdrop/coin/no_turf = 5, + /obj/effect/spawner/lootdrop/cig_packs/no_turf = 10, + /obj/effect/spawner/lootdrop/cigars_cases/no_turf = 5, /obj/item/reagent_containers/food/snacks/grown/cannabis = 5, /obj/item/storage/pill_bottle/dice = 5, /obj/item/toy/cards/deck = 5, - /obj/effect/spawner/lootdrop/druggie_pill = 5, + /obj/effect/spawner/lootdrop/druggie_pill/no_turf = 5, /obj/item/kitchen/knife = 5, /obj/item/screwdriver = 5, - /obj/item/crowbar/red = 0.5, //Dont you need a crowbar to open this? + /obj/item/crowbar/red = 1, //Dont you need a crowbar to open this? /obj/item/stack/medical/bruise_pack = 3, /obj/item/reagent_containers/food/drinks/bottle/vodka = 2, /obj/item/radio = 5, - /obj/item/flashlight = 4.5, + /obj/item/flashlight = 4, /obj/item/clothing/mask/breath = 2, /obj/item/tank/internals/emergency_oxygen = 3, /obj/item/storage/box/mre/menu4/safe = 3, @@ -502,13 +505,14 @@ /obj/effect/spawner/lootdrop/high_loot_toilet name = "random high toilet spawner" lootcount = 1 + spawn_on_turf = FALSE //Note this is out of a 100 - Meaning the number you see is also the percent its going to pick that //The items inside are always going to be something usefull, illegal and likely traitorous. loot = list( /obj/item/clothing/glasses/sunglasses = 5, - /obj/effect/spawner/lootdrop/coin = 5, - /obj/effect/spawner/lootdrop/space_cash = 5, - /obj/effect/spawner/lootdrop/druggie_pill = 5, + /obj/effect/spawner/lootdrop/coin/no_turf = 5, + /obj/effect/spawner/lootdrop/space_cash/no_turf = 5, + /obj/effect/spawner/lootdrop/druggie_pill/no_turf = 5, /obj/item/storage/fancy/cigarettes/cigpack_syndicate = 5, /obj/item/suppressor = 5, /obj/item/toy/cards/deck/syndicate = 5, @@ -521,3 +525,24 @@ /obj/item/clothing/gloves/combat = 10, /obj/item/clothing/shoes/sneakers/noslip = 10 ) + +/obj/effect/spawner/lootdrop/coin/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/space_cash/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/druggie_pill/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/gloves/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/cig_packs/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/cigars_cases/no_turf + spawn_on_turf = FALSE + +/obj/effect/spawner/lootdrop/glowstick/no_turf + spawn_on_turf = FALSE diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index aad6f45198..22769b05b1 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -41,7 +41,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/hitsound = null var/usesound = null var/throwhitsound = null + + /// Weight class for how much storage capacity it uses and how big it physically is meaning storages can't hold it if their maximum weight class isn't as high as it. var/w_class = WEIGHT_CLASS_NORMAL + /// Volume override for the item, otherwise automatically calculated from w_class. + var/w_volume /// The amount of stamina it takes to swing an item in a normal melee attack do not lie to me and say it's for realism because it ain't. If null it will autocalculate from w_class. var/total_mass //Total mass in arbitrary pound-like values. If there's no balance reasons for an item to have otherwise, this var should be the item's weight in pounds. @@ -434,6 +438,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) item_flags |= IN_INVENTORY user.update_equipment_speed_mods() +//Overlays for the worn overlay so you can overlay while you overlay +//eg: ammo counters, primed grenade flashing, etc. +//"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file +/obj/item/proc/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = list() + SEND_SIGNAL(src, COMSIG_ITEM_WORN_OVERLAYS, isinhands, icon_file, used_state, style_flags, .) + //sometimes we only want to grant the item's action if it's equipped in a specific slot. /obj/item/proc/item_action_slot_check(slot, mob/user, datum/action/A) if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there @@ -857,6 +868,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) return return ..() +/// Get an item's volume that it uses when being stored. +/obj/item/proc/get_w_volume() + // if w_volume is 0 you fucked up anyways lol + return w_volume || AUTO_SCALE_VOLUME(w_class) + /obj/item/proc/embedded(mob/living/carbon/human/embedded_mob) return diff --git a/code/game/objects/items/RCL.dm b/code/game/objects/items/RCL.dm index fccf790a23..f3ea461c74 100644 --- a/code/game/objects/items/RCL.dm +++ b/code/game/objects/items/RCL.dm @@ -113,7 +113,7 @@ cable_overlay.color = GLOB.cable_colors[colors[current_color_index]] . += cable_overlay -/obj/item/twohanded/rcl/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/twohanded/rcl/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands || !(loaded?.amount)) return diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index e2ace42be7..ac60a322d8 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -303,8 +303,8 @@ block_chance = 50 var/shield_icon = "shield-red" -/obj/item/nullrod/staff/worn_overlays(isinhands, icon_file, style_flags = NONE) - . = list() +/obj/item/nullrod/staff/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) + . = ..() if(isinhands) . += mutable_appearance('icons/effects/effects.dmi', shield_icon, MOB_LAYER + 0.01) diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm index 16d8ec0f4e..e4cfeab20f 100644 --- a/code/game/objects/items/melee/energy.dm +++ b/code/game/objects/items/melee/energy.dm @@ -324,7 +324,7 @@ . = ..() . += "Alt-click to recolor it." -/obj/item/melee/transforming/energy/sword/cx/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/melee/transforming/energy/sword/cx/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(active) if(isinhands) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index b137c5c0f3..08ce73109c 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -663,21 +663,19 @@ var/maxReduction = 1 -/obj/effect/proc_holder/silicon/cyborg/vtecControl/Click(mob/living/silicon/robot/user) - var/mob/living/silicon/robot/self = usr - +/obj/effect/proc_holder/silicon/cyborg/vtecControl/Trigger(mob/living/silicon/robot/user) currentState = (currentState + 1) % 3 - if(istype(self)) + if(istype(user)) switch(currentState) if (0) - self.speed = initial(self.speed) + user.speed = initial(user.speed) if (1) - self.speed = initial(self.speed) - maxReduction * 0.5 + user.speed = initial(user.speed) - maxReduction * 0.5 if (2) - self.speed = initial(self.speed) - maxReduction * 1 + user.speed = initial(user.speed) - maxReduction * 1 action.button_icon_state = "Chevron_State_[currentState]" action.UpdateButtonIcon() - return + return TRUE diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 205ce57251..50e9b94e97 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -72,6 +72,8 @@ to_chat(user, " [M] is at full health.") return FALSE user.visible_message("[user] applies \the [src] on [M].", "You apply \the [src] on [M].") + if(AmBloodsucker(M)) + return M.heal_bodypart_damage((heal_brute/2)) return TRUE if(iscarbon(M)) @@ -148,6 +150,8 @@ return if(iscarbon(M)) return heal_carbon(M, user, 0, heal_burn) + if(AmBloodsucker(M)) + return to_chat(user, "You can't heal [M] with the \the [src]!") /obj/item/stack/medical/ointment/suicide_act(mob/living/user) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index bd9673f455..dc6f5f701e 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -22,7 +22,7 @@ for(var/obj/item/I in contents) . += I.get_belt_overlay() -/obj/item/storage/belt/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/storage/belt/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands && onmob_overlays) for(var/obj/item/I in contents) diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm index c1cbf534ca..6ff5dfc8ad 100644 --- a/code/game/objects/items/tanks/watertank.dm +++ b/code/game/objects/items/tanks/watertank.dm @@ -376,8 +376,8 @@ filling.color = mix_color_from_reagents(reagents.reagent_list) add_overlay(filling) -/obj/item/reagent_containers/chemtank/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) //apply chemcolor and level - . = list() +/obj/item/reagent_containers/chemtank/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) //apply chemcolor and level + . = ..() //inhands + reagent_filling if(!isinhands && reagents.total_volume) var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "backpackmob-10") diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 0d2892cb4a..e9f517a9f1 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -53,8 +53,8 @@ base_overlay.appearance_flags = RESET_COLOR . += base_overlay -/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/screwdriver/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(isinhands && random_color) var/mutable_appearance/M = mutable_appearance(icon_file, "screwdriver_head") M.appearance_flags = RESET_COLOR diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index e9b5712e71..9291b72467 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -349,7 +349,7 @@ update_light() return TRUE -/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/toy/sword/cx/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(active) if(isinhands) diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm index 1a09cc57b6..2b6a91eb51 100644 --- a/code/game/objects/items/twohanded.dm +++ b/code/game/objects/items/twohanded.dm @@ -531,7 +531,7 @@ update_light() return TRUE -/obj/item/twohanded/dualsaber/hypereutactic/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/twohanded/dualsaber/hypereutactic/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(isinhands) var/mutable_appearance/gem_inhand = mutable_appearance(icon_file, "hypereutactic_gem") diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 3127485878..57d7e08862 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -222,7 +222,7 @@ LINEN BINS add_overlay(g_mouth) add_overlay(g_eyes) -/obj/item/bedsheet/gondola/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) +/obj/item/bedsheet/gondola/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) . += mutable_appearance(icon_file, g_mouth) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 892d85cd6e..95edd15951 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -64,7 +64,7 @@ else I.forceMove(drop_location()) to_chat(user, "You find [I] in the cistern.") - w_items -= I.w_class + w_items = max(w_items - I.w_class, 0) else open = !open update_icon() @@ -115,6 +115,12 @@ secret.desc += "" //In case you want to add something to the item that spawns contents += secret +/obj/structure/toilet/secret/LateInitialize() + . = ..() + w_items = 0 //recalculate total weight thanks to the secret. + for(var/obj/item/I in contents) + w_items += I.w_class + /obj/structure/toilet/secret/low_loot secret_type = /obj/effect/spawner/lootdrop/low_loot_toilet diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index c61ac8972c..7e1b39cb39 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -173,6 +173,16 @@ /turf/closed/mineral/silver = 12, /turf/closed/mineral/plasma = 20, /turf/closed/mineral/iron = 40, /turf/closed/mineral/titanium = 11, /turf/closed/mineral/gibtonite = 4, /turf/closed/mineral/bscrystal = 1) +/turf/closed/mineral/random/no_caves/earth_like + icon_state = "rock_oxy" + turf_type = /turf/open/floor/plating/asteroid + baseturfs = /turf/open/floor/plating/asteroid + mineralSpawnChanceList = list(/turf/closed/mineral/uranium/earth_like = 5, /turf/closed/mineral/diamond/earth_like = 1, /turf/closed/mineral/gold/earth_like = 10, + /turf/closed/mineral/silver/earth_like = 12, /turf/closed/mineral/plasma/earth_like = 20, /turf/closed/mineral/iron/earth_like = 40, + /turf/closed/mineral/titanium/earth_like = 11, /turf/closed/mineral/gibtonite/earth_like = 4, /turf/closed/mineral/bscrystal/earth_like = 1) + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + defer_change = TRUE + /turf/closed/mineral/random/high_chance icon_state = "rock_highchance" mineralChance = 25 @@ -194,6 +204,10 @@ icon_state = "rock_highchance_oxy" turf_type = /turf/open/floor/plating/asteroid baseturfs = /turf/open/floor/plating/asteroid + mineralSpawnChanceList = list( + /turf/closed/mineral/uranium/earth_like = 35, /turf/closed/mineral/diamond/earth_like = 30, /turf/closed/mineral/gold/earth_like = 45, + /turf/closed/mineral/titanium/earth_like = 45, /turf/closed/mineral/silver/earth_like = 50, /turf/closed/mineral/plasma/earth_like = 50, + /turf/closed/mineral/bscrystal/earth_like = 20) initial_gas_mix = OPENTURF_DEFAULT_ATMOS defer_change = TRUE @@ -211,6 +225,10 @@ turf_type = /turf/open/floor/plating/asteroid baseturfs = /turf/open/floor/plating/asteroid initial_gas_mix = OPENTURF_DEFAULT_ATMOS + mineralSpawnChanceList = list( + /turf/closed/mineral/uranium/earth_like = 2, /turf/closed/mineral/diamond/earth_like = 1, /turf/closed/mineral/gold/earth_like = 4, + /turf/closed/mineral/titanium/earth_like = 4, /turf/closed/mineral/silver/earth_like = 6, /turf/closed/mineral/plasma/earth_like = 15, + /turf/closed/mineral/iron/earth_like = 40, /turf/closed/mineral/gibtonite/earth_like = 2, /turf/closed/mineral/bscrystal/earth_like = 1) defer_change = TRUE /turf/closed/mineral/random/volcanic @@ -246,13 +264,6 @@ /turf/closed/mineral/silver/volcanic = 20, /turf/closed/mineral/plasma/volcanic = 30, /turf/closed/mineral/bscrystal/volcanic = 1, /turf/closed/mineral/gibtonite/volcanic = 2, /turf/closed/mineral/iron/volcanic = 95) -/turf/closed/mineral/random/earth_like - icon_state = "rock_oxy" - turf_type = /turf/open/floor/plating/asteroid - baseturfs = /turf/open/floor/plating/asteroid - initial_gas_mix = OPENTURF_DEFAULT_ATMOS - defer_change = TRUE - /turf/closed/mineral/iron mineralType = /obj/item/stack/ore/iron @@ -624,3 +635,10 @@ baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface initial_gas_mix = LAVALAND_DEFAULT_ATMOS defer_change = 1 + +/turf/closed/mineral/gibtonite/earth_like + icon_state = "rock_oxy" + turf_type = /turf/open/floor/plating/asteroid + baseturfs = /turf/open/floor/plating/asteroid + initial_gas_mix = OPENTURF_DEFAULT_ATMOS + defer_change = TRUE diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_integration.dm b/code/modules/antagonists/bloodsucker/bloodsucker_integration.dm index 3a6b4efedb..98fb69e52c 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_integration.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_integration.dm @@ -1,12 +1,6 @@ // INTEGRATION: Adding Procs and Datums to existing "classes" -/mob/living/proc/AmBloodsucker(falseIfInDisguise=FALSE) - // No Datum - if(!mind || !mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)) - return FALSE - return TRUE - -/mob/living/proc/HaveBloodsuckerBodyparts(var/displaymessage="") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages. +/mob/living/proc/HaveBloodsuckerBodyparts(displaymessage = "") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages. if(!getorganslot(ORGAN_SLOT_HEART)) if(displaymessage != "") to_chat(src, "Without a heart, you are incapable of [displaymessage].") @@ -21,33 +15,6 @@ return FALSE return TRUE - - -// GET DAMAGE - - -// Do NOT count the damage on prosthetics for this. -/mob/living/proc/getBruteLoss_nonProsthetic() - return getBruteLoss() - -/mob/living/proc/getFireLoss_nonProsthetic() - return getFireLoss() - -/mob/living/carbon/getBruteLoss_nonProsthetic() - var/amount = 0 - for(var/obj/item/bodypart/BP in bodyparts) - if(BP.status < 2) - amount += BP.brute_dam - return amount - -/mob/living/carbon/getFireLoss_nonProsthetic() - var/amount = 0 - for(var/obj/item/bodypart/BP in bodyparts) - if(BP.status < 2) - amount += BP.burn_dam - return amount - -/mob/living/carbon // EXAMINING /mob/living/carbon/human/proc/ReturnVampExamine(var/mob/viewer) if(!mind || !viewer.mind) diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm index e774cf4250..efccb5591e 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_life.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_life.dm @@ -12,10 +12,10 @@ /datum/antagonist/bloodsucker/proc/LifeTick()// Should probably run from life.dm, same as handle_changeling, but will be an utter pain to move set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side. - var/notice_healing = FALSE + var/notice_healing while(owner && !AmFinalDeath()) // owner.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) == src if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_DEATHCOMA)) // Deduct Blood - AddBloodVolume(-0.1) // -.15 (before tick went from 10 to 30, but we also charge more for faking life now) + AddBloodVolume(passive_blood_drain) // -.1 currently if(HandleHealing(1)) // Heal if(notice_healing == FALSE && owner.current.blood_volume > 0) to_chat(owner, "The power of your blood begins knitting your wounds...") @@ -25,7 +25,7 @@ HandleStarving() // Death HandleDeath() // Standard Update update_hud()// Daytime Sleep in Coffin - if (SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker")) + if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker")) if(istype(owner.current.loc, /obj/structure/closet/crate/coffin)) Torpor_Begin() // Wait before next pass @@ -39,12 +39,12 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /datum/antagonist/bloodsucker/proc/AddBloodVolume(value) - owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, maxBloodVolume) + owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, max_blood_volume) update_hud() /datum/antagonist/bloodsucker/proc/HandleFeeding(mob/living/carbon/target, mult=1) // mult: SILENT feed is 1/3 the amount - var/blood_taken = min(feedAmount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time) + var/blood_taken = min(feed_amount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time) target.blood_volume -= blood_taken // Simple Animals lose a LOT of blood, and take damage. This is to keep cats, cows, and so forth from giving you insane amounts of blood. if(!ishuman(target)) @@ -82,38 +82,40 @@ /datum/antagonist/bloodsucker/proc/HandleHealing(mult = 1) // NOTE: Mult of 0 is just a TEST to see if we are injured and need to go into Torpor! //It is called from your coffin on close (by you only) + var/actual_regen = regen_rate + additional_regen if(poweron_masquerade == TRUE || owner.current.AmStaked()) return FALSE - owner.current.adjustStaminaLoss(-1.5 + (regenRate * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more. - owner.current.adjustCloneLoss(-0.1 * (regenRate * 2) * mult, 0) - owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0) + if(owner.current.reagents.has_reagent(/datum/reagent/consumable/garlic)) + return FALSE + if(istype(owner.current.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace)) + return FALSE + owner.current.adjustStaminaLoss(-1.5 + (actual_regen * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more. + owner.current.adjustCloneLoss(-0.1 * (actual_regen * 2) * mult, 0) + owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (actual_regen * 4) * mult) // No Bleeding - if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete. + /*if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete. var/mob/living/carbon/human/H = owner.current - H.bleed_rate = 0 + if(H.bleed_rate > 0) //Only heal bleeding if we are actually bleeding + H.bleed_rate =- 0.5 + actual_regen * 0.2 */ if(iscarbon(owner.current)) // Damage Heal: Do I have damage to ANY bodypart? var/mob/living/carbon/C = owner.current var/costMult = 1 // Coffin makes it cheaper var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire) - var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_DEATHCOMA)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin) + var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin) if(amInCoffinWhileTorpor) mult *= 4 // Increase multiplier if we're sleeping in a coffin. - fireheal = min(C.getFireLoss_nonProsthetic(), regenRate) // NOTE: Burn damage ONLY heals in torpor. - costMult = 0.25 + fireheal = min(C.getFireLoss(), regen_rate) // NOTE: Burn damage ONLY heals in torpor. C.ExtinguishMob() CureDisabilities() // Extinguish Fire C.remove_all_embedded_objects() // Remove Embedded! owner.current.regenerate_organs() // Heal Organs (will respawn original eyes etc. but we replace right away, next) CheckVampOrgans() // Heart, Eyes - else - if(owner.current.blood_volume <= 0) // No Blood? Lower Mult - mult = 0.25 - // Crit from burn? Lower damage to maximum allowed. - //if (C.getFireLoss() > owner.current.getMaxHealth()) - // fireheal = regenRate / 2 + if(check_limbs(costMult)) + return TRUE + // BRUTE: Always Heal - var/bruteheal = min(C.getBruteLoss_nonProsthetic(), regenRate) - var/toxinheal = min(C.getToxLoss(), regenRate) + var/bruteheal = min(C.getBruteLoss(), actual_regen) + var/toxinheal = min(C.getToxLoss(), actual_regen) // Heal if Damaged if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return. if(mult == 0) @@ -127,28 +129,29 @@ //C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above. AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal return TRUE // Healed! Done for this tick. - if(amInCoffinWhileTorpor) // Limbs? (And I have no other healing) - var/list/missing = owner.current.get_missing_limbs() // Heal Missing - if (missing.len) // Cycle through ALL limbs and regen them! - for (var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it. - owner.current.regenerate_limb(targetLimbZone, 0) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head")) - var/obj/item/bodypart/L = owner.current.get_bodypart( targetLimbZone ) // 2) Limb returns Damaged - AddBloodVolume(50 * costMult) // Costs blood to heal - L.brute_dam = 60 - to_chat(owner.current, "Your flesh knits as it regrows [L]!") - playsound(owner.current, 'sound/magic/demon_consume.ogg', 50, 1) - // DONE! After regenerating ANY number of limbs, we stop here. - return TRUE - /*else // REMOVED: For now, let's just leave prosthetics on. Maybe you WANT to be a robovamp. - // Remove Prosthetic/False Limb - for(var/obj/item/bodypart/BP in C.bodyparts) - message_admins("T1: [BP] ") - if (istype(BP) && BP.status == 2) - message_admins("T2: [BP] ") - BP.drop_limb() - return TRUE */ - // NOTE: Limbs have a "status", like their hosts "stat". 2 is dead (aka Prosthetic). 1 seems to be idle/alive.*/ - return FALSE + + + +/datum/antagonist/bloodsucker/proc/check_limbs(costMult) + var/limb_regen_cost = 50 * costMult + var/mob/living/carbon/C = owner.current + var/list/missing = C.get_missing_limbs() + if(missing.len && C.blood_volume < limb_regen_cost + 5) + return FALSE + for(var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it. + C.regenerate_limb(targetLimbZone, FALSE) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head")) + AddBloodVolume(50) + var/obj/item/bodypart/L = C.get_bodypart(targetLimbZone) // 2) Limb returns Damaged + L.brute_dam = 60 + to_chat(C, "Your flesh knits as it regrows your [L]!") + playsound(C, 'sound/magic/demon_consume.ogg', 50, TRUE) + return TRUE + /*for(var/obj/item/bodypart/BP in C.bodyparts) + if(!istype(BP) && !BP.status == 2) + return FALSE + to_chat(C, "Your body expels the [BP]!") + BP.drop_limb() + return TRUE */ /datum/antagonist/bloodsucker/proc/CureDisabilities() var/mob/living/carbon/C = owner.current @@ -179,7 +182,16 @@ if(owner.current.blood_volume < BLOOD_VOLUME_BAD / 2) owner.current.blur_eyes(8 - 8 * (owner.current.blood_volume / BLOOD_VOLUME_BAD)) // Nutrition - owner.current.nutrition = min(owner.current.blood_volume, NUTRITION_LEVEL_FED) // <-- 350 //NUTRITION_LEVEL_FULL + owner.current.nutrition = clamp(owner.current.blood_volume, 545, 0) //The amount of blood is how full we are. + //A bit higher regeneration based on blood volume + if(owner.current.blood_volume < 700) + additional_regen = 0.4 + else if(owner.current.blood_volume < BLOOD_VOLUME_NORMAL) + additional_regen = 0.3 + else if(owner.current.blood_volume < BLOOD_VOLUME_OKAY) + additional_regen = 0.2 + else if(owner.current.blood_volume < BLOOD_VOLUME_BAD) + additional_regen = 0.1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEATH @@ -189,7 +201,7 @@ /datum/antagonist/bloodsucker/proc/HandleDeath() // FINAL DEATH // Fire Damage? (above double health) - if(owner.current.getFireLoss_nonProsthetic() >= owner.current.maxHealth * 2.5) + if(owner.current.getFireLoss() >= owner.current.maxHealth * 3) FinalDeath() return // Staked while "Temp Death" or Asleep @@ -209,8 +221,8 @@ // for (var/datum/action/bloodsucker/masquerade/P in powers) // P.Deactivate() // TEMP DEATH - var/total_brute = owner.current.getBruteLoss_nonProsthetic() - var/total_burn = owner.current.getFireLoss_nonProsthetic() + var/total_brute = owner.current.getBruteLoss() + var/total_burn = owner.current.getFireLoss() var/total_toxloss = owner.current.getToxLoss() //This is neater than just putting it in total_damage var/total_damage = total_brute + total_burn + total_toxloss // Died? Convert to Torpor (fake death) @@ -218,27 +230,25 @@ Torpor_Begin() to_chat(owner, "Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.") sleep(30) //To avoid spam - if (poweron_masquerade == TRUE) + if(poweron_masquerade == TRUE) to_chat(owner, "Your wounds will not heal until you disable the Masquerade power.") // End Torpor: else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn) if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin)) // Not Daytime, Not in Torpor - if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker")) + if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker")) Torpor_End() // Fake Unconscious if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT) - owner.current.Unconscious(20,1) - //HEALTH_THRESHOLD_CRIT 0 - //HEALTH_THRESHOLD_FULLCRIT -30 - //HEALTH_THRESHOLD_DEAD -100 + owner.current.Unconscious(20, 1) -/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin=FALSE) +/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin = FALSE) owner.current.stat = UNCONSCIOUS - owner.current.fakedeath("bloodsucker") // Come after UNCONSCIOUS or else it fails + owner.current.apply_status_effect(STATUS_EFFECT_UNCONSCIOUS) + ADD_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker") // Come after UNCONSCIOUS or else it fails ADD_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") // Without this, you'll just keep dying while you recover. - ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever. - ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever. + ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in space. Otherwise you just...heal forever. + ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker") // Visuals owner.current.update_sight() owner.current.reload_fullscreen() @@ -247,10 +257,10 @@ if(power.active && !power.can_use_in_torpor) power.DeactivatePower() - /datum/antagonist/bloodsucker/proc/Torpor_End() owner.current.stat = SOFT_CRIT - owner.current.cure_fakedeath("bloodsucker") // Come after SOFT_CRIT or else it fails + owner.current.remove_status_effect(STATUS_EFFECT_UNCONSCIOUS) + REMOVE_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker") REMOVE_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") REMOVE_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") REMOVE_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker") @@ -283,18 +293,19 @@ // Free my Vassals! FreeAllVassals() // Elders get Dusted - if(vamplevel >= 4) // (vamptitle) + if(bloodsucker_level >= 4) // (bloodsucker_title) owner.current.visible_message("[owner.current]'s skin crackles and dries, their skin and bones withering to dust. A hollow cry whips from what is now a sandy pile of remains.", \ "Your soul escapes your withering body as the abyss welcomes you to your Final Death.", \ "You hear a dry, crackling sound.") + sleep(50) owner.current.dust() // Fledglings get Gibbed else owner.current.visible_message("[owner.current]'s skin bursts forth in a spray of gore and detritus. A horrible cry echoes from what is now a wet pile of decaying meat.", \ "Your soul escapes your withering body as the abyss welcomes you to your Final Death.", \ "You hear a wet, bursting sound.") - owner.current.gib(TRUE, FALSE, FALSE)//Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety. - playsound(owner.current.loc, 'sound/effects/tendril_destroyed.ogg', 40, 1) + owner.current.gib(TRUE, FALSE, FALSE) //Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety. + playsound(owner.current, 'sound/effects/tendril_destroyed.ogg', 40, TRUE) @@ -304,15 +315,15 @@ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/mob/proc/CheckBloodsuckerEatFood(var/food_nutrition) - if (!isliving(src)) +/mob/proc/CheckBloodsuckerEatFood(food_nutrition) + if(!isliving(src)) return var/mob/living/L = src - if(!L.AmBloodsucker()) + if(!AmBloodsucker(L)) return - // We're a vamp? Try to eat food... - var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) - bloodsuckerdatum.handle_eat_human_food(food_nutrition) + // We're a bloodsucker? Try to eat food... + var/datum/antagonist/bloodsucker/B = L.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + B.handle_eat_human_food(food_nutrition) /datum/antagonist/bloodsucker/proc/handle_eat_human_food(food_nutrition, puke_blood = TRUE, masquerade_override) // Called from snacks.dm and drinks.dm diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm index 507e1f2739..5c4b1f2b9f 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm @@ -93,6 +93,14 @@ if(display_error) to_chat(owner, "You have a stake in your chest! Your powers are useless.") return FALSE + if(istype(owner.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace)) + if(display_error) + to_chat(owner, "") + return FALSE + if(owner.reagents?.has_reagent(/datum/reagent/consumable/garlic)) + if(display_error) + to_chat(owner, "Garlic in your blood is interfering with your powers!") + return FALSE // Incap? if(must_be_capacitated) var/mob/living/L = owner diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm index 263f91a9a6..b7d98c6783 100644 --- a/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm +++ b/code/modules/antagonists/bloodsucker/bloodsucker_sunlight.dm @@ -141,23 +141,23 @@ if(!bloodsuckerdatum.warn_sun_locker) to_chat(M, "Your skin sizzles. The [M.current.loc] doesn't protect well against UV bombardment.") bloodsuckerdatum.warn_sun_locker = TRUE - M.current.adjustFireLoss(0.5 + bloodsuckerdatum.vamplevel / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.vamplevel / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.vamplevel) + M.current.adjustFireLoss(0.5 + bloodsuckerdatum.bloodsucker_level / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.bloodsucker_level / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.bloodsucker_level) M.current.updatehealth() SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_1) // Out in the Open? Buh Bye else if(!bloodsuckerdatum.warn_sun_burn) - if(bloodsuckerdatum.vamplevel > 0) + if(bloodsuckerdatum.bloodsucker_level > 0) to_chat(M, "The solar flare sets your skin ablaze!") else to_chat(M, "The solar flare scalds your neophyte skin!") bloodsuckerdatum.warn_sun_burn = TRUE if(M.current.fire_stacks <= 0) M.current.fire_stacks = 0 - if(bloodsuckerdatum.vamplevel > 0) - M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.vamplevel / 10) + if(bloodsuckerdatum.bloodsucker_level > 0) + M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.bloodsucker_level / 10) M.current.IgniteMob() - M.current.adjustFireLoss(2 + bloodsuckerdatum.vamplevel) // M.current.fireloss += 2 + bloodsuckerdatum.vamplevel // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.vamplevel) + M.current.adjustFireLoss(2 + bloodsuckerdatum.bloodsucker_level) // M.current.fireloss += 2 + bloodsuckerdatum.bloodsucker_level // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.bloodsucker_level) M.current.updatehealth() SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2) diff --git a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm index 94c62df696..946be31ed6 100644 --- a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm +++ b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm @@ -8,9 +8,9 @@ job_rank = ROLE_BLOODSUCKER threat = 5 // NAME - var/vampname // My Dracula name - var/vamptitle // My Dracula title - var/vampreputation // My "Surname" or description of my deeds + var/bloodsucker_name // My Dracula style name + var/bloodsucker_title // My Dracula style title + var/bloodsucker_reputation // My "Surname" or description of my deeds // CLAN var/datum/team/vampireclan/clan var/list/datum/antagonist/vassal/vassals = list()// Vassals under my control. Periodically remove the dead ones. @@ -20,35 +20,33 @@ var/poweron_feed = FALSE // Am I feeding? var/poweron_masquerade = FALSE // STATS - var/vamplevel = 0 - var/vamplevel_unspent = 1 - var/regenRate = 0.4 // How many points of Brute do I heal per tick? - var/feedAmount = 15 // Amount of blood drawn from a target per tick. - var/maxBloodVolume = 600 // Maximum blood a Vamp can hold via feeding. // BLOOD_VOLUME_NORMAL 550 // BLOOD_VOLUME_SAFE 475 //BLOOD_VOLUME_OKAY 336 //BLOOD_VOLUME_BAD 224 // BLOOD_VOLUME_SURVIVE 122 + var/bloodsucker_level + var/bloodsucker_level_unspent = 1 + var/regen_rate = 0.3 // How fast do I regenerate? + var/additional_regen // How much additional blood regen we gain from bonuses such as high blood. + var/feed_amount = 15 // Amount of blood drawn from a target per tick. + var/max_blood_volume = 600 // Maximum blood a Vamp can hold via feeding. // OBJECTIVES var/list/datum/objective/objectives_given = list() // For removal if needed. var/area/lair var/obj/structure/closet/crate/coffin // TRACKING - var/foodInGut = 0 // How much food to throw up later. You shouldn't have eaten that. - var/warn_sun_locker = FALSE // So we only get the locker burn message once per day. - var/warn_sun_burn = FALSE // So we only get the sun burn message once per day. - var/had_toxlover = FALSE + var/foodInGut // How much food to throw up later. You shouldn't have eaten that. + var/warn_sun_locker // So we only get the locker burn message once per day. + var/warn_sun_burn // So we only get the sun burn message once per day. + var/had_toxlover var/level_bloodcost + var/passive_blood_drain = -0.1 //The amount of blood we loose each bloodsucker life() tick // LISTS var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \ TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE) - // NOTES: TRAIT_AGEUSIA <-- Doesn't like flavors. - // REMOVED: TRAIT_NODEATH - // TO ADD: - //var/static/list/defaultOrgans = list (/obj/item/organ/heart/vampheart,/obj/item/organ/heart/vampeyes) /datum/antagonist/bloodsucker/on_gain() SSticker.mode.bloodsuckers |= owner // Add if not already in here (and you might be, if you were picked at round start) SSticker.mode.check_start_sunlight()// Start Sunlight? (if first Vamp) SelectFirstName()// Name & Title - SelectTitle(am_fledgling=TRUE) // If I have a creator, then set as Fledgling. - SelectReputation(am_fledgling=TRUE) + SelectTitle(am_fledgling = TRUE) // If I have a creator, then set as Fledgling. + SelectReputation(am_fledgling = TRUE) AssignStarterPowersAndStats()// Give Powers & Stats forge_bloodsucker_objectives()// Objectives & Team update_bloodsucker_icons_added(owner.current, "bloodsucker") // Add Antag HUD @@ -68,18 +66,18 @@ /datum/antagonist/bloodsucker/greet() var/fullname = ReturnFullName(TRUE) - to_chat(owner, "You are [fullname], a bloodsucking vampire!
") + to_chat(owner, "You are [fullname], a strain of vampire dubbed bloodsucker!
") owner.announce_objectives() to_chat(owner, "* You regenerate your health slowly, you're weak to fire, and you depend on blood to survive. Allow your stolen blood to run too low, and you will find yourself at \ risk of being discovered!
") //to_chat(owner, "As an immortal, your power is linked to your age. The older you grow, the more abilities you will have access to.") - var/vamp_greet - vamp_greet += "* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.
" - vamp_greet += "* Use \",b\" to speak your ancient Bloodsucker language.
" - vamp_greet += "Bloodsucker Tip: Rest in a Coffin to claim it, and that area, as your lair.
" - vamp_greet += "Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.
" - vamp_greet += "Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.
" - to_chat(owner, vamp_greet) + var/bloodsucker_greet + bloodsucker_greet += "* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.
" + bloodsucker_greet += "* Use \",b\" to speak your ancient Bloodsucker language.
" + bloodsucker_greet += "Bloodsucker Tip: Rest in a Coffin to claim it, and that area, as your lair.
" + bloodsucker_greet += "Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.
" + bloodsucker_greet += "Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.
" + to_chat(owner, bloodsucker_greet) owner.current.playsound_local(null, 'sound/bloodsucker/BloodsuckerAlert.ogg', 100, FALSE, pressure_affected = FALSE) antag_memory += "Although you were born a mortal, in un-death you earned the name [fullname].
" @@ -92,13 +90,13 @@ owner.current.blood_volume = max(owner.current.blood_volume,BLOOD_VOLUME_SAFE) /datum/antagonist/bloodsucker/threat() - return ..()+3*vamplevel + return ..() + 3 * bloodsucker_level /datum/antagonist/bloodsucker/proc/SelectFirstName() // Names (EVERYONE gets one)) if(owner.current.gender == MALE) - vampname = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \ + bloodsucker_name = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \ "Sveyn","Aurel","Alexe","Iustin","Theodor","Dimitrie","Octav","Damien","Magnus","Caine","Abel", // Romanian/Ancient "Lucius","Gaius","Otho","Balbinus","Arcadius","Romanos","Alexios","Vitellius", // Latin "Melanthus","Teuthras","Orchamus","Amyntor","Axion", // Greek @@ -106,7 +104,7 @@ "Dio") else - vampname = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \ + bloodsucker_name = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \ "Alina","Rodica","Teodora","Denisa","Mihaela","Svetla","Stefania","Diyana","Kelssa","Lilith", // Romanian/Ancient "Alexia","Athanasia","Callista","Karena","Nephele","Scylla","Ursa", // Latin "Alcestis","Damaris","Elisavet","Khthonia","Teodora", // Greek @@ -114,57 +112,57 @@ /datum/antagonist/bloodsucker/proc/SelectTitle(am_fledgling = 0, forced = FALSE) // Already have Title - if (!forced && vamptitle != null) + if(!forced && bloodsucker_title != null) return // Titles [Master] - if (!am_fledgling) + if(!am_fledgling) if(owner.current.gender == MALE) - vamptitle = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master") + bloodsucker_title = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master") else - vamptitle = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress") + bloodsucker_title = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress") to_chat(owner, "You have earned a title! You are now known as [ReturnFullName(TRUE)]!") // Titles [Fledgling] else - vamptitle = null + bloodsucker_title = null /datum/antagonist/bloodsucker/proc/SelectReputation(am_fledgling = 0, forced=FALSE) // Already have Reputation - if(!forced && vampreputation != null) + if(!forced && bloodsucker_reputation != null) return // Reputations [Master] if(!am_fledgling) - vampreputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \ + bloodsucker_reputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \ "Inqisitor","Harvester","Reviled","Robust","Betrayer","Destructor","Damned","Accursed","Terrible","Vicious","Profane","Vile","Depraved","Foul","Slayer","Manslayer","Sovereign","Slaughterer", \ "Forsaken","Mad","Dragon","Savage","Villainous","Nefarious","Inquisitor","Marauder","Horrible","Immortal","Undying","Overlord","Corrupt","Hellspawn","Tyrant","Sanguineous") if(owner.current.gender == MALE) if(prob(10)) // Gender override - vampreputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King") + bloodsucker_reputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King") else if(prob(10)) // Gender override - vampreputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen") + bloodsucker_reputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen") to_chat(owner, "You have earned a reputation! You are now known as [ReturnFullName(TRUE)]!") // Reputations [Fledgling] else - vampreputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\ + bloodsucker_reputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\ "Unspoiled","Disgraced","Defrocked","Shamed","Meek","Timid","Broken")//,"Fresh") /datum/antagonist/bloodsucker/proc/AmFledgling() - return !vamptitle + return !bloodsucker_title /datum/antagonist/bloodsucker/proc/ReturnFullName(var/include_rep=0) var/fullname // Name First - fullname = (vampname ? vampname : owner.current.name) + fullname = (bloodsucker_name ? bloodsucker_name : owner.current.name) // Title - if(vamptitle) - fullname = vamptitle + " " + fullname + if(bloodsucker_title) + fullname = bloodsucker_title + " " + fullname // Rep - if(include_rep && vampreputation) - fullname = fullname + " the " + vampreputation + if(include_rep && bloodsucker_reputation) + fullname = fullname + " the " + bloodsucker_reputation return fullname @@ -199,15 +197,12 @@ var/mob/living/carbon/human/H = owner.current var/datum/species/S = H.dna.species // Make Changes - H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank! + H.physiology.brute_mod *= 0.8 H.physiology.cold_mod = 0 H.physiology.stun_mod *= 0.5 H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1 - //S.heatmod += 0.5 // Heat shouldn't affect. Only Fire. - //S.punchstunthreshold = 8 //damage at which punches from this race will stun 9 S.punchdamagelow += 1 //lowest possible punch damage 0 S.punchdamagehigh += 1 //highest possible punch damage 9 - // Clown if(istype(H) && owner.assigned_role == "Clown") H.dna.remove_mutation(CLOWNMUT) to_chat(H, "As a vampiric clown, you are no longer a danger to yourself. Your nature is subdued.") @@ -215,8 +210,6 @@ CheckVampOrgans() // Heart, Eyes // Language owner.current.grant_language(/datum/language/vampiric) - // Soul - //owner.current.hellbound = TRUE Causes wierd stuff owner.hasSoul = FALSE // If false, renders the character unable to sell their soul. owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles // Disabilities @@ -248,7 +241,6 @@ // Clown if(istype(H) && owner.assigned_role == "Clown") H.dna.add_mutation(CLOWNMUT) - // NOTE: Use initial() to return things to default! // Physiology owner.current.regenerate_organs() // Update Health @@ -264,13 +256,13 @@ set waitfor = FALSE if(!owner || !owner.current) return - vamplevel_unspent ++ + bloodsucker_level_unspent ++ // Spend Rank Immediately? if(istype(owner.current.loc, /obj/structure/closet/crate/coffin)) SpendRank() else to_chat(owner, "You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.") - if(vamplevel_unspent >= 2) + if(bloodsucker_level_unspent >= 2) to_chat(owner, "Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.
") /datum/antagonist/bloodsucker/proc/LevelUpPowers() @@ -279,10 +271,10 @@ /datum/antagonist/bloodsucker/proc/SpendRank() set waitfor = FALSE - if(vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current)) + if(bloodsucker_level_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current)) return var/mob/living/L = owner.current - level_bloodcost = maxBloodVolume * 0.2 + level_bloodcost = max_blood_volume * 0.2 //If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker //TODO: Make this into a radial, or perhaps a tgui next UI @@ -298,7 +290,7 @@ if(options.len > 1) var/choice = input(owner.current, "You have the opportunity to grow more ancient at the cost of [level_bloodcost] units of blood. Select a power to advance your Rank.", "Your Blood Thickens...") in options // Cheat-Safety: Can't keep opening/closing coffin to spam levels - if(vamplevel_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal. + if(bloodsucker_level_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal. return if(!istype(owner.current.loc, /obj/structure/closet/crate/coffin)) to_chat(owner.current, "Return to your coffin to advance your Rank.") @@ -329,20 +321,20 @@ // More Health owner.current.setMaxHealth(owner.current.maxHealth + 10) // Vamp Stats - regenRate += 0.05 // Points of brute healed (starts at 0.3) - feedAmount += 2 // Increase how quickly I munch down vics (15) - maxBloodVolume += 100 // Increase my max blood (600) + regen_rate += 0.05 // Points of brute healed (starts at 0.3) + feed_amount += 2 // Increase how quickly I munch down vics (15) + max_blood_volume += 100 // Increase my max blood (600) ///////// - vamplevel ++ - vamplevel_unspent -- + bloodsucker_level ++ + bloodsucker_level_unspent -- // Assign True Reputation - if(vamplevel == 4) + if(bloodsucker_level == 4) SelectReputation(am_fledgling = FALSE, forced = TRUE) - to_chat(owner.current, "You are now a rank [vamplevel] Bloodsucker. Your strength, health, feed rate, regen rate, and maximum blood have all increased!") + to_chat(owner.current, "You are now a rank [bloodsucker_level] Bloodsucker. Your strength, health, feed rate, regen rate, can have up to [bloodsucker_level - count_vassals(owner.current.mind)] vassals, and maximum blood have all increased!") to_chat(owner.current, "Your existing powers have all ranked up as well!") update_hud(TRUE) - owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head. + owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, TRUE, pressure_affected = FALSE) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -654,13 +646,13 @@ var/datum/antagonist/vassal/mob_V = M.mind.has_antag_datum(ANTAG_DATUM_VASSAL) // Check 2) If they are a BLOODSUCKER, then are they my Master? if (mob_V && atom_B == mob_V.master) - return TRUE // SUCCESS! + return TRUE // Check 3) If I am a BLOODSUCKER, then are they my Vassal? if (mob_B && atom_V && (atom_V in mob_B.vassals)) - return TRUE // SUCCESS! + return TRUE // Check 4) If we are both VASSAL, then do we have the same master? if (atom_V && mob_V && atom_V.master == mob_V.master) - return TRUE // SUCCESS! + return TRUE return FALSE @@ -705,10 +697,10 @@ // Update Rank Counter if(owner.current.hud_used.vamprank_display) - var/valuecolor = vamplevel_unspent ? "#FFFF00" : "#FF0000" - owner.current.hud_used.vamprank_display.update_counter(vamplevel, valuecolor) + var/valuecolor = bloodsucker_level_unspent ? "#FFFF00" : "#FF0000" + owner.current.hud_used.vamprank_display.update_counter(bloodsucker_level, valuecolor) if(updateRank) // Only change icon on special request. - owner.current.hud_used.vamprank_display.icon_state = (vamplevel_unspent > 0) ? "rank_up" : "rank" + owner.current.hud_used.vamprank_display.icon_state = (bloodsucker_level_unspent > 0) ? "rank_up" : "rank" /obj/screen/bloodsucker @@ -718,12 +710,12 @@ invisibility = INVISIBILITY_ABSTRACT /obj/screen/bloodsucker/proc/update_counter(value, valuecolor) - invisibility = 0 // Make Visible + invisibility = 0 -/obj/screen/bloodsucker/blood_counter // NOTE: Look up /obj/screen/devil/soul_counter in _onclick / hud / human.dm - icon = 'icons/mob/actions/bloodsucker.dmi'//'icons/mob/screen_gen.dmi' +/obj/screen/bloodsucker/blood_counter + icon = 'icons/mob/actions/bloodsucker.dmi' name = "Blood Consumed" - icon_state = "blood_display"//"power_display" + icon_state = "blood_display" screen_loc = ui_blood_display /obj/screen/bloodsucker/blood_counter/update_counter(value, valuecolor) @@ -748,22 +740,27 @@ /datum/antagonist/bloodsucker/proc/update_sunlight(value, amDay = FALSE) // No Hud? Get out. - if (!owner.current.hud_used) + if(!owner.current.hud_used) return // Update Sun Time - if (owner.current.hud_used.sunlight_display) + if(owner.current.hud_used.sunlight_display) var/valuecolor = "#BBBBFF" - if (amDay) + if(amDay) valuecolor = "#FF5555" else if(value <= 25) valuecolor = "#FFCCCC" else if(value < 10) valuecolor = "#FF5555" - var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value,1)] s" + var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value, 1)] s" owner.current.hud_used.sunlight_display.update_counter( value_string, valuecolor ) owner.current.hud_used.sunlight_display.icon_state = "sunlight_" + (amDay ? "day":"night") /obj/screen/bloodsucker/sunlight_counter/update_counter(value, valuecolor) ..() - maptext = "
[value]
" + maptext = "
[value]
" + +/datum/antagonist/bloodsucker/proc/count_vassals(datum/mind/master) + var/datum/antagonist/bloodsucker/B = master.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + var/vassal_amount = B.vassals.len + return vassal_amount diff --git a/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm b/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm index e4e26fe034..640c53946f 100644 --- a/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm +++ b/code/modules/antagonists/bloodsucker/items/bloodsucker_organs.dm @@ -5,7 +5,8 @@ var/obj/item/organ/O // Heart O = owner.current.getorganslot(ORGAN_SLOT_HEART) - if(!istype(O, /obj/item/organ/heart/vampheart)) + + if(!istype(O, /obj/item/organ/heart/vampheart) && !istype(O, /obj/item/organ/heart/demon)) qdel(O) var/obj/item/organ/heart/vampheart/H = new H.Insert(owner.current) diff --git a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm index a8925dfb7b..7998a33c7b 100644 --- a/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm +++ b/code/modules/antagonists/bloodsucker/objects/bloodsucker_crypt.dm @@ -115,13 +115,15 @@ qdel(src) /obj/structure/bloodsucker/vassalrack/examine(mob/user) + var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) . = ..() - if(isvamp(user) || isobserver(user)) + if(B || isobserver(user)) . += {"This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service."} . += {"You need to first secure the vassal rack by clicking on it while it is in your lair."} . += {"Simply click and hold on a victim, and then drag their sprite on the vassal rack. Alt click on the vassal rack to unbuckle them."} . += {"Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant."} . += {"To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools."} + . += {" You have only the power for [B.bloodsucker_level - B.count_vassals(user.mind)] vassals"} /* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL) . += {"This is the vassal rack, which allows your master to thrall crewmembers into his minions.\n Aid your master in bringing their victims here and keeping them secure.\n @@ -130,7 +132,7 @@ /obj/structure/bloodsucker/vassalrack/MouseDrop_T(atom/movable/O, mob/user) if(!O.Adjacent(src) || O == user || !isliving(O) || !isliving(user) || useLock || has_buckled_mobs() || user.incapacitated()) return - if(!anchored && isvamp(user)) + if(!anchored && AmBloodsucker(user)) to_chat(user, "Until this rack is secured in place, it cannot serve its purpose.") return // PULL TARGET: Remember if I was pullin this guy, so we can restore this @@ -183,7 +185,7 @@ /obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/M, mob/user) // Attempt Unbuckle - if(!isvamp(user)) + if(!AmBloodsucker(user)) if(M == user) M.visible_message("[user] tries to release themself from the rack!",\ "You attempt to release yourself from the rack!") // For sound if not seen --> "You hear a squishy wet noise.") @@ -222,15 +224,15 @@ // Go away. Torturing. if(useLock) return - var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) // CHECK ONE: Am I claiming this? Is it in the right place? - if(istype(bloodsuckerdatum) && !owner) - if(!bloodsuckerdatum.lair) + if(istype(B) && !owner) + if(!B.lair) to_chat(user, "You don't have a lair. Claim a coffin to make that location your lair.") - if(bloodsuckerdatum.lair != get_area(src)) - to_chat(user, "You may only activate this structure in your lair: [bloodsuckerdatum.lair].") + if(B.lair != get_area(src)) + to_chat(user, "You may only activate this structure in your lair: [B.lair].") return - switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore","Secure [src]","Yes", "No")) + switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore", "Secure [src]", "Yes", "No")) if("Yes") owner = user density = FALSE @@ -241,27 +243,31 @@ return // CHECK TWO: Am I a non-bloodsucker? var/mob/living/carbon/C = pick(buckled_mobs) - if(!istype(bloodsuckerdatum)) + if(!istype(B)) // Try to release this guy user_unbuckle_mob(C, user) return // Bloodsucker Owner! Let the boy go. if(C.mind) - var/datum/antagonist/vassal/vassaldatum = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL) - if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD) + var/datum/antagonist/vassal/V = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL) + if(istype(V) && V.master == B || C.stat >= DEAD) unbuckle_mob(C) useLock = FALSE // Failsafe return // Just torture the boy torture_victim(user, C) +#define CONVERT_COST 150 + /obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target) - var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) + var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) // Check Bloodmob/living/M, force = FALSE, check_loc = TRUE - var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals - if(user.blood_volume < convert_cost + 5) + if(user.blood_volume < CONVERT_COST + 5) to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target].") return + if(B.count_vassals(user.mind) > B.bloodsucker_level) + to_chat(user, "Your power is yet too weak to bring more vassals under your control....") + return // Prep... useLock = TRUE // Step One: Tick Down Conversion from 3 to 0 @@ -302,12 +308,13 @@ useLock = FALSE return // Check: Blood - if(user.blood_volume < convert_cost) - to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!") + if(user.blood_volume < CONVERT_COST) + to_chat(user, "You don't have enough blood to initiate the Dark Communion with [target], you need [CONVERT_COST - user.blood_volume] units more!") useLock = FALSE return - bloodsuckerdatum.AddBloodVolume(-convert_cost) - target.add_mob_blood(user) + B.AddBloodVolume(-CONVERT_COST) + target.add_mob_blood(user, "Youve used [CONVERT_COST] amount of blood to gain a new vassal!") + to_chat(user, ) user.visible_message("[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!", \ "You paint a bloody marking across [target]'s forehead, place your wrist to [target.p_their()] mouth, and subject [target.p_them()] to the Dark Communion.") if(!do_mob(user, src, 50)) @@ -315,21 +322,22 @@ useLock = FALSE return // Convert to Vassal! - if(bloodsuckerdatum && bloodsuckerdatum.attempt_turn_vassal(target)) + if(B && B.attempt_turn_vassal(target)) //remove_loyalties(target) // In case of Mindshield, or appropriate Antag (Traitor, Internal, etc) //if (!target.buckled) // to_chat(user, "The ritual has been interrupted!") // useLock = FALSE // return - user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head. - target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head. - target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head. + user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE) + target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE) + target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE) target.Jitter(25) target.emote("laugh") //remove_victim(target) // Remove on CLICK ONLY! useLock = FALSE -/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult=1) +#undef CONVERT_COST +/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult = 1) var/torture_time = 15 // Fifteen seconds if you aren't using anything. Shorter with weapons and such. var/torture_dmg_brute = 2 var/torture_dmg_burn = 0 @@ -454,7 +462,7 @@ /obj/structure/bloodsucker/candelabrum/examine(mob/user) . = ..() - if((isvamp()) || isobserver(user)) + if((AmBloodsucker(user)) || isobserver(user)) . += {"This is a magical candle which drains at the sanity of mortals who are not under your command while it is active."} . += {"You can alt click on it from any range to turn it on remotely, or simply be next to it and click on it to turn it on and off normally."} /* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL) @@ -463,12 +471,12 @@ /obj/structure/bloodsucker/candelabrum/attack_hand(mob/user) var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL) - if(isvamp(user) || istype(T)) + if(AmBloodsucker(user) || istype(T)) toggle() /obj/structure/bloodsucker/candelabrum/AltClick(mob/user) // Bloodsuckers can turn their candles on from a distance. SPOOOOKY. - if(isvamp(user)) + if(AmBloodsucker(user)) toggle() /obj/structure/bloodsucker/candelabrum/proc/toggle(mob/user) @@ -485,7 +493,7 @@ if(lit) for(var/mob/living/carbon/human/H in viewers(7, src)) var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL) - if(isvamp(H) || T) //We dont want vassals or vampires affected by this + if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this return H.hallucination = 20 SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vampcandle", /datum/mood_event/vampcandle) diff --git a/code/modules/antagonists/bloodsucker/powers/cloak.dm b/code/modules/antagonists/bloodsucker/powers/cloak.dm index 1bb7b02357..a616c39923 100644 --- a/code/modules/antagonists/bloodsucker/powers/cloak.dm +++ b/code/modules/antagonists/bloodsucker/powers/cloak.dm @@ -2,7 +2,7 @@ /datum/action/bloodsucker/cloak name = "Cloak of Darkness" - desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas." + desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas, and you cannot dissapear while mortals watch you." button_icon_state = "power_cloak" bloodcost = 5 cooldown = 50 diff --git a/code/modules/antagonists/bloodsucker/powers/feed.dm b/code/modules/antagonists/bloodsucker/powers/feed.dm index bbce221d91..8ac4fcebc1 100644 --- a/code/modules/antagonists/bloodsucker/powers/feed.dm +++ b/code/modules/antagonists/bloodsucker/powers/feed.dm @@ -140,7 +140,7 @@ to_chat(user, "You lean quietly toward [target] and secretly draw out your fangs...") else to_chat(user, "You pull [target] close to you and draw out your fangs...") - if(!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10) + if(!do_mob(user, target, feed_time, 0, 1, extra_checks = CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10) to_chat(user, "Your feeding was interrupted.") //DeactivatePower(user,target) return @@ -166,7 +166,7 @@ var/deadmessage = target.stat == DEAD ? "" : " [target.p_they(TRUE)] looks dazed, and will not remember this." user.visible_message("[user] puts [target]'s wrist up to [user.p_their()] mouth.", \ "You secretly slip your fangs into [target]'s wrist.[deadmessage]", \ - vision_distance = notice_range, ignored_mobs=target) // Only people who AREN'T the target will notice this action. + vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action. // Warn Feeder about Witnesses... var/was_unnoticed = TRUE for(var/mob/living/M in viewers(notice_range, owner)) @@ -257,11 +257,11 @@ to_chat(user, "Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.") warning_target_dead = TRUE // Full? - if(!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume) + if(!warning_full && user.blood_volume >= bloodsuckerdatum.max_blood_volume) to_chat(user, "You are full. Further blood will be wasted.") warning_full = TRUE // Blood Remaining? (Carbons/Humans only) - if(iscarbon(target) && !target.AmBloodsucker(1)) + if(iscarbon(target) && !AmBloodsucker(target, TRUE)) if(target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD) to_chat(user, "Your victim's blood volume is fatally low!") else if(target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY) @@ -275,8 +275,9 @@ break // Blood Gulp Sound - owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head. - + owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE) + if(!amSilent) + target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE) // DONE! //DeactivatePower(user,target) if(amSilent) @@ -294,12 +295,12 @@ /datum/action/bloodsucker/feed/proc/CheckKilledTarget(mob/living/user, mob/living/target) - // Bad Vampire. You shouldn't do that. + // Bad Bloodsucker. You shouldn't do that. if(target && target.stat >= DEAD && ishuman(target)) SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankkilled", /datum/mood_event/drankkilled) // BAD // in bloodsucker_life.dm /datum/action/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target) - return ..() && target && (!target_grappled || user.pulling == target)// Active, and still Antag, + return ..() && target && (!target_grappled || user.pulling == target) && blood_sucking_checks(target, TRUE, TRUE) // Active, and still antag, // NOTE: We only care about pulling if target started off that way. Mostly only important for Aggressive feed. /datum/action/bloodsucker/feed/proc/ApplyVictimEffects(mob/living/target) diff --git a/code/modules/antagonists/bloodsucker/powers/fortitude.dm b/code/modules/antagonists/bloodsucker/powers/fortitude.dm index f0724f8204..a58034df0d 100644 --- a/code/modules/antagonists/bloodsucker/powers/fortitude.dm +++ b/code/modules/antagonists/bloodsucker/powers/fortitude.dm @@ -33,6 +33,15 @@ if(was_running) user.toggle_move_intent() while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN) + if(istype(user.buckled, /obj/vehicle)) //We dont want people using fortitude being able to use vehicles + var/obj/vehicle/V = user.buckled + var/datum/component/riding/VRD = V.GetComponent(/datum/component/riding) + if(VRD) + VRD.force_dismount(user) + to_chat(user, "You trip off the [V], your muscles too heavy for it to support you.") + else + V.unbuckle_mob(user, force = TRUE) + to_chat(user, "You fall off the [V], your weight making you too heavy to be supported by it.") // Pay Blood Toll (if awake) if(user.stat == CONSCIOUS) bloodsuckerdatum.AddBloodVolume(-0.5) // Used to be 0.3 blood per 2 seconds, but we're making it more expensive to keep on. diff --git a/code/modules/antagonists/bloodsucker/powers/haste.dm b/code/modules/antagonists/bloodsucker/powers/haste.dm index 143950b32f..05e2cd0330 100644 --- a/code/modules/antagonists/bloodsucker/powers/haste.dm +++ b/code/modules/antagonists/bloodsucker/powers/haste.dm @@ -8,7 +8,7 @@ desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed." button_icon_state = "power_speed" bloodcost = 6 - cooldown = 50 + cooldown = 120 target_range = 15 power_activates_immediately = TRUE message_Trigger = ""//"Whom will you subvert to your will?" diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm index 574edf225a..aa45c56892 100644 --- a/code/modules/antagonists/changeling/changeling_power.dm +++ b/code/modules/antagonists/changeling/changeling_power.dm @@ -28,8 +28,7 @@ action.Remove(user) return -/obj/effect/proc_holder/changeling/Click() - var/mob/user = usr +/obj/effect/proc_holder/changeling/Trigger(mob/user) if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling)) return try_to_sting(user) diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm index 3e19ce74fe..a8fe56aae7 100644 --- a/code/modules/antagonists/changeling/powers/tiny_prick.dm +++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm @@ -3,8 +3,7 @@ desc = "Stabby stabby." var/sting_icon = null -/obj/effect/proc_holder/changeling/sting/Click() - var/mob/user = usr +/obj/effect/proc_holder/changeling/sting/Trigger(mob/user) if(!user || !user.mind) return var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) @@ -74,8 +73,7 @@ action_icon_state = "ling_sting_transform" action_background_icon_state = "bg_ling" -/obj/effect/proc_holder/changeling/sting/transformation/Click() - var/mob/user = usr +/obj/effect/proc_holder/changeling/sting/transformation/Trigger(mob/user) var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) if(changeling.chosen_sting) unset_sting(user) diff --git a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm index 37f6f0b2d7..0c01dc0963 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm @@ -35,7 +35,7 @@ var/span_for_name = "heavy_brass" var/span_for_message = "brass" -/datum/action/innate/hierophant/IsAvailable() +/datum/action/innate/hierophant/IsAvailable(silent = FALSE) if(!is_servant_of_ratvar(owner)) return FALSE return ..() diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm index a87767c05e..40aca961fc 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm @@ -12,7 +12,7 @@ var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create var/obj/item/clockwork/weapon/weapon -/datum/action/innate/call_weapon/IsAvailable() +/datum/action/innate/call_weapon/IsAvailable(silent = FALSE) if(!is_servant_of_ratvar(owner)) qdel(src) return diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm index 6e7d830db6..5837ac302d 100644 --- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm +++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm @@ -121,8 +121,8 @@ . = ..() addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later -/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(isinhands && item_state && inhand_overlay) var/mutable_appearance/M = mutable_appearance(icon_file, "slab_[inhand_overlay]") . += M diff --git a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm index e4722dbcb0..faa5e025ca 100644 --- a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm +++ b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm @@ -232,7 +232,7 @@ background_icon_state = "bg_clock" buttontooltipstyle = "clockcult" -/datum/action/innate/eminence/IsAvailable() +/datum/action/innate/eminence/IsAvailable(silent = FALSE) if(!iseminence(owner)) qdel(src) return @@ -283,7 +283,7 @@ desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once." button_icon_state = "Spatial Gateway" -/datum/action/innate/eminence/mass_recall/IsAvailable() +/datum/action/innate/eminence/mass_recall/IsAvailable(silent = FALSE) . = ..() if(.) var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm index d6296aeaa0..130fc24583 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm @@ -153,7 +153,7 @@ /obj/item/clothing/head/helmet/space, /obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up -/datum/action/innate/clockwork_armaments/IsAvailable() +/datum/action/innate/clockwork_armaments/IsAvailable(silent = FALSE) if(!is_servant_of_ratvar(owner)) qdel(src) return diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index bea86d8bb4..d64e99d206 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -17,7 +17,7 @@ qdel(X) ..() -/datum/action/innate/cult/blood_magic/IsAvailable() +/datum/action/innate/cult/blood_magic/IsAvailable(silent = FALSE) if(!iscultist(owner)) return FALSE return ..() @@ -118,7 +118,7 @@ hand_magic = null ..() -/datum/action/innate/cult/blood_spell/IsAvailable() +/datum/action/innate/cult/blood_spell/IsAvailable(silent = FALSE) if(!iscultist(owner) || owner.incapacitated() || !charges) return FALSE return ..() diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index 8021443217..77893225fa 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -6,7 +6,7 @@ buttontooltipstyle = "cult" check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS -/datum/action/innate/cult/IsAvailable() +/datum/action/innate/cult/IsAvailable(silent = FALSE) if(!iscultist(owner)) return FALSE return ..() @@ -51,7 +51,7 @@ name = "Spiritual Communion" desc = "Conveys a message from the spirit realm that all cultists can hear." -/datum/action/innate/cult/comm/spirit/IsAvailable() +/datum/action/innate/cult/comm/spirit/IsAvailable(silent = FALSE) if(iscultist(owner.mind.current)) return TRUE @@ -72,7 +72,7 @@ name = "Assert Leadership" button_icon_state = "cultvote" -/datum/action/innate/cult/mastervote/IsAvailable() +/datum/action/innate/cult/mastervote/IsAvailable(silent = FALSE) var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE) if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner)) return FALSE @@ -140,7 +140,7 @@ to_chat(B.current,"[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!") return TRUE -/datum/action/innate/cult/master/IsAvailable() +/datum/action/innate/cult/master/IsAvailable(silent = FALSE) if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master) || GLOB.cult_narsie) return 0 return ..() @@ -226,9 +226,9 @@ CM.attached_action = src ..() -/datum/action/innate/cult/master/cultmark/IsAvailable() +/datum/action/innate/cult/master/cultmark/IsAvailable(silent = FALSE) if(cooldown > world.time) - if(!CM.active) + if(!CM.active && !silent) to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!") return FALSE return ..() @@ -308,7 +308,7 @@ name = "Mark a Blood Target for the Cult" desc = "Marks a target for the entire cult to track." -/datum/action/innate/cult/master/cultmark/ghost/IsAvailable() +/datum/action/innate/cult/master/cultmark/ghost/IsAvailable(silent = FALSE) if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current)) return TRUE else @@ -322,7 +322,7 @@ var/cooldown = 0 var/base_cooldown = 600 -/datum/action/innate/cult/ghostmark/IsAvailable() +/datum/action/innate/cult/ghostmark/IsAvailable(silent = FALSE) if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current)) return TRUE else @@ -401,11 +401,11 @@ PM.attached_action = src ..() -/datum/action/innate/cult/master/pulse/IsAvailable() +/datum/action/innate/cult/master/pulse/IsAvailable(silent = FALSE) if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master)) return FALSE if(cooldown > world.time) - if(!PM.active) + if(!PM.active && !silent) to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!") return FALSE return ..() diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 11c0e9ade5..b05aa7f769 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -222,7 +222,7 @@ phasein = /obj/effect/temp_visual/dir_setting/cult/phase phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out -/datum/action/innate/dash/cult/IsAvailable() +/datum/action/innate/dash/cult/IsAvailable(silent = FALSE) if(iscultist(holder) && current_charges) return TRUE else @@ -242,7 +242,7 @@ sword = bastard holder = user -/datum/action/innate/cult/spin2win/IsAvailable() +/datum/action/innate/cult/spin2win/IsAvailable(silent = FALSE) if(iscultist(holder) && cooldown <= world.time) return TRUE else @@ -451,8 +451,8 @@ return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL return BLOCK_NONE -/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands && current_charges) . += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01) diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm index 60a8527860..b164246060 100644 --- a/code/modules/antagonists/cult/rune_spawn_action.dm +++ b/code/modules/antagonists/cult/rune_spawn_action.dm @@ -14,7 +14,7 @@ var/obj/effect/temp_visual/cult/rune_spawn/rune_center_type var/rune_color -/datum/action/innate/cult/create_rune/IsAvailable() +/datum/action/innate/cult/create_rune/IsAvailable(silent = FALSE) if(!rune_type || cooldown > world.time) return FALSE return ..() diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm index 724c4e6f76..c1f493ac52 100644 --- a/code/modules/antagonists/swarmer/swarmer.dm +++ b/code/modules/antagonists/swarmer/swarmer.dm @@ -179,8 +179,8 @@ /obj/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) if(resistance_flags & INDESTRUCTIBLE) return FALSE - for(var/mob/living/L in contents) - if(!issilicon(L) && !isbrain(L)) + for(var/mob/living/L in GetAllContents()) + if(!ispAI(L) && !isbrain(L)) to_chat(S, "An organism has been detected inside this object. Aborting.") return FALSE return ..() @@ -416,6 +416,57 @@ to_chat(S, "Destroying this object would cause a catastrophic chain reaction. Aborting.") return FALSE +/obj/machinery/ore_silo/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "Destroying this object, however tempting it's, will disrupt the research development that may serve for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/rnd/server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "Destroying this object, will disrupt the research development that may serve for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) //pool's closed, but not. + to_chat(S, "The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.") + return FALSE + +/obj/structure/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.") + return FALSE + +/obj/structure/holosign/barrier/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + var/static/list/lazy_typecache = typecacheof(list(/obj/structure/holosign/barrier/engineering, /obj/structure/holosign/barrier/firelock, /obj/structure/holosign/barrier/atmos, /obj/structure/holosign/barrier/combifan)) + if(lazy_typecache[type]) + to_chat(S, "Destroying this holographic barrier may not benefit us. Aborting.") + return FALSE + return ..() + +/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "This advanced piece of technology may be of use for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/computer/bsa_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "This advanced piece of technology may be of use for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/bsa/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "This advanced piece of technology may be of use for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/dna_vault/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "This advanced piece of technology may be of use for our masters in the future. Aborting.") + return FALSE + +/obj/structure/filler/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "This advanced piece of technology may be of use for our masters in the future. Aborting.") + return FALSE + +/obj/machinery/computer/sat_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "Destroying this object will lower the station shielding against space debris. Aborting.") + return FALSE + +/obj/machinery/satellite/meteor_shield/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + to_chat(S, "Destroying this object will lower the station shielding against space debris. Aborting.") + return FALSE + ////END CTRL CLICK FOR SWARMERS//// /mob/living/simple_animal/hostile/swarmer/proc/Fabricate(atom/fabrication_object,fabrication_cost = 0) @@ -429,6 +480,14 @@ return new fabrication_object(loc) /mob/living/simple_animal/hostile/swarmer/proc/Integrate(atom/movable/target) + if(isobj(target)) + var/obj/O = target + if(O.resistance_flags & INDESTRUCTIBLE) + return FALSE + for(var/mob/living/L in GetAllContents()) + if(!ispAI(L) && !isbrain(L)) + to_chat(src, "An organism has been detected inside this object. Aborting.") + return FALSE var/resource_gain = target.IntegrateAmount() if(resources + resource_gain > max_resources) to_chat(src, "We cannot hold more materials!") diff --git a/code/modules/antagonists/swarmer/swarmer_event.dm b/code/modules/antagonists/swarmer/swarmer_event.dm index 6ef35fdbaa..c626799a53 100644 --- a/code/modules/antagonists/swarmer/swarmer_event.dm +++ b/code/modules/antagonists/swarmer/swarmer_event.dm @@ -1,10 +1,10 @@ /datum/round_event_control/spawn_swarmer name = "Spawn Swarmer Shell" typepath = /datum/round_event/spawn_swarmer - weight = 0 - max_occurrences = 0 + weight = 7 + max_occurrences = 1 //Only once okay fam earliest_start = 30 MINUTES - min_players = 15 + min_players = 35 gamemode_blacklist = list("dynamic") diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index e6ca95472e..6616eea006 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( else owner_AI = owner -/datum/action/innate/ai/IsAvailable() +/datum/action/innate/ai/IsAvailable(silent = FALSE) . = ..() if(owner_AI && owner_AI.malf_cooldown > world.time) return FALSE diff --git a/code/modules/cargo/packs/science.dm b/code/modules/cargo/packs/science.dm index a3548a5eb6..6b4733aad8 100644 --- a/code/modules/cargo/packs/science.dm +++ b/code/modules/cargo/packs/science.dm @@ -74,10 +74,9 @@ /datum/supply_pack/science/circuitry name = "Circuitry Starter Pack Crate" - desc = "Journey into the mysterious world of Circuitry with this starter pack. Contains a circuit printer, analyzer, debugger and wirer. Power cells not included." + desc = "Journey into the mysterious world of Circuitry with this starter pack. Contains a circuit printer, debugger and wirer. Power cells not included." cost = 1000 - contains = list(/obj/item/integrated_electronics/analyzer, - /obj/item/integrated_circuit_printer, + contains = list(/obj/item/integrated_circuit_printer, /obj/item/integrated_electronics/debugger, /obj/item/integrated_electronics/wirer) crate_name = "circuitry starter pack crate" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index adfcd547bc..f7d251f32d 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -150,7 +150,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) "ipc_antenna" = "None", "flavor_text" = "", "meat_type" = "Mammalian", - "body_model" = MALE + "body_model" = MALE, + "body_size" = RESIZE_DEFAULT_SIZE ) var/list/custom_names = list() @@ -294,7 +295,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "[real_name]
" dat += "Be nameless: [nameless ? "Yes" : "No"]
" - dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" dat += "Age: [age]
" dat += "Special Names:
" @@ -345,7 +346,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) else dat += "[TextPreview(features["flavor_text"])]...
" dat += "

Body

" - dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" if(gender != NEUTER && pref_species.sexes) dat += "Body Model:[features["body_model"] == MALE ? "Masculine" : "Feminine"]
" dat += "Species:[pref_species.name]
" @@ -379,6 +380,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "    Change
" mutant_colors = TRUE + if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max)) + dat += "Sprite Size: [features["body_size"]]%
" + if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits)) if(!use_skintones && !mutant_colors) @@ -2119,6 +2123,38 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_toggle_color) hud_toggle_color = new_toggle_color + if("gender") + var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object") + if(!chosengender) + return + switch(chosengender) + if("nonbinary") + chosengender = PLURAL + features["body_model"] = pick(MALE, FEMALE) + if("object") + chosengender = NEUTER + features["body_model"] = MALE + else + features["body_model"] = chosengender + gender = chosengender + facial_hair_style = random_facial_hair_style(gender) + hair_style = random_hair_style(gender) + + if("body_size") + var/min = CONFIG_GET(number/body_size_min) + var/max = CONFIG_GET(number/body_size_max) + var/danger = CONFIG_GET(number/threshold_body_size_slowdown) + var/new_body_size = input(user, "Choose your desired sprite size:\n([min*100]%-[max*100]%), Warning: May make your character look distorted[danger > min ? ", and an exponential slowdown will occur for those smaller than [danger*100]%!" : "!"]", "Character Preference", features["body_size"]*100) as num|null + if (new_body_size) + new_body_size = CLAMP(new_body_size * 0.01, min, max) + var/dorfy + if(danger > new_body_size) + dorfy = alert(user, "The chosen size appears to be smaller than the threshold of [danger*100]%, which will lead to an added exponential slowdown. Are you sure about that?", "Dwarfism Alert", "Yes", "Move it to the threshold", "No") + if(!dorfy || dorfy == "Move it above the threshold") + new_body_size = danger + if(dorfy != "No") + features["body_size"] = new_body_size + else switch(href_list["preference"]) //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj @@ -2171,22 +2207,6 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("publicity") if(unlock_content) toggles ^= MEMBER_PUBLIC - if("gender") - var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object") - if(!chosengender) - return - switch(chosengender) - if("nonbinary") - chosengender = PLURAL - features["body_model"] = pick(MALE, FEMALE) - if("object") - chosengender = NEUTER - features["body_model"] = MALE - else - features["body_model"] = chosengender - gender = chosengender - facial_hair_style = random_facial_hair_style(gender) - hair_style = random_hair_style(gender) if("body_model") features["body_model"] = features["body_model"] == MALE ? FEMALE : MALE @@ -2431,6 +2451,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) pref_species = new /datum/species/human save_character() + var/old_size = character.dna.features["body_size"] + character.dna.features = features.Copy() character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE) character.dna.real_name = character.real_name @@ -2452,6 +2474,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.give_genitals(TRUE) //character.update_genitals() is already called on genital.update_appearance() + character.dna.update_body_size(old_size) + SEND_SIGNAL(character, COMSIG_HUMAN_PREFS_COPIED_TO, src, icon_updates, roundstart_checks) //let's be sure the character updates diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index ca51a27dae..7da9d5a1dc 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -395,6 +395,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["body_is_always_random"] >> be_random_body S["gender"] >> gender S["body_model"] >> features["body_model"] + S["body_size"] >> features["body_size"] S["age"] >> age S["hair_color"] >> hair_color S["facial_hair_color"] >> facial_hair_color @@ -568,6 +569,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None") features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list) + var/static/size_min + if(!size_min) + size_min = CONFIG_GET(number/body_size_min) + var/static/size_max + if(!size_max) + size_max = CONFIG_GET(number/body_size_max) + features["body_size"] = sanitize_integer(features["body_size"], size_min, size_max, RESIZE_DEFAULT_SIZE) + var/static/list/B_sizes if(!B_sizes) var/list/L = CONFIG_GET(keyed_list/breasts_cups_prefs) @@ -643,6 +652,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["body_is_always_random"] , be_random_body) WRITE_FILE(S["gender"] , gender) WRITE_FILE(S["body_model"] , features["body_model"]) + WRITE_FILE(S["body_size"] , features["body_size"]) WRITE_FILE(S["age"] , age) WRITE_FILE(S["hair_color"] , hair_color) WRITE_FILE(S["facial_hair_color"] , facial_hair_color) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 402d16e7ec..d484027ad5 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -47,25 +47,12 @@ //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it. //You append this to clothing objects. - //Polychrome stuff: - var/hasprimary = FALSE //These vars allow you to choose which overlays a clothing has - var/hassecondary = FALSE - var/hastertiary = FALSE - var/primary_color = "#FFFFFF" //RGB in hexcode - var/secondary_color = "#FFFFFF" - var/tertiary_color = "#808080" - - //No idea what this is but eh -tori - var/force_alternate_icon = FALSE - /obj/item/clothing/Initialize() . = ..() if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE)) actions_types += /datum/action/item_action/toggle_voice_box if(ispath(pocket_storage_component_path)) LoadComponent(pocket_storage_component_path) - if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled - update_icon() //Applies the overlays and default colors onto the clothes on spawn. /obj/item/clothing/MouseDrop(atom/over_object) . = ..() @@ -150,8 +137,6 @@ how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n" how_cool_are_your_threads += "
" . += how_cool_are_your_threads.Join() - if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled - . += "Alt-click to recolor it." /obj/item/clothing/obj_break(damage_flag) if(!damaged_clothes) @@ -195,173 +180,6 @@ BLIND // can't see anything female_clothing_icon = fcopy_rsc(female_clothing_icon) GLOB.female_clothing_icons[index] = female_clothing_icon -/obj/item/clothing/under/verb/toggle() - set name = "Adjust Suit Sensors" - set category = "Object" - set src in usr - var/mob/M = usr - if (istype(M, /mob/dead/)) - return - if (!can_use(M)) - return - if(src.has_sensor == LOCKED_SENSORS) - to_chat(usr, "The controls are locked.") - return 0 - if(src.has_sensor == BROKEN_SENSORS) - to_chat(usr, "The sensors have shorted out!") - return 0 - if(src.has_sensor <= NO_SENSORS) - to_chat(usr, "This suit does not have any sensors.") - return 0 - - var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon") - var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes - if(get_dist(usr, src) > 1) - to_chat(usr, "You have moved too far away!") - return - sensor_mode = modes.Find(switchMode) - 1 - - if (src.loc == usr) - switch(sensor_mode) - if(0) - to_chat(usr, "You disable your suit's remote sensing equipment.") - if(1) - to_chat(usr, "Your suit will now only report whether you are alive or dead.") - if(2) - to_chat(usr, "Your suit will now only report your exact vital lifesigns.") - if(3) - to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") - - if(ishuman(loc)) - var/mob/living/carbon/human/H = loc - if(H.w_uniform == src) - H.update_suit_sensors() - - -/obj/item/clothing/under/CtrlClick(mob/user) - . = ..() - - if (!(item_flags & IN_INVENTORY)) - return - - if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) - return - - if(has_sensor == LOCKED_SENSORS) - to_chat(user, "The controls are locked.") - return - if(has_sensor == BROKEN_SENSORS) - to_chat(user, "The sensors have shorted out!") - return - if(has_sensor <= NO_SENSORS) - to_chat(user, "This suit does not have any sensors.") - return - - sensor_mode = SENSOR_COORDS - - to_chat(user, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.w_uniform == src) - H.update_suit_sensors() - -/obj/item/clothing/under/AltClick(mob/user) - . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) - return - if(attached_accessory) - remove_accessory(user) - else - rolldown() - // Polychrome stuff: - if(hasprimary | hassecondary | hastertiary) - var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays - switch(choice) //Lets the list's options actually lead to something - if("Primary Color") - var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it. - if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL. - primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly - update_icon() //updates the item icon - user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works. - if("Secondary Color") - var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null - if(secondary_color_input) - secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - if("Tertiary Color") - var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null - if(tertiary_color_input) - tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - return TRUE - -/obj/item/clothing/neck/AltClick(mob/user) - . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) - return - // Polychrome stuff: - if(hasprimary | hassecondary | hastertiary) - var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays - switch(choice) //Lets the list's options actually lead to something - if("Primary Color") - var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it. - if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL. - primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly - update_icon() //updates the item icon - user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works. - if("Secondary Color") - var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null - if(secondary_color_input) - secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - if("Tertiary Color") - var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null - if(tertiary_color_input) - tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - return TRUE - -/obj/item/clothing/under/verb/jumpsuit_adjust() - set name = "Adjust Jumpsuit Style" - set category = null - set src in usr - rolldown() - -/obj/item/clothing/under/proc/rolldown() - if(!can_use(usr)) - return - if(!can_adjust) - to_chat(usr, "You cannot wear this suit any differently!") - return - if(toggle_jumpsuit_adjust()) - to_chat(usr, "You adjust the suit to wear it more casually.") - else - to_chat(usr, "You adjust the suit back to normal.") - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - H.update_inv_w_uniform() - H.update_body() - -/obj/item/clothing/under/proc/toggle_jumpsuit_adjust() - adjusted = !adjusted - - if(adjusted) - if(fitted != FEMALE_UNIFORM_TOP) - fitted = NO_FEMALE_UNIFORM - if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted - body_parts_covered &= ~CHEST - else - fitted = initial(fitted) - if(!alt_covers_chest) - body_parts_covered |= CHEST - - return adjusted - /obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc. if(!can_use(user)) return FALSE @@ -441,15 +259,3 @@ BLIND // can't see anything return FALSE return TRUE - -/obj/item/clothing/update_overlays() // Polychrome stuff - . = ..() - if(hasprimary) //Checks if the overlay is enabled - var/mutable_appearance/primary_overlay = mutable_appearance(icon, "[item_state]-primary", color = primary_color) //Automagically picks overlays - . += primary_overlay //Applies the coloured overlay onto the item sprite. but NOT the mob sprite. - if(hassecondary) - var/mutable_appearance/secondary_overlay = mutable_appearance(icon, "[item_state]-secondary", color = secondary_color) - . += secondary_overlay - if(hastertiary) - var/mutable_appearance/tertiary_overlay = mutable_appearance(icon, "[item_state]-tertiary", color = tertiary_color) - . += tertiary_overlay diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index aff86f62f1..8cbc416b2e 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -346,8 +346,8 @@ add_atom_colour("#[user.eye_color]", FIXED_COLOUR_PRIORITY) colored_before = TRUE -/obj/item/clothing/glasses/sunglasses/blindfold/white/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/glasses/sunglasses/blindfold/white/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands && ishuman(loc) && !colored_before) var/mob/living/carbon/human/H = loc var/mutable_appearance/M = mutable_appearance('icons/mob/clothing/eyes.dmi', "blindfoldwhite") diff --git a/code/modules/clothing/glasses/phantomthief.dm b/code/modules/clothing/glasses/phantomthief.dm index 92eaaef35b..fecf660450 100644 --- a/code/modules/clothing/glasses/phantomthief.dm +++ b/code/modules/clothing/glasses/phantomthief.dm @@ -23,8 +23,8 @@ else . += "[DisplayTimeText(nextadrenalinepop - world.time)] left before the adrenaline injector can be used again." -/obj/item/clothing/glasses/phantomthief/syndicate/proc/injectadrenaline(mob/user, combatmodestate) - if(istype(user) && combatmodestate && world.time >= nextadrenalinepop) +/obj/item/clothing/glasses/phantomthief/syndicate/proc/injectadrenaline(mob/living/user, was_forced = FALSE) + if(user.combat_flags & COMBAT_FLAG_COMBAT_TOGGLED && world.time >= nextadrenalinepop) nextadrenalinepop = world.time + 5 MINUTES user.reagents.add_reagent(/datum/reagent/syndicateadrenals, 5) user.playsound_local(user, 'sound/misc/adrenalinject.ogg', 100, 0, pressure_affected = FALSE) diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 0729317eac..ddf5e4b584 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -26,8 +26,8 @@ user.visible_message("\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!") return OXYLOSS -/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index d599fbf6f7..475e7a4e51 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -48,8 +48,8 @@ -/obj/item/clothing/head/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/head/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet") diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 73e626bcd1..ffd50cbfbe 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -124,7 +124,7 @@ playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing update_icon() -/obj/item/clothing/head/hardhat/weldhat/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/clothing/head/hardhat/weldhat/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) . += mutable_appearance('icons/mob/clothing/head.dmi', "weldhelmet") diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 6ba58016f2..9c96223a6f 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -204,8 +204,8 @@ icon = S.icon icon_state = S.icon_state -/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style] if(!S) diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index 5019633cf0..7df38661e5 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -28,8 +28,8 @@ /obj/item/clothing/mask/proc/handle_speech() -/obj/item/clothing/mask/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/mask/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) if(body_parts_covered & HEAD) if(damaged_clothes) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 069ab43dd9..402ea37f21 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -6,8 +6,8 @@ strip_delay = 40 equip_delay_other = 40 -/obj/item/clothing/neck/worn_overlays(isinhands = FALSE, icon_flag, style_flags = NONE) - . = list() +/obj/item/clothing/neck/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) if(body_parts_covered & HEAD) if(damaged_clothes) @@ -169,54 +169,44 @@ name = "pet collar" desc = "It's for pets. Though you probably could wear it yourself, you'd doubtless be the subject of ridicule. It seems to be made out of a polychromic material." icon_state = "petcollar" - mob_overlay_icon = 'icons/mob/clothing/neck.dmi' //Because, as it appears, the item itself is normally not directly aware of its worn overlays, so this is about the easiest way, without adding a new var. - hasprimary = TRUE - primary_color = "#00BBBB" pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/collar + var/poly_states = 1 + var/poly_colors = list("#00BBBB") var/tagname = null + var/treat_path = /obj/item/reagent_containers/food/snacks/cookie + +/obj/item/clothing/neck/petcollar/Initialize() + . = ..() + if(treat_path) + new treat_path(src) + +/obj/item/clothing/neck/petcollar/ComponentInitialize() + . = ..() + if(!poly_states) + return + AddElement(/datum/element/polychromic, poly_colors, poly_states) /obj/item/clothing/neck/petcollar/attack_self(mob/user) tagname = stripped_input(user, "Would you like to change the name on the tag?", "Name your new pet", "Spot", MAX_NAME_LEN) name = "[initial(name)] - [tagname]" -/obj/item/clothing/neck/petcollar/worn_overlays(isinhands, icon_file, style_flags = NONE) - . = ..() - if(hasprimary | hassecondary | hastertiary) - if(!isinhands) //prevents the worn sprites from showing up if you're just holding them - if(hasprimary) //checks if overlays are enabled - var/mutable_appearance/primary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-primary") //automagical sprite selection - primary_worn.color = primary_color //colors the overlay - . += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite - if(hassecondary) - var/mutable_appearance/secondary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-secondary") - secondary_worn.color = secondary_color - . += secondary_worn - if(hastertiary) - var/mutable_appearance/tertiary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-tertiary") - tertiary_worn.color = tertiary_color - . += tertiary_worn - /obj/item/clothing/neck/petcollar/leather name = "leather pet collar" icon_state = "leathercollar" - - hasprimary = TRUE - hassecondary = TRUE - primary_color = "#222222" - secondary_color = "#888888" + poly_states = 2 + poly_colors = list("#222222", "#888888") /obj/item/clothing/neck/petcollar/choker desc = "Quite fashionable... if you're somebody who's just read their first BDSM-themed erotica novel." name = "choker" icon_state = "choker" - - hasprimary = TRUE - primary_color = "#222222" + poly_colors = list("#222222") /obj/item/clothing/neck/petcollar/locked name = "locked collar" desc = "A collar that has a small lock on it to keep it from being removed." pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/collar/locked + treat_path = /obj/item/key/collar var/lock = FALSE /obj/item/clothing/neck/petcollar/locked/attackby(obj/item/K, mob/user, params) @@ -238,32 +228,19 @@ /obj/item/clothing/neck/petcollar/locked/leather name = "leather pet collar" icon_state = "leathercollar" - - hasprimary = TRUE - hassecondary = TRUE - primary_color = "#222222" - secondary_color = "#888888" + poly_states = 2 + poly_colors = list("#222222", "#888888") /obj/item/clothing/neck/petcollar/locked/choker name = "choker" desc = "Quite fashionable... if you're somebody who's just read their first BDSM-themed erotica novel." icon_state = "choker" - - hasprimary = TRUE - primary_color = "#222222" + poly_colors = list("#222222") /obj/item/key/collar name = "Collar Key" desc = "A key for a tiny lock on a collar or bag." -/obj/item/clothing/neck/petcollar/Initialize() - . = ..() - new /obj/item/reagent_containers/food/snacks/cookie(src) - -/obj/item/clothing/neck/petcollar/locked/Initialize() - . = ..() - new /obj/item/key/collar(src) - ////////////// //DOPE BLING// ////////////// diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index 471c7623fd..802dd7265e 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -49,8 +49,8 @@ last_bloodtype = blood_dna[blood_dna[blood_dna.len]]//trust me this works last_blood_DNA = blood_dna[blood_dna.len] -/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/shoes/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(!isinhands) var/bloody = FALSE if(blood_DNA) diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 1f868dad6d..7a3ed902ea 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -377,3 +377,99 @@ name = "black cowboy boots" desc = "A pair of black cowboy boots, pretty easy to scuff up." icon_state = "cowboyboots_black" + +/obj/item/clothing/shoes/wallwalkers + name = "wall walking boots" + desc = "Contrary to popular belief, these do not allow you to walk on walls. Through bluespace magic stolen from an organisation that hoards technology, they simply allow you to slip through the atoms that make up anything, but only while walking, for safety reasons. As well as this, they unfortunately cause minor breath loss as the majority of atoms in your lungs are sucked out into any solid object you walk through. Make sure not to overuse them." + icon_state = "walkboots" + var/walkcool = 0 + var/wallcharges = 4 + var/newlocobject = null + +/obj/item/clothing/shoes/wallwalkers/equipped(mob/user,slot) + . = ..() + if(slot == SLOT_SHOES) + RegisterSignal(user, COMSIG_MOB_CLIENT_MOVE,.proc/intercept_user_move) + +/obj/item/clothing/shoes/wallwalkers/dropped(mob/user) + . = ..() + UnregisterSignal(user, COMSIG_MOB_CLIENT_MOVE) + +/obj/item/clothing/shoes/wallwalkers/attackby(obj/item/W, mob/user, params) + . = ..() + if(!istype(W, /obj/item/bluespacerecharge)) + return + var/obj/item/bluespacerecharge/ER = W + if(ER.uses) + wallcharges += ER.uses + to_chat(user, "You charged the bluespace crystal in the [src]. It now has [wallcharges] charges left.") + ER.uses = 0 + ER.icon_state = "[initial(ER.icon_state)]0" + else + to_chat(user, "[ER] has no crystal on it.") + +/obj/item/clothing/shoes/wallwalkers/examine(mob/user) + . = ..() + . += "It has [wallcharges] charges left." + +/obj/item/clothing/shoes/wallwalkers/proc/intercept_user_move(mob/living/m, client/client, dir, newloc, oldloc) + if (walkcool >= world.time || m.m_intent != MOVE_INTENT_WALK || wallcharges <= 0) + return + walkcool = world.time + m.movement_delay() + var/issolid = FALSE + var/turf/K = newloc + if (istype(K)) + if (K.density) + issolid = TRUE + if (!issolid) + for (var/atom/T in newloc) //stuff on the new turf + if (!T.CanPass(m,newloc) && T != m) + issolid = TRUE + newlocobject = T + break + if (!issolid) + for (var/atom/T in oldloc) //directional shit on the old turf + if (!T.CanPass(m,newloc) && T != m && T != newlocobject) + issolid = TRUE + break + newlocobject = null //stopping structures from using two charges because of how shitty the canpass code is + m.forceMove(newloc) + if (!issolid) + return + m.adjustOxyLoss(rand(5,13)) + if (prob(15)) + m.adjustBruteLoss(rand(4,7)) + to_chat(m,"You feel as if travelling through the solid object left something behind and it hurts!") + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(5, 1, oldloc) + s.start() + flash_lighting_fx(3, 3, LIGHT_COLOR_ORANGE) + wallcharges-- + +/obj/item/bluespacerecharge + name = "bluespace crystal recharging device" + desc = "A small cell with two prongs lazily jabbed into it. It looks like it's made for replacing the crystals in bluespace devices." + icon = 'icons/obj/module.dmi' + icon_state = "bluespace_charge" + item_flags = NOBLUDGEON + w_class = WEIGHT_CLASS_TINY + var/uses = 6 + +/obj/item/bluespacerecharge/examine(mob/user) + . = ..() + if(uses) + . += "It can add up to [uses] charges to compatible devices." + else + . += "The crystal is gone." + +/obj/item/bluespacerecharge/attackby(obj/item/I, mob/user, params) + ..() + if(!istype(I, /obj/item/stack/ore/bluespace_crystal) || uses) + return + var/obj/item/stack/ore/bluespace_crystal/B = I + if (B.amount < 10) + return + uses += 3 + to_chat(user, "You insert [I] into [src].") + B.use(10) + icon_state = initial(icon_state) diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index 4311aa5166..94ccdf94c6 100644 --- a/code/modules/clothing/spacesuits/chronosuit.dm +++ b/code/modules/clothing/spacesuits/chronosuit.dm @@ -321,7 +321,7 @@ check_flags = AB_CHECK_CONSCIOUS //|AB_CHECK_INSIDE var/obj/item/clothing/suit/space/chronos/chronosuit = null -/datum/action/innate/chrono_teleport/IsAvailable() +/datum/action/innate/chrono_teleport/IsAvailable(silent = FALSE) return (chronosuit && chronosuit.activated && chronosuit.camera && !chronosuit.teleporting) /datum/action/innate/chrono_teleport/Activate() diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index da979cd516..93b34f4522 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -30,16 +30,14 @@ /obj/item/clothing/head/helmet/space/hardsuit/attack_self(mob/user) on = !on - icon_state = "[basestate][on]-[hardsuit_type]" user.update_inv_head() //so our mob-overlays update - if(on) set_light(brightness_on) else set_light(0) - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() + +/obj/item/clothing/head/helmet/space/hardsuit/update_icon_state() + icon_state = "[basestate][on]-[hardsuit_type]" /obj/item/clothing/head/helmet/space/hardsuit/dropped(mob/user) ..() @@ -802,7 +800,7 @@ var/mob/living/carbon/human/C = loc C.update_inv_wear_suit() -/obj/item/clothing/suit/space/hardsuit/shielded/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/clothing/suit/space/hardsuit/shielded/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) var/file2use = style_flags & STYLE_ALL_TAURIC ? 'modular_citadel/icons/mob/64x32_effects.dmi' : 'icons/effects/effects.dmi' @@ -959,7 +957,7 @@ . = ..() . += mutable_appearance(icon, "knight_cydonia_overlay", color = energy_color) -/obj/item/clothing/head/helmet/space/hardsuit/lavaknight/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) +/obj/item/clothing/head/helmet/space/hardsuit/lavaknight/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) var/mutable_appearance/energy_overlay = mutable_appearance(icon_file, "knight_cydonia_overlay", ABOVE_LIGHTING_LAYER) @@ -990,7 +988,7 @@ . = ..() . += mutable_appearance(icon, "knight_cydonia_overlay", color = energy_color) -/obj/item/clothing/suit/space/hardsuit/lavaknight/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) +/obj/item/clothing/suit/space/hardsuit/lavaknight/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) var/mutable_appearance/energy_overlay = mutable_appearance(icon_file, "knight_cydonia_overlay", ABOVE_LIGHTING_LAYER) diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index fee8dbce33..f17eb91b74 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -67,7 +67,7 @@ var/datum/action/A=X A.UpdateButtonIcon() -/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/clothing/head/helmet/space/plasmaman/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands && on) . += mutable_appearance(icon_file, light_overlay) diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index e01ec2dde8..8de49c63de 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -12,7 +12,7 @@ var/suittoggled = FALSE mutantrace_variation = STYLE_DIGITIGRADE -/obj/item/clothing/suit/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) +/obj/item/clothing/suit/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) if(damaged_clothes) diff --git a/code/modules/clothing/suits/cloaks.dm b/code/modules/clothing/suits/cloaks.dm index 7d56fbe6dd..ce3d2576f9 100644 --- a/code/modules/clothing/suits/cloaks.dm +++ b/code/modules/clothing/suits/cloaks.dm @@ -91,3 +91,14 @@ heat_protection = HEAD max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF | ACID_PROOF | GOLIATH_RESISTANCE + +/obj/item/clothing/neck/cloak/polychromic + name = "polychromic cloak" + desc = "For when you want to show off your horrible colour coordination skills." + icon_state = "polyce" + item_state = "qmcloak" + var/list/poly_colors = list("#FFFFFF", "#FFFFFF", "#808080") + +/obj/item/clothing/neck/cloak/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 3) diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 0e345636cf..c133ea7c88 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -974,70 +974,11 @@ icon_state = "coatpoly" item_state = "coatpoly" hoodtype = /obj/item/clothing/head/hooded/winterhood/polychromic - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#6A6964" - secondary_color = "#C4B8A6" - tertiary_color = "#0000FF" + +/obj/item/clothing/suit/hooded/wintercoat/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#6A6964", "#C4B8A6", "#0000FF"), 3) /obj/item/clothing/head/hooded/winterhood/polychromic icon_state = "winterhood_poly" item_state = "winterhood_poly" - -/obj/item/clothing/head/hooded/winterhood/polychromic/worn_overlays(isinhands, icon_file, style_flags = NONE) //this is where the main magic happens. - . = ..() - if(suit.hasprimary | suit.hassecondary) - if(!isinhands) //prevents the worn sprites from showing up if you're just holding them - if(suit.hasprimary) //checks if overlays are enabled - var/mutable_appearance/primary_worn = mutable_appearance(icon_file, "[icon_state]-primary") //automagical sprite selection - primary_worn.color = suit.primary_color //colors the overlay - . += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite. - if(suit.hassecondary) - var/mutable_appearance/secondary_worn = mutable_appearance(icon_file, "[icon_state]-secondary") - secondary_worn.color = suit.secondary_color - . += secondary_worn - -/obj/item/clothing/suit/hooded/wintercoat/polychromic/worn_overlays(isinhands, icon_file, style_flags = NONE) //this is where the main magic happens. - . = ..() - if(hasprimary | hassecondary | hastertiary) - if(!isinhands) //prevents the worn sprites from showing up if you're just holding them - if(hasprimary) //checks if overlays are enabled - var/mutable_appearance/primary_worn = mutable_appearance(icon_file, "[icon_state]-primary[suittoggled ? "_t" : ""]") //automagical sprite selection - primary_worn.color = primary_color //colors the overlay - . += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite. - if(hassecondary) - var/mutable_appearance/secondary_worn = mutable_appearance(icon_file, "[icon_state]-secondary[suittoggled ? "_t" : ""]") - secondary_worn.color = secondary_color - . += secondary_worn - if(hastertiary) - var/mutable_appearance/tertiary_worn = mutable_appearance(icon_file, "[icon_state]-tertiary[suittoggled ? "_t" : ""]") - tertiary_worn.color = tertiary_color - . += tertiary_worn - -/obj/item/clothing/suit/hooded/wintercoat/AltClick(mob/user) - . = ..() - if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) - return - if(hasprimary | hassecondary | hastertiary) - var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays - switch(choice) //Lets the list's options actually lead to something - if("Primary Color") - var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it. - if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL. - primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly - update_icon() //updates the item icon - user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works. - if("Secondary Color") - var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null - if(secondary_color_input) - secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - if("Tertiary Color") - var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null - if(tertiary_color_input) - tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1) - update_icon() - user.regenerate_icons() - return TRUE diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index cbbd64ebcc..4f29eab6ab 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -6,7 +6,7 @@ var/hoodtype = /obj/item/clothing/head/hooded/winterhood //so the chaplain hoodie or other hoodies can override this /obj/item/clothing/suit/hooded/New() - MakeHood() + hood = MakeHelmet() ..() /obj/item/clothing/suit/hooded/Destroy() @@ -14,11 +14,15 @@ qdel(hood) hood = null -/obj/item/clothing/suit/hooded/proc/MakeHood() +/obj/item/clothing/suit/proc/MakeHelmet(obj/item/clothing/head/H) + SEND_SIGNAL(src, COMSIG_SUIT_MADE_HELMET, H) + return H + +/obj/item/clothing/suit/hooded/MakeHelmet(obj/item/clothing/head/hooded/H) if(!hood) - var/obj/item/clothing/head/hooded/W = new hoodtype(src) - W.suit = src - hood = W + H = new hoodtype(src) + H.suit = src + return ..() /obj/item/clothing/suit/hooded/ui_action_click() ToggleHood() @@ -125,7 +129,7 @@ //Hardsuit toggle code /obj/item/clothing/suit/space/hardsuit/Initialize() - MakeHelmet() + helmet = MakeHelmet() . = ..() /obj/item/clothing/suit/space/hardsuit/Destroy() @@ -140,13 +144,13 @@ suit.helmet = null return ..() -/obj/item/clothing/suit/space/hardsuit/proc/MakeHelmet() +/obj/item/clothing/suit/space/hardsuit/MakeHelmet(obj/item/clothing/head/helmet/space/hardsuit/H) if(!helmettype) return if(!helmet) - var/obj/item/clothing/head/helmet/space/hardsuit/W = new helmettype(src) - W.suit = src - helmet = W + H = new helmettype(src) + H.suit = src + return ..() /obj/item/clothing/suit/space/hardsuit/ui_action_click() ..() diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 30bccff6de..fe3aaf4bda 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -18,28 +18,14 @@ var/obj/item/clothing/accessory/attached_accessory var/mutable_appearance/accessory_overlay -/obj/item/clothing/under/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() +/obj/item/clothing/under/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE) + . = ..() if(isinhands) return if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") if(blood_DNA) . += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color()) - if(accessory_overlay) - . += accessory_overlay - if(hasprimary) //checks if overlays are enabled - var/mutable_appearance/primary_worn = mutable_appearance(icon_file, "[icon_state]-primary") //automagical sprite selection - primary_worn.color = primary_color //colors the overlay - . += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite. - if(hassecondary) - var/mutable_appearance/secondary_worn = mutable_appearance(icon_file, "[icon_state]-secondary") - secondary_worn.color = secondary_color - . += secondary_worn - if(hastertiary) - var/mutable_appearance/tertiary_worn = mutable_appearance(icon_file, "[icon_state]-tertiary") - tertiary_worn.color = tertiary_color - . += tertiary_worn /obj/item/clothing/under/attackby(obj/item/I, mob/user, params) if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) @@ -167,5 +153,121 @@ if(attached_accessory) . += "\A [attached_accessory] is attached to it." +/obj/item/clothing/under/verb/toggle() + set name = "Adjust Suit Sensors" + set category = "Object" + set src in usr + var/mob/M = usr + if (istype(M, /mob/dead/)) + return + if (!can_use(M)) + return + if(src.has_sensor == LOCKED_SENSORS) + to_chat(usr, "The controls are locked.") + return 0 + if(src.has_sensor == BROKEN_SENSORS) + to_chat(usr, "The sensors have shorted out!") + return 0 + if(src.has_sensor <= NO_SENSORS) + to_chat(usr, "This suit does not have any sensors.") + return 0 + + var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon") + var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes + if(get_dist(usr, src) > 1) + to_chat(usr, "You have moved too far away!") + return + sensor_mode = modes.Find(switchMode) - 1 + + if (src.loc == usr) + switch(sensor_mode) + if(0) + to_chat(usr, "You disable your suit's remote sensing equipment.") + if(1) + to_chat(usr, "Your suit will now only report whether you are alive or dead.") + if(2) + to_chat(usr, "Your suit will now only report your exact vital lifesigns.") + if(3) + to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + + if(ishuman(loc)) + var/mob/living/carbon/human/H = loc + if(H.w_uniform == src) + H.update_suit_sensors() + + +/obj/item/clothing/under/CtrlClick(mob/user) + . = ..() + + if (!(item_flags & IN_INVENTORY)) + return + + if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + return + + if(has_sensor == LOCKED_SENSORS) + to_chat(user, "The controls are locked.") + return + if(has_sensor == BROKEN_SENSORS) + to_chat(user, "The sensors have shorted out!") + return + if(has_sensor <= NO_SENSORS) + to_chat(user, "This suit does not have any sensors.") + return + + sensor_mode = SENSOR_COORDS + + to_chat(user, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.w_uniform == src) + H.update_suit_sensors() + +/obj/item/clothing/under/AltClick(mob/user) + . = ..() + if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + return + if(attached_accessory) + remove_accessory(user) + else + rolldown() + +/obj/item/clothing/under/verb/jumpsuit_adjust() + set name = "Adjust Jumpsuit Style" + set category = null + set src in usr + rolldown() + +/obj/item/clothing/under/proc/rolldown() + if(!can_use(usr)) + return + if(!can_adjust) + to_chat(usr, "You cannot wear this suit any differently!") + return + if(toggle_jumpsuit_adjust()) + to_chat(usr, "You adjust the suit to wear it more casually.") + else + to_chat(usr, "You adjust the suit back to normal.") + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + H.update_inv_w_uniform() + H.update_body() + +/obj/item/clothing/under/proc/toggle_jumpsuit_adjust() + adjusted = !adjusted + + if(adjusted) + if(fitted != FEMALE_UNIFORM_TOP) + fitted = NO_FEMALE_UNIFORM + if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted + body_parts_covered &= ~CHEST + else + fitted = initial(fitted) + if(!alt_covers_chest) + body_parts_covered |= CHEST + + return adjusted + /obj/item/clothing/under/rank dying_key = DYE_REGISTRY_UNDER diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index 12988c26ae..69a1dc67b3 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -91,13 +91,13 @@ name = "polychromic kilt" desc = "It's not a skirt!" icon_state = "polykilt" - hasprimary = TRUE - hassecondary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#F08080" body_parts_covered = CHEST|GROIN|ARMS|LEGS mutantrace_variation = NONE +/obj/item/clothing/under/costume/kilt/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#FFFFFF", "#F08080"), 2) + /obj/item/clothing/under/costume/gladiator name = "gladiator uniform" desc = "Are you not entertained? Is that not why you are here?" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index a7557a0702..d475ca8100 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -241,69 +241,67 @@ desc = "A fancy button-up shirt made with polychromic threads." icon_state = "polysuit" item_state = "sl_suit" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#353535" - tertiary_color = "#353535" mutantrace_variation = NONE +/obj/item/clothing/under/misc/poly_shirt/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#FFFFFF", "#353535", "#353535"), 3) + /obj/item/clothing/under/misc/polyshorts name = "polychromic shorts" desc = "For ease of movement and style." icon_state = "polyshorts" item_state = "rainbow" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#353535" - secondary_color = "#808080" - tertiary_color = "#808080" can_adjust = FALSE body_parts_covered = CHEST|GROIN|ARMS +/obj/item/clothing/under/misc/polyshorts/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#353535", "#808080", "#808080"), 3) + /obj/item/clothing/under/misc/polyjumpsuit name = "polychromic tri-tone jumpsuit" desc = "A fancy jumpsuit made with polychromic threads." icon_state = "polyjump" item_state = "rainbow" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#808080" - tertiary_color = "#FF3535" can_adjust = FALSE mutantrace_variation = NONE +/obj/item/clothing/under/misc/polyjumpsuit/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#FFFFFF", "#808080", "#353535"), 3) + /obj/item/clothing/under/misc/poly_bottomless name = "polychromic bottomless shirt" - desc = "Great for showing off your junk in dubious style." + desc = "Great for showing off your underwear in dubious style." icon_state = "polybottomless" item_state = "rainbow" - primary_color = "#808080" - secondary_color = "#FF3535" body_parts_covered = CHEST|ARMS //Because there's no bottom included can_adjust = FALSE mutantrace_variation = NONE +/obj/item/clothing/under/misc/poly_bottomless/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#808080", "#FF3535"), 2) + /obj/item/clothing/under/misc/poly_tanktop name = "polychromic tank top" desc = "For those lazy summer days." icon_state = "polyshimatank" item_state = "rainbow" - primary_color = "#808080" - secondary_color = "#FFFFFF" - tertiary_color = "#8CC6FF" body_parts_covered = CHEST|GROIN can_adjust = FALSE mutantrace_variation = NONE + var/list/poly_states = 3 + var/list/poly_colors = list("#808080", "#FFFFFF", "#8CC6FF") + +/obj/item/clothing/under/misc/poly_tanktop/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, poly_states) /obj/item/clothing/under/misc/poly_tanktop/female name = "polychromic feminine tank top" desc = "Great for showing off your chest in style. Not recommended for males." icon_state = "polyfemtankpantsu" - hastertiary = FALSE - primary_color = "#808080" - secondary_color = "#FF3535" + poly_states = 2 + poly_colors = list("#808080", "#FF3535") diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm index ebf7cb5896..f61a41e4c3 100644 --- a/code/modules/clothing/under/shorts.dm +++ b/code/modules/clothing/under/shorts.dm @@ -35,19 +35,18 @@ desc = "95% Polychrome, 5% Spandex!" icon_state = "polyshortpants" item_state = "rainbow" - hasprimary = TRUE - hassecondary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#F08080" mutantrace_variation = NONE + var/list/poly_colors = list("#FFFFFF", "#F08080") + +/obj/item/clothing/under/shorts/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 2) /obj/item/clothing/under/shorts/polychromic/pantsu name = "polychromic panties" desc = "Topless striped panties. Now with 120% more polychrome!" icon_state = "polypantsu" item_state = "rainbow" - hastertiary = FALSE - primary_color = "#FFFFFF" - secondary_color = "#8CC6FF" body_parts_covered = GROIN mutantrace_variation = NONE + poly_colors = list("#FFFFFF", "#8CC6FF") diff --git a/code/modules/clothing/under/skirt_dress.dm b/code/modules/clothing/under/skirt_dress.dm index f00e96d821..fa2c9eed71 100644 --- a/code/modules/clothing/under/skirt_dress.dm +++ b/code/modules/clothing/under/skirt_dress.dm @@ -211,21 +211,18 @@ desc = "A fancy skirt made with polychromic threads." icon_state = "polyskirt" item_state = "rainbow" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#F08080" - tertiary_color = "#808080" mutantrace_variation = NONE + var/list/poly_colors = list("#FFFFFF", "#F08080", "#808080") + +/obj/item/clothing/under/dress/skirt/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, poly_colors, 3) /obj/item/clothing/under/dress/skirt/polychromic/pleated name = "polychromic pleated skirt" desc = "A magnificent pleated skirt complements the woolen polychromatic sweater." icon_state = "polypleat" item_state = "rainbow" - primary_color = "#8CC6FF" - secondary_color = "#808080" - tertiary_color = "#FF3535" body_parts_covered = CHEST|GROIN|ARMS mutantrace_variation = NONE + poly_colors = list("#8CC6FF", "#808080", "#FF3535") diff --git a/code/modules/clothing/under/suits.dm b/code/modules/clothing/under/suits.dm index 3ee5204c3b..087262dd1e 100644 --- a/code/modules/clothing/under/suits.dm +++ b/code/modules/clothing/under/suits.dm @@ -109,11 +109,9 @@ desc = "For when you want to show off your horrible colour coordination skills." icon_state = "polysuit" item_state = "sl_suit" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#FFFFFF" - secondary_color = "#FFFFFF" - tertiary_color = "#808080" can_adjust = FALSE mutantrace_variation = NONE + +/obj/item/clothing/under/suit/polychromic/ComponentInitialize() + . = ..() + AddElement(/datum/element/polychromic, list("#FFFFFF", "#FFFFFF", "#808080"), 3) diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm index 204e5ce455..99fd2af9bb 100644 --- a/code/modules/food_and_drinks/food/snacks_bread.dm +++ b/code/modules/food_and_drinks/food/snacks_bread.dm @@ -179,6 +179,18 @@ tastes = list("bread" = 1) foodtype = GRAIN +/obj/item/reagent_containers/food/snacks/garlicbread + name = "garlic bread" + desc = "Alas, it is limited." + icon = 'icons/obj/food/burgerbread.dmi' + icon_state = "garlicbread" + item_state = "garlicbread" + bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 2) + list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin= 4, /datum/reagent/consumable/garlic = 2) + bitesize = 3 + tastes = list("bread" = 1, "garlic" = 1, "butter" = 1) + foodtype = GRAIN + /obj/item/reagent_containers/food/snacks/deepfryholder name = "Deep Fried Foods Holder Obj" desc = "If you can see this description the code for the deep fryer fucked up." diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm index a7cad1d7bb..d02ad0f1a0 100644 --- a/code/modules/food_and_drinks/food/snacks_meat.dm +++ b/code/modules/food_and_drinks/food/snacks_meat.dm @@ -207,7 +207,7 @@ name = "raw khinkali" desc = "One hundred khinkalis? Do I look like a pig?" icon_state = "khinkali" - list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1) + list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/consumable/garlic = 1) cooked_type = /obj/item/reagent_containers/food/snacks/khinkali tastes = list("meat" = 1, "onions" = 1, "garlic" = 1) foodtype = MEAT @@ -216,7 +216,7 @@ name = "khinkali" desc = "One hundred khinkalis? Do I look like a pig?" icon_state = "khinkali" - list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 2) + list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/garlic = 1) bitesize = 3 filling_color = "#F0F0F0" tastes = list("meat" = 1, "onions" = 1, "garlic" = 1) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index b163c6ba97..94c8d7219c 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -86,8 +86,8 @@ tag_overlay.pixel_y = boxes.len * 3 add_overlay(tag_overlay) -/obj/item/pizzabox/worn_overlays(isinhands, icon_file, style_flags = NONE) - . = list() +/obj/item/pizzabox/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) + . = ..() var/current_offset = 2 if(isinhands) for(var/V in boxes) //add EXTRA BOX per box diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm index c3890b28eb..335078eb4c 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm @@ -125,6 +125,16 @@ result = /obj/item/reagent_containers/food/snacks/baguette subcategory = CAT_BREAD +/datum/crafting_recipe/food/garlicbread + name = "Garlic Bread" + time = 40 + reqs = list(/obj/item/reagent_containers/food/snacks/grown/garlic = 1, + /obj/item/reagent_containers/food/snacks/breadslice/plain = 1, + /obj/item/reagent_containers/food/snacks/butter = 1 + ) + result = /obj/item/reagent_containers/food/snacks/garlicbread + subcategory = CAT_BREAD + /datum/crafting_recipe/food/butterbiscuit name = "Butter Biscuit" reqs = list( diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm index 528fc61156..385d7fa359 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm @@ -37,7 +37,8 @@ name = "Raw Khinkali" reqs = list( /obj/item/reagent_containers/food/snacks/doughslice = 1, - /obj/item/reagent_containers/food/snacks/faggot = 1 + /obj/item/reagent_containers/food/snacks/faggot = 1, + /obj/item/reagent_containers/food/snacks/grown/garlic = 1 ) result = /obj/item/reagent_containers/food/snacks/rawkhinkali subcategory = CAT_MISCFOOD diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm index 9fb97c08a7..316bdb8289 100644 --- a/code/modules/holodeck/area_copy.dm +++ b/code/modules/holodeck/area_copy.dm @@ -63,23 +63,34 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars_by_type, typecacheof_assoc_list(list( var/src_min_x = 99999 var/src_min_y = 99999 + var/src_max_x = 0 + var/src_max_y = 0 var/list/refined_src = new/list() for (var/turf/T in turfs_src) src_min_x = min(src_min_x,T.x) src_min_y = min(src_min_y,T.y) + src_max_x = max(src_max_x,T.y) + src_max_y = max(src_max_y,T.y) for (var/turf/T in turfs_src) refined_src[T] = "[T.x - src_min_x].[T.y - src_min_y]" var/trg_min_x = 99999 var/trg_min_y = 99999 + var/trg_max_x = 0 + var/trg_max_y = 0 var/list/refined_trg = new/list() for (var/turf/T in turfs_trg) trg_min_x = min(trg_min_x,T.x) trg_min_y = min(trg_min_y,T.y) + trg_max_x = max(trg_max_x,T.y) + trg_max_y = max(trg_max_y,T.y) + + var/diff_x = round(((src_max_x - src_min_x) - (trg_max_x - trg_min_x))/2) + var/diff_y = round(((src_max_y - src_min_y) - (trg_max_y - trg_min_y))/2) for (var/turf/T in turfs_trg) - refined_trg["[T.x - trg_min_x].[T.y - trg_min_y]"] = T + refined_trg["[T.x - trg_min_x + diff_x].[T.y - trg_min_y + diff_y]"] = T var/list/toupdate = new/list() diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index b5cbed8b79..3c87082393 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -2,7 +2,10 @@ Holodeck Update The on-station holodeck area is of type [holodeck_type]. - All subtypes of [program_type] are loaded into the program cache or emag programs list. + All types found in GLOB.holodeck_areas_per_comp_type[src.type], generated on make_datum_references_lists(), + are loaded into the program cache or emag programs list. + Paths with their abstract_type variable equal to themselves will be skipped. + If init_program is null, a random program will be loaded on startup. If you don't wish this, set it to the offline program or another of your choosing. @@ -12,7 +15,6 @@ 3) Create a new control console that uses those areas Non-mapped areas should be skipped but you should probably comment them out anyway. - The base of program_type will always be ignored; only subtypes will be loaded. */ #define HOLODECK_CD 25 @@ -35,7 +37,6 @@ // Splitting this up allows two holodecks of the same size // to use the same source patterns. Y'know, if you want to. var/holodeck_type = /area/holodeck/rec_center // locate(this) to get the target holodeck - var/program_type = /area/holodeck/rec_center // subtypes of this (but not this itself) are loadable programs var/active = FALSE var/damaged = FALSE @@ -181,7 +182,7 @@ return ..() /obj/machinery/computer/holodeck/proc/generate_program_list() - for(var/typekey in subtypesof(program_type)) + for(var/typekey in GLOB.holodeck_areas_prototypes[type]) var/area/holodeck/A = GLOB.areas_by_type[typekey] if(!A || !A.contents.len) continue diff --git a/code/modules/hydroponics/grown/garlic.dm b/code/modules/hydroponics/grown/garlic.dm new file mode 100644 index 0000000000..4184b85008 --- /dev/null +++ b/code/modules/hydroponics/grown/garlic.dm @@ -0,0 +1,29 @@ +/obj/item/seeds/garlic + name = "pack of garlic seeds" + desc = "A packet of extremely pungent seeds." + icon_state = "seed-garlic" + species = "garlic" + plantname = "Garlic Sprouts" + product = /obj/item/reagent_containers/food/snacks/grown/garlic + yield = 6 + potency = 25 + growthstages = 3 + growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi' + reagents_add = list(/datum/reagent/consumable/garlic = 0.15, /datum/reagent/consumable/nutriment = 0.1) + +/obj/item/reagent_containers/food/snacks/grown/garlic + seed = /obj/item/seeds/garlic + name = "garlic" + desc = "Delicious, but with a potentially overwhelming odor." + icon_state = "garlic" + filling_color = "#C0C9A0" + bitesize_mod = 2 + tastes = list("garlic" = 1) + wine_power = 10 + +/obj/item/clothing/neck/garlic_necklace + name = "garlic necklace" + desc = "A clove of garlic on a cable, tied to itself in a circle, just might fit around your neck. For loonies people who fear getting their blood sucked." + icon_state = "garlic_necklace" + item_state = "garlic_necklace" + \ No newline at end of file diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm index 2ebaa6d5e2..a75b9caf5f 100644 --- a/code/modules/hydroponics/grown/onion.dm +++ b/code/modules/hydroponics/grown/onion.dm @@ -14,7 +14,7 @@ weed_chance = 3 growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi' reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1) - mutatelist = list(/obj/item/seeds/onion/red) + mutatelist = list(/obj/item/seeds/onion/red, /obj/item/seeds/garlic) /obj/item/reagent_containers/food/snacks/grown/onion seed = /obj/item/seeds/onion diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index 3769f9eacc..aeddf771b8 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -78,7 +78,7 @@ make_podman = 1 break else - if(M.ckey == ckey && M.stat == DEAD && !M.suiciding) + if(M.ckey == ckey && M.stat == DEAD && !M.suiciding && AmBloodsucker(M)) make_podman = 1 if(isliving(M)) var/mob/living/L = M diff --git a/code/modules/language/vampiric.dm b/code/modules/language/vampiric.dm index 6da54ce844..ab48a17d2f 100644 --- a/code/modules/language/vampiric.dm +++ b/code/modules/language/vampiric.dm @@ -1,4 +1,4 @@ -// VAMPIRE LANGUAGE // +// BLOODSUCKER LANGUAGE // /datum/language/vampiric name = "Blah-Sucker" diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index d3a417b439..30eed6c8f0 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -117,7 +117,7 @@ glass_overlay.appearance_flags = RESET_COLOR . += glass_overlay -/obj/item/clothing/head/helmet/space/hostile_environment/worn_overlays(isinhands, icon_file, style_flags = NONE) +/obj/item/clothing/head/helmet/space/hostile_environment/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(!isinhands) var/mutable_appearance/M = mutable_appearance('icons/mob/clothing/head.dmi', "hostile_env_glass") diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index b515ebbc13..1fd1b31b69 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -433,19 +433,23 @@ desc = "A glowing trinket that was originally the Hierophant's beacon. Suitable as a trophy for a kinetic crusher." icon_state = "vortex_talisman" denied_type = /obj/item/crusher_trophy/vortex_talisman + var/vortex_cd /obj/item/crusher_trophy/vortex_talisman/effect_desc() - return "mark detonation to create a barrier you can pass" + return "mark detonation to create a barrier you can pass that lasts for 7.5 seconds, with a cooldown of 9 seconds after creation." /obj/item/crusher_trophy/vortex_talisman/on_mark_detonation(mob/living/target, mob/living/user) + if(vortex_cd >= world.time) + return var/turf/T = get_turf(user) - new /obj/effect/temp_visual/hierophant/wall/crusher(T, user) //a wall only you can pass! + var/obj/effect/temp_visual/hierophant/wall/crusher/W = new (T, user) //a wall only you can pass! var/turf/otherT = get_step(T, turn(user.dir, 90)) if(otherT) new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) otherT = get_step(T, turn(user.dir, -90)) if(otherT) new /obj/effect/temp_visual/hierophant/wall/crusher(otherT, user) + vortex_cd = world.time + W.duration * 1.2 /obj/effect/temp_visual/hierophant/wall/crusher duration = 75 diff --git a/code/modules/mining/equipment/regenerative_core.dm b/code/modules/mining/equipment/regenerative_core.dm index ae451ba1a8..c14aa097bb 100644 --- a/code/modules/mining/equipment/regenerative_core.dm +++ b/code/modules/mining/equipment/regenerative_core.dm @@ -26,8 +26,8 @@ slot = "hivecore" force = 0 actions_types = list(/datum/action/item_action/organ_action/use) - var/inert = 0 - var/preserved = 0 + var/inert + var/preserved /obj/item/organ/regenerative_core/Initialize() . = ..() @@ -38,7 +38,9 @@ go_inert() /obj/item/organ/regenerative_core/proc/preserved(implanted = 0) - inert = FALSE + if(inert) + name = initial(name) + inert = FALSE preserved = TRUE update_icon() desc = "All that remains of a hivelord. It is preserved, allowing you to use it to heal completely without danger of decay." @@ -69,14 +71,15 @@ /obj/item/organ/regenerative_core/afterattack(atom/target, mob/user, proximity_flag) . = ..() - if(proximity_flag && ishuman(target)) + if(proximity_flag) + apply_healing_core(target, user) + +/obj/item/organ/regenerative_core/proc/apply_healing_core(atom/target, mob/user) + if(ishuman(target)) var/mob/living/carbon/human/H = target if(inert) to_chat(user, "[src] has decayed and can no longer be used to heal.") return - if(isvamp(user)) - to_chat(user, "[src] breaks down as it fails to heal your unholy self") - return else if(H.stat == DEAD) to_chat(user, "[src] are useless on the dead.") @@ -87,22 +90,16 @@ else to_chat(user, "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments.") SSblackbox.record_feedback("nested tally", "hivelord_core", 1, list("[type]", "used", "self")) - H.revive(full_heal = 1) + if(AmBloodsucker(H)) + H.revive(full_heal = FALSE) + else + H.revive(full_heal = TRUE) qdel(src) user.log_message("[user] used [src] to heal [H]! Wake the fuck up, Samurai!", LOG_ATTACK, color="green") //Logging for 'old' style legion core use, when clicking on a sprite of yourself or another. /obj/item/organ/regenerative_core/attack_self(mob/user) //Knouli's first hack! Allows for the use of the core in hand rather than needing to click on the target, yourself, to selfheal. Its a rip of the proc just above - but skips on distance check and only uses 'user' rather than 'target' - if(ishuman(user)) //Check if user is human, no need for distance check as it's self heal - var/mob/living/carbon/human/H = user //Set H to user rather than target - if(inert) //Inert cores are useless - to_chat(user, "[src] has decayed and can no longer be used to heal.") - return - else //Skip on check if the target to be healed is dead as, if you are dead, you're not going to be able to use it on yourself! - to_chat(user, "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments.") - SSblackbox.record_feedback("nested tally", "hivelord_core", 1, list("[type]", "used", "self")) - H.revive(full_heal = 1) - qdel(src) - H.log_message("[H] used [src] to heal themselves! Making use of Knouli's sexy and intelligent use-in-hand proc!", LOG_ATTACK, color="green") //Logging for 'new' style legion core use, when using the core in-hand. + . = ..() + apply_healing_core(user) /obj/item/organ/regenerative_core/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE) diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm index ef6a372f9e..42b2c4433b 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -21,14 +21,13 @@ Doesn't work on other aliens/AI.*/ . = ..() action = new(src) -/obj/effect/proc_holder/alien/Click() - if(!iscarbon(usr)) - return 1 - var/mob/living/carbon/user = usr - if(cost_check(check_turf,user)) +/obj/effect/proc_holder/alien/Trigger(mob/living/carbon/user, skip_cost_check) + if(!istype(user)) + return TRUE + if(!skip_cost_check || cost_check(check_turf,user)) if(fire(user) && user) // Second check to prevent runtimes when evolving user.adjustPlasma(-plasma_cost) - return 1 + return TRUE /obj/effect/proc_holder/alien/on_gain(mob/living/carbon/user) return diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 6947ab28f8..eb1b38b9ff 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -247,13 +247,13 @@ /proc/CanHug(mob/living/M) if(!istype(M)) - return 0 + return FALSE if(M.stat == DEAD) - return 0 + return FALSE if(M.getorgan(/obj/item/organ/alien/hivenode)) - return 0 - if(isvamp(M)) - return 0 + return FALSE + if(AmBloodsucker(M)) + return FALSE if(ismonkey(M)) return 1 @@ -262,9 +262,9 @@ if(ishuman(C) && !(SLOT_WEAR_MASK in C.dna.species.no_equip)) var/mob/living/carbon/human/H = C if(H.is_mouth_covered(head_only = 1)) - return 0 - return 1 - return 0 + return FALSE + return TRUE + return FALSE #undef MIN_ACTIVE_TIME #undef MAX_ACTIVE_TIME diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index d3f262403b..40b8de36c5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -854,7 +854,7 @@ /mob/living/carbon/proc/can_defib() var/tlimit = DEFIB_TIME_LIMIT * 10 var/obj/item/organ/heart = getorgan(/obj/item/organ/heart) - if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK)) + if(suiciding || hellbound || HAS_TRAIT(src, TRAIT_HUSK) || AmBloodsucker(src)) return if((world.time - timeofdeath) > tlimit) return diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 4ee069afe8..abc2288e9b 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -469,7 +469,7 @@ var/cooldown = 150 var/last_teleport = 0 -/datum/action/innate/unstable_teleport/IsAvailable() +/datum/action/innate/unstable_teleport/IsAvailable(silent = FALSE) if(..()) if(world.time > last_teleport + cooldown) return 1 diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 9937b52002..775f36cfc7 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -43,7 +43,7 @@ C.faction |= "slime" /datum/species/jelly/spec_life(mob/living/carbon/human/H) - if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for vampires + if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for blooduskers return if(!H.blood_volume) H.blood_volume += 5 @@ -84,7 +84,7 @@ background_icon_state = "bg_alien" required_mobility_flags = NONE -/datum/action/innate/regenerate_limbs/IsAvailable() +/datum/action/innate/regenerate_limbs/IsAvailable(silent = FALSE) if(..()) var/mob/living/carbon/human/H = owner var/list/limbs_to_heal = H.get_missing_limbs() @@ -223,7 +223,7 @@ icon_icon = 'icons/mob/actions/actions_slime.dmi' background_icon_state = "bg_alien" -/datum/action/innate/split_body/IsAvailable() +/datum/action/innate/split_body/IsAvailable(silent = FALSE) if(..()) var/mob/living/carbon/human/H = owner if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT) @@ -776,7 +776,7 @@ ..() species = _species -/datum/action/innate/use_extract/IsAvailable() +/datum/action/innate/use_extract/IsAvailable(silent = FALSE) if(..()) if(species && species.current_extract && (world.time > species.extract_cooldown)) return TRUE diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 7c5f0f473a..415cd9889c 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -81,6 +81,9 @@ if(H.blood_volume >= BLOOD_VOLUME_MAXIMUM) to_chat(H, "You're already full!") return + //This checks whether or not they are wearing a garlic clove on their neck + if(!blood_sucking_checks(victim, TRUE, FALSE)) + return if(victim.stat == DEAD) to_chat(H, "You need a living victim!") return @@ -92,6 +95,9 @@ to_chat(victim, "[H] tries to bite you, but stops before touching you!") to_chat(H, "[victim] is blessed! You stop just in time to avoid catching fire.") return + //Here we check now for both the garlic cloves on the neck and for blood in the victims bloodstream. + if(!blood_sucking_checks(victim, TRUE, TRUE)) + return if(!do_after(H, 30, target = victim)) return var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index ae7009f5f6..63e772e07c 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -321,12 +321,16 @@ There are several things that need to be remembered: if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated return - if(client && hud_used && hud_used.inv_slots[SLOT_BACK]) + if(client && hud_used) var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD] inv.update_icon() - update_mutant_bodyparts() if(head) + head.screen_loc = ui_head + if(client && hud_used && hud_used.hud_shown) + if(hud_used.inventory_shown) + client.screen += head + update_observer_view(head,1) remove_overlay(HEAD_LAYER) var/obj/item/clothing/head/H = head var/alt_icon = H.mob_overlay_icon || 'icons/mob/clothing/head.dmi' @@ -348,6 +352,7 @@ There are several things that need to be remembered: head_overlay.pixel_y += dna.species.offset_features[OFFSET_HEAD][2] overlays_standing[HEAD_LAYER] = head_overlay apply_overlay(HEAD_LAYER) + update_mutant_bodyparts() /mob/living/carbon/human/update_inv_belt() remove_overlay(BELT_LAYER) @@ -457,11 +462,16 @@ There are several things that need to be remembered: if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated return - if(client && hud_used && hud_used.inv_slots[SLOT_WEAR_MASK]) + if(client && hud_used) var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK] inv.update_icon() if(wear_mask) + wear_mask.screen_loc = ui_mask + if(client && hud_used && hud_used.hud_shown) + if(hud_used.inventory_shown) + client.screen += wear_mask + update_observer_view(wear_mask,1) var/obj/item/clothing/mask/M = wear_mask remove_overlay(FACEMASK_LAYER) var/alt_icon = M.mob_overlay_icon || 'icons/mob/clothing/mask.dmi' @@ -515,22 +525,6 @@ There are several things that need to be remembered: //human HUD updates for items in our inventory -//update whether our head item appears on our hud. -/mob/living/carbon/human/update_hud_head(obj/item/I) - I.screen_loc = ui_head - if(client && hud_used && hud_used.hud_shown) - if(hud_used.inventory_shown) - client.screen += I - update_observer_view(I,1) - -//update whether our mask item appears on our hud. -/mob/living/carbon/human/update_hud_wear_mask(obj/item/I) - I.screen_loc = ui_mask - if(client && hud_used && hud_used.hud_shown) - if(hud_used.inventory_shown) - client.screen += I - update_observer_view(I,1) - //update whether our neck item appears on our hud. /mob/living/carbon/human/update_hud_neck(obj/item/I) I.screen_loc = ui_neck @@ -579,13 +573,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if /obj/item/proc/build_worn_icon(default_layer = 0, default_icon_file = null, isinhands = FALSE, femaleuniform = NO_FEMALE_UNIFORM, override_state, style_flags = NONE, use_mob_overlay_icon = TRUE) var/t_state - if(override_state) - t_state = override_state - else - if(isinhands && item_state) - t_state = item_state - else - t_state = icon_state + t_state = override_state || item_state || icon_state //Find a valid icon file from variables+arguments var/file2use @@ -609,7 +597,7 @@ use_mob_overlay_icon: if FALSE, it will always use the default_icon_file even if //Get the overlays for this item when it's being worn //eg: ammo counters, primed grenade flashes, etc. - var/list/worn_overlays = worn_overlays(isinhands, file2use, style_flags) + var/list/worn_overlays = worn_overlays(isinhands, file2use, t_state, style_flags) if(worn_overlays && worn_overlays.len) standing.overlays.Add(worn_overlays) diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 0cfca9f212..a431059a89 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -90,9 +90,9 @@ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated return - if(client && hud_used && hud_used.inv_slots[SLOT_WEAR_MASK]) + if(client && hud_used) var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_WEAR_MASK] - inv.update_icon() + inv?.update_icon() if(wear_mask) if(!(head && (head.flags_inv & HIDEMASK))) @@ -110,7 +110,7 @@ if(wear_neck) if(!(head && (head.flags_inv & HIDENECK))) - overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi', override_state = wear_mask.icon_state) + overlays_standing[NECK_LAYER] = wear_neck.build_worn_icon(default_layer = NECK_LAYER, default_icon_file = 'icons/mob/clothing/neck.dmi', override_state = wear_neck.icon_state) update_hud_neck(wear_neck) apply_overlay(NECK_LAYER) @@ -118,9 +118,9 @@ /mob/living/carbon/update_inv_back() remove_overlay(BACK_LAYER) - if(client && hud_used && hud_used.inv_slots[SLOT_BACK]) + if(client && hud_used) var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_BACK] - inv.update_icon() + inv?.update_icon() if(back) overlays_standing[BACK_LAYER] = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = 'icons/mob/clothing/back.dmi', override_state = back.icon_state) @@ -134,9 +134,9 @@ if(!get_bodypart(BODY_ZONE_HEAD)) //Decapitated return - if(client && hud_used && hud_used.inv_slots[SLOT_BACK]) + if(client && hud_used) var/obj/screen/inventory/inv = hud_used.inv_slots[SLOT_HEAD] - inv.update_icon() + inv?.update_icon() if(head) overlays_standing[HEAD_LAYER] = head.build_worn_icon(default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/clothing/head.dmi', override_state = head.icon_state) @@ -191,15 +191,6 @@ /mob/living/carbon/proc/update_hud_back(obj/item/I) return - - -//Overlays for the worn overlay so you can overlay while you overlay -//eg: ammo counters, primed grenade flashing, etc. -//"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file -/obj/item/proc/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE) - . = list() - - /mob/living/carbon/update_body() update_body_parts() diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 35b49cce8e..f90b285d2d 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -354,7 +354,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(cultslurring) message = cultslur(message) - + if(clockcultslurring) message = CLOCK_CULT_SLUR(message) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 3c3612f434..439bedf3cc 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -400,10 +400,9 @@ action.button_icon_state = "wrap_[active]" action.UpdateButtonIcon() -/obj/effect/proc_holder/wrap/Click() - if(!istype(usr, /mob/living/simple_animal/hostile/poison/giant_spider/nurse)) +/obj/effect/proc_holder/wrap/Trigger(mob/living/simple_animal/hostile/poison/giant_spider/nurse/user) + if(!istype(user)) return TRUE - var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = usr activate(user) return TRUE @@ -444,7 +443,7 @@ check_flags = AB_CHECK_CONSCIOUS button_icon_state = "lay_eggs" -/datum/action/innate/spider/lay_eggs/IsAvailable() +/datum/action/innate/spider/lay_eggs/IsAvailable(silent = FALSE) if(..()) if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse)) return 0 @@ -508,7 +507,7 @@ desc = "Send a command to all living spiders." button_icon_state = "command" -/datum/action/innate/spider/comm/IsAvailable() +/datum/action/innate/spider/comm/IsAvailable(silent = FALSE) if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife)) return FALSE return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index 6ec8e0cfd2..138d7f155e 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -11,6 +11,7 @@ speed = 0 maxHealth = 250 health = 250 + blood_volume = 0 gender = NEUTER mob_biotypes = NONE diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm index bf80ab9ff4..4f8e271d6f 100644 --- a/code/modules/mob/living/simple_animal/slime/powers.dm +++ b/code/modules/mob/living/simple_animal/slime/powers.dm @@ -11,7 +11,7 @@ background_icon_state = "bg_alien" var/needs_growth = NO_GROWTH_NEEDED -/datum/action/innate/slime/IsAvailable() +/datum/action/innate/slime/IsAvailable(silent = FALSE) if(..()) var/mob/living/simple_animal/slime/S = owner if(needs_growth == GROWTH_NEEDED) diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index e5aaa016bd..536eacca7d 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -1,4 +1,5 @@ /mob/Logout() + SEND_SIGNAL(src, COMSIG_MOB_CLIENT_LOGOUT, client) log_message("[key_name(src)] is no longer owning mob [src]([src.type])", LOG_OWNERSHIP) SStgui.on_logout(src) unset_machine() diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 4d9d15ae5c..ffc0970bdf 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -353,7 +353,7 @@ if(m_intent == MOVE_INTENT_RUN) m_intent = MOVE_INTENT_WALK else - if (HAS_TRAIT(src,TRAIT_NORUNNING)) // FULPSTATION 7/10/19 So you can't run during fortitude. + if (HAS_TRAIT(src,TRAIT_NORUNNING)) to_chat(src, "You find yourself unable to run.") return FALSE m_intent = MOVE_INTENT_RUN diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 835055ea48..36005232f3 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -257,6 +257,7 @@ /obj/machinery/light/small/built icon_state = "bulb-empty" + start_with_cell = FALSE /obj/machinery/light/small/built/Initialize() . = ..() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index dd40648191..9c1a23174e 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -513,7 +513,7 @@ icon_icon = 'icons/mob/actions/actions_items.dmi' button_icon_state = "sniper_zoom" -/datum/action/item_action/toggle_scope_zoom/IsAvailable() +/datum/action/item_action/toggle_scope_zoom/IsAvailable(silent = FALSE) . = ..() if(!.) var/obj/item/gun/G = target diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 7695ef77be..5f2edd5206 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -284,7 +284,7 @@ if(L.mind) L.mind.transfer_to(S) if(owner) - to_chat(S, "You are an animate statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved! Do not harm [owner], your creator.") + to_chat(S, "You are an animated statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved! Do not harm [owner], your creator.") P.forceMove(S) return else diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 384a113b27..5eb5b94de9 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -214,7 +214,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) //For easy bloodsucker disgusting and blood removal /datum/reagent/proc/disgust_bloodsucker(mob/living/carbon/C, disgust, blood_change, blood_puke = TRUE, force) - if(isvamp(C)) + if(AmBloodsucker(C)) var/datum/antagonist/bloodsucker/bloodsuckerdatum = C.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) if(disgust) bloodsuckerdatum.handle_eat_human_food(disgust, blood_puke, force) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index da461ef4ff..7ee233b449 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -579,7 +579,7 @@ All effects don't start immediately, but rather get worse over time; the rate is value = 1.3 /datum/reagent/consumable/ethanol/bloody_mary/on_mob_life(mob/living/carbon/C) - if(isvamp(C)) + if(AmBloodsucker(C)) disgust_bloodsucker(FALSE, 1) //Bloodsuckers get SOME blood from it, for style reasons. if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio)) C.blood_volume = min((BLOOD_VOLUME_NORMAL*C.blood_ratio), C.blood_volume + 3) //Bloody Mary quickly restores blood loss. diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index fa30609c54..c003fc7111 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -18,6 +18,7 @@ /datum/reagent/consumable/on_mob_life(mob/living/carbon/M) current_cycle++ M.nutrition += nutriment_factor + M.CheckBloodsuckerEatFood(nutriment_factor) holder.remove_reagent(type, metabolization_rate) /datum/reagent/consumable/reaction_mob(mob/living/M, method=TOUCH, reac_volume) @@ -423,6 +424,50 @@ M.emote(pick("twitch","giggle")) ..() +/datum/reagent/consumable/garlic //NOTE: having garlic in your blood stops vampires from biting you. + name = "Garlic Juice" + //id = "garlic" + description = "Crushed garlic. Chefs love it, but it can make you smell bad." + color = "#FEFEFE" + taste_description = "garlic" + metabolization_rate = 0.15 * REAGENTS_METABOLISM + +/datum/reagent/consumable/garlic/on_mob_life(mob/living/carbon/M) + if(isvampire(M)) //incapacitating but not lethal. Unfortunately, vampires cannot vomit. + if(prob(min(25, current_cycle))) + to_chat(M, "You can't get the scent of garlic out of your nose! You can barely think...") + M.Stun(10) + M.Jitter(10) + return + + else if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.job == "Cook") + if(prob(20)) //stays in the system much longer than sprinkles/banana juice, so heals slower to partially compensate + H.heal_bodypart_damage(1, 1, 0) + . = 1 + ..() + +/datum/reagent/consumable/garlic/reaction_mob(mob/living/M, method, reac_volume) + if(AmBloodsucker(M, TRUE)) //Theyll be immune to garlic as long as they masquarade, but they cant do it if they already have it. + switch(method) + if(INGEST) + if(prob(min(30, current_cycle))) + to_chat(M, "You cant get the smell of garlic out of your nose! You cant think straight because of it!") + M.Jitter(15) + if(prob(min(15, current_cycle))) + M.visible_message("Something you ate is burning your stomach!", "[M] clutches their stomach and falls to the ground!") + M.Knockdown(20) + M.emote("scream") + if(prob(min(5, current_cycle)) && iscarbon(M)) + var/mob/living/carbon/C + C.vomit() + if(INJECT) + if(prob(min(20, current_cycle))) + to_chat(M, "You feel like your veins are boiling!") + M.emote("scream") + M.adjustFireLoss(5) + ..() /datum/reagent/consumable/sprinkles name = "Sprinkles" value = 3 diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 03488fa8a9..143fe508b6 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -45,6 +45,12 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th /obj/effect/proc_holder/singularity_pull() return +/obj/effect/proc_holder/Click() + return Trigger(usr, FALSE) + +/obj/effect/proc_holder/proc/Trigger(mob/user) + return TRUE + /obj/effect/proc_holder/proc/InterceptClickOn(mob/living/caller, params, atom/A) if(caller.ranged_ability != src || ranged_ability_user != caller) //I'm not actually sure how these would trigger, but, uh, safety, I guess? to_chat(caller, "[caller.ranged_ability.name] has been disabled.") @@ -150,8 +156,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(mobs_blacklist) mobs_blacklist = typecacheof(mobs_blacklist) -/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = FALSE, mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell - if(!can_cast(user, skipcharge)) +/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = FALSE, mob/user = usr, skip_can_cast = FALSE) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell + if(!skip_can_cast && !can_cast(user, skipcharge)) return FALSE if(!skipcharge) @@ -181,17 +187,22 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th return TRUE /obj/effect/proc_holder/spell/proc/invocation(mob/user = usr) //spelling the spell out and setting it on recharge/reducing charges amount + var/mob/living/L + if(isliving(user)) + L = user switch(invocation_type) if("shout") - if(prob(50))//Auto-mute? Fuck that noise - user.say(invocation, forced = "spell") - else - user.say(replacetext(invocation," ","`"), forced = "spell") + if(!L || L.can_speak_vocal(invocation)) + if(prob(50))//Auto-mute? Fuck that noise + user.say(invocation, forced = "spell") + else + user.say(replacetext(invocation," ","`"), forced = "spell") if("whisper") - if(prob(50)) - user.whisper(invocation) - else - user.whisper(replacetext(invocation," ","`")) + if(!L || L.can_speak_vocal(invocation)) + if(prob(50)) + user.whisper(invocation) + else + user.whisper(replacetext(invocation," ","`")) if("emote") user.visible_message(invocation, invocation_emote_self) //same style as in mob/living/emote.dm @@ -210,8 +221,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th qdel(action) return ..() -/obj/effect/proc_holder/spell/Click() - if(cast_check()) +/obj/effect/proc_holder/spell/Trigger(mob/user, skip_can_cast = TRUE) + if(cast_check(FALSE, user, skip_can_cast)) choose_targets() return 1 @@ -432,7 +443,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th return 1 /obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE) - var/magic_flags = SEND_SIGNAL(user, COMSIG_MOB_SPELL_CAST_CHECK, src) + var/magic_flags = SEND_SIGNAL(user, COMSIG_MOB_SPELL_CAN_CAST, src) if(magic_flags & SPELL_SKIP_ALL_REQS) return TRUE @@ -448,9 +459,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th to_chat(user, "You can't cast this spell here.") return FALSE - if(!skipcharge) - if(!charge_check(user)) - return FALSE + if(!skipcharge && !charge_check(user, silent)) + return FALSE if(user.stat && !stat_allowed && !(magic_flags & SPELL_SKIP_STAT)) if(!silent) diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm index 786026a1bc..1a904b1076 100644 --- a/code/modules/spells/spell_types/aimed.dm +++ b/code/modules/spells/spell_types/aimed.dm @@ -11,12 +11,11 @@ var/current_amount = 0 //How many projectiles left. var/projectiles_per_fire = 1 //Projectiles per fire. Probably not a good thing to use unless you override ready_projectile(). -/obj/effect/proc_holder/spell/aimed/Click() - var/mob/living/user = usr +/obj/effect/proc_holder/spell/aimed/Trigger(mob/user, skip_can_cast = TRUE) if(!istype(user)) return var/msg - if(!can_cast(user, FALSE, TRUE)) + if(!skip_can_cast && !can_cast(user, FALSE, TRUE)) msg = "You can no longer cast [name]!" remove_ranged_ability(msg) return diff --git a/code/modules/spells/spell_types/lightning.dm b/code/modules/spells/spell_types/lightning.dm index 81b26cf464..d0c3c4166c 100644 --- a/code/modules/spells/spell_types/lightning.dm +++ b/code/modules/spells/spell_types/lightning.dm @@ -15,9 +15,9 @@ action_icon_state = "lightning" -/obj/effect/proc_holder/spell/targeted/tesla/Click() - if(!ready && cast_check()) - StartChargeup() +/obj/effect/proc_holder/spell/targeted/tesla/Trigger(mob/user, skip_can_cast = TRUE) + if(!ready && cast_check(FALSE, user, skip_can_cast)) + StartChargeup(user) return 1 /obj/effect/proc_holder/spell/targeted/tesla/proc/StartChargeup(mob/user = usr) diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm index a3bb81ae55..8f39da5031 100644 --- a/code/modules/spells/spell_types/mime.dm +++ b/code/modules/spells/spell_types/mime.dm @@ -16,12 +16,12 @@ action_icon_state = "mime" action_background_icon_state = "bg_mime" -/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click() - if(usr && usr.mind) - if(!usr.mind.miming) +/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Trigger(mob/user, skip_can_cast = TRUE) + if(user.mind) + if(!user.mind.miming) to_chat(usr, "You must dedicate yourself to silence first.") return - invocation = "[usr.real_name] looks as if a wall is in front of [usr.p_them()]." + invocation = "[user.real_name] looks as if a wall is in front of [user.p_them()]." else invocation_type ="none" ..() @@ -41,17 +41,12 @@ action_icon_state = "mime" action_background_icon_state = "bg_mime" -/obj/effect/proc_holder/spell/targeted/mime/speak/Click() - if(!usr) - return - if(!ishuman(usr)) - return - var/mob/living/carbon/human/H = usr - if(H.mind.miming) +/obj/effect/proc_holder/spell/targeted/mime/speak/Trigger(mob/user, skip_can_cast = TRUE) + if(user.mind?.miming) still_recharging_msg = "You can't break your vow of silence that fast!" else still_recharging_msg = "You'll have to wait before you can give your vow of silence again!" - ..() + return ..() /obj/effect/proc_holder/spell/targeted/mime/speak/cast(list/targets,mob/user = usr) for(var/mob/living/carbon/human/H in targets) @@ -82,15 +77,15 @@ action_icon_state = "mime" action_background_icon_state = "bg_mime" -/obj/effect/proc_holder/spell/targeted/forcewall/mime/Click() - if(usr && usr.mind) - if(!usr.mind.miming) +/obj/effect/proc_holder/spell/targeted/forcewall/mime/Trigger(mob/user, skip_can_cast = TRUE) + if(user.mind) + if(!user.mind.miming) to_chat(usr, "You must dedicate yourself to silence first.") return - invocation = "[usr.real_name] looks as if a blockade is in front of [usr.p_them()]." + invocation = "[user.real_name] looks as if a blockade is in front of [user.p_them()]." else invocation_type ="none" - ..() + return ..() /obj/effect/proc_holder/spell/aimed/finger_guns name = "Finger Guns" @@ -114,19 +109,18 @@ base_icon_state = "mime" -/obj/effect/proc_holder/spell/aimed/finger_guns/Click() - var/mob/living/carbon/human/owner = usr - if(owner.incapacitated()) - to_chat(owner, "You can't properly point your fingers while incapacitated.") +/obj/effect/proc_holder/spell/aimed/finger_guns/Trigger(mob/user, skip_can_cast = TRUE) + if(user.incapacitated()) + to_chat(user, "You can't properly point your fingers while incapacitated.") return - if(usr && usr.mind) - if(!usr.mind.miming) + if(user.mind) + if(!user.mind.miming) to_chat(usr, "You must dedicate yourself to silence first.") return - invocation = "[usr.real_name] fires [usr.p_their()] finger gun!" + invocation = "[user.real_name] fires [user.p_their()] finger gun!" else invocation_type ="none" - ..() + return ..() /obj/effect/proc_holder/spell/targeted/touch/mimerope name = "Invisible Rope" @@ -144,8 +138,8 @@ action_background_icon_state = "bg_mime" hand_path = /obj/item/melee/touch_attack/mimerope -/obj/effect/proc_holder/spell/targeted/touch/mimerope/Click() - if(usr && usr.mind) +/obj/effect/proc_holder/spell/targeted/touch/mimerope/Trigger(mob/user, skip_can_cast = TRUE) + if(user.mind) if(!usr.mind.miming) to_chat(usr, "You must dedicate yourself to silence first.") return diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 7c849dbd68..671d31530a 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -74,7 +74,7 @@ ..() cords = target -/datum/action/item_action/organ_action/colossus/IsAvailable() +/datum/action/item_action/organ_action/colossus/IsAvailable(silent = FALSE) if(world.time < cords.next_command) return FALSE if(!owner) @@ -632,7 +632,7 @@ ..() cords = target -/datum/action/item_action/organ_action/velvet/IsAvailable() +/datum/action/item_action/organ_action/velvet/IsAvailable(silent = FALSE) return TRUE /datum/action/item_action/organ_action/velvet/Trigger() diff --git a/code/modules/uplink/uplink_items/uplink_clothing.dm b/code/modules/uplink/uplink_items/uplink_clothing.dm index aad9834612..d6336bd982 100644 --- a/code/modules/uplink/uplink_items/uplink_clothing.dm +++ b/code/modules/uplink/uplink_items/uplink_clothing.dm @@ -83,4 +83,10 @@ name = "Thieving Gloves" desc = "A pair of gloves that are insulated and frictionless, allowing you to steal easily from anyone you see." item = /obj/item/clothing/gloves/thief - cost = 4 \ No newline at end of file + cost = 4 + +/datum/uplink_item/suits/wallwalkers + name = "Wall Walking Boots" + desc = "Through bluespace magic stolen from an organisation that hoards technology, these boots simply allow you to slip through the atoms that make up anything, but only while walking, for safety reasons. As well as this, they unfortunately cause minor breath loss as the majority of atoms in your lungs are sucked out into any solid object you walk through." + item = /obj/item/clothing/shoes/wallwalkers + cost = 6 \ No newline at end of file diff --git a/code/modules/uplink/uplink_items/uplink_devices.dm b/code/modules/uplink/uplink_items/uplink_devices.dm index 1a7345a3ae..194281ded6 100644 --- a/code/modules/uplink/uplink_items/uplink_devices.dm +++ b/code/modules/uplink/uplink_items/uplink_devices.dm @@ -20,6 +20,12 @@ item = /obj/item/emagrecharge cost = 2 +/datum/uplink_item/device_tools/bluespacerecharge + name = "Bluespace Crystal Recharging Device" + desc = "A small device intended for recharging Wall Walking boots. Using it will add six charges to them. Use ten bluespace crystals on this recharger to add three more charges to it. " + item = /obj/item/bluespacerecharge + cost = 2 + /datum/uplink_item/device_tools/phantomthief name = "Syndicate Mask" desc = "A cheap plastic mask fitted with an adrenaline autoinjector, which can be used by simply tensing your muscles" diff --git a/config/config.txt b/config/config.txt index fd5dc968fb..35af0e848b 100644 --- a/config/config.txt +++ b/config/config.txt @@ -510,13 +510,16 @@ DEFAULT_VIEW 21x15 ### FAIL2TOPIC: ### Automated IP bans for world/Topic() spammers +### NOTE FOR WINDOWS HOSTS: This requires you to be running dreamdaemon as an administrator for it to work at all. TGS3 handles this automatically, and honestly there's no reason not to be using TGS3 if you're hosting on Windows. +### NOTE FOR LINUX HOSTS: This requires manual setup of iptables. Beware that improper configuration of this can and will irreversibly fuck up a server, so please don't tinker with it if you don't know what you're doing. ## Enabled -FAIL2TOPIC_ENABLED +#FAIL2TOPIC_ENABLED ## Minimum wait time in deciseconds between valid requests FAIL2TOPIC_RATE_LIMIT 10 ## Number of requests after breaching rate limit that triggers a ban FAIL2TOPIC_MAX_FAILS 5 ## Firewall rule name used on physical server +## FOR LINUX HOSTS: This is used as the chain name. The iptables chain doesn't get created or hooked up to INPUT automatically, so you'll have to get that set up yourself. Recommended name: BYOND FAIL2TOPIC_RULE_NAME _dd_fail2topic ## Enable automatic profiling - Byond 513.1506 and newer only. diff --git a/config/game_options.txt b/config/game_options.txt index c3930fd325..8c48ac6ede 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -620,3 +620,16 @@ BREASTS_CUPS_PREFS e ## Minimum and maximum limits for penis length from the character creation menu. PENIS_MIN_INCHES_PREFS 1 PENIS_MAX_INCHES_PREFS 20 + +## Body size configs, the feature will be disabled if both min and max have the same value. +BODY_SIZE_MIN 1 +BODY_SIZE_MAX 1 + +## Pun-Pun movement slowdown given to characters with a body size smaller than this value, +## to compensate for their smaller hitbox. +## To disable, just make sure the value is lower than 'body_size_min' +THRESHOLD_BODY_SIZE_SLOWDOWN 0.85 + +## Multiplier used in the smaller strides slowdown calculation. +## Doesn't apply to floating or crawling mobs. +BODY_SIZE_SLOWDOWN_MULTIPLIER 0.25 \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-10986.yml b/html/changelogs/AutoChangeLog-pr-10986.yml new file mode 100644 index 0000000000..bac7b9692a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10986.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - rscadd: "wall walking boots" diff --git a/html/changelogs/AutoChangeLog-pr-11275.yml b/html/changelogs/AutoChangeLog-pr-11275.yml new file mode 100644 index 0000000000..5a3ce31631 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11275.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - rscadd: "Reenabled the swarmers event. Also blacklisted another dozen other machineries and structures that may be critical to the shift or station integrity from swarmers' HUNGER for materials." + - bugfix: "Fixed find_safe_turfs() searching for turfs with concentration of oxygen lower than 16 rather higher." diff --git a/html/changelogs/AutoChangeLog-pr-11379.yml b/html/changelogs/AutoChangeLog-pr-11379.yml new file mode 100644 index 0000000000..319d4b2140 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11379.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - refactor: "refactored polychromic clothing into an element." diff --git a/html/changelogs/AutoChangeLog-pr-11618.yml b/html/changelogs/AutoChangeLog-pr-11618.yml new file mode 100644 index 0000000000..99acbbeef5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11618.yml @@ -0,0 +1,12 @@ +author: "Arturlang" +delete-after: True +changes: + - rscadd: "Adds garlic, a mutation of onions" + - rscadd: "You can now make garlic necklaces." + - tweak: "Tweaked hunger to be more the same as blood level for bloodsuckers" + - tweak: "Bloodsuckers no longer get zero healing from regenerative cores, the core now heals their wounds but not their blood." + - balance: "Bloodsucker heal is now based a lot more on blood level." + - bugfix: "You can no longer be effectively immortal when fully auged as a bloodsucker." + - bugfix: "Regenerative cores will regain their old names when they are renewed, no more working decayed cores." + - code_imp: "Removes a lot of unnecesiry clutter of comments and tries to make the vars more consistent for bloodsucker code." + - code_imp: "Made the regenerative core use one proc instead of copypasta" diff --git a/html/changelogs/AutoChangeLog-pr-11655.yml b/html/changelogs/AutoChangeLog-pr-11655.yml new file mode 100644 index 0000000000..7acbf5efa7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11655.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - balance: "The crusher's vortex talisman trophy now has a cooldown between each spawned wall." diff --git a/html/changelogs/AutoChangeLog-pr-11809.yml b/html/changelogs/AutoChangeLog-pr-11809.yml new file mode 100644 index 0000000000..92c882825f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11809.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - rscadd: "Volumetric storage is here." diff --git a/html/changelogs/AutoChangeLog-pr-11819.yml b/html/changelogs/AutoChangeLog-pr-11819.yml new file mode 100644 index 0000000000..6619f26aba --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11819.yml @@ -0,0 +1,5 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Wizard robes & co work again now." + - bugfix: "Fixed some spell casting message spam." diff --git a/html/changelogs/AutoChangeLog-pr-11824.yml b/html/changelogs/AutoChangeLog-pr-11824.yml new file mode 100644 index 0000000000..2b91fc5564 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11824.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixed yet another few airless issues with the space hermit ruin." diff --git a/html/changelogs/AutoChangeLog-pr-11826.yml b/html/changelogs/AutoChangeLog-pr-11826.yml new file mode 100644 index 0000000000..4ffe43239d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11826.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - refactor: "Backend body size preferences." diff --git a/html/changelogs/AutoChangeLog-pr-11828.yml b/html/changelogs/AutoChangeLog-pr-11828.yml new file mode 100644 index 0000000000..067963046f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11828.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed toilet cistern loot spawning on the floor." diff --git a/html/changelogs/AutoChangeLog-pr-11829.yml b/html/changelogs/AutoChangeLog-pr-11829.yml new file mode 100644 index 0000000000..5cf966cd02 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11829.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed a whacky miniature cell duping issue." diff --git a/html/changelogs/AutoChangeLog-pr-11830.yml b/html/changelogs/AutoChangeLog-pr-11830.yml new file mode 100644 index 0000000000..79d3e7656f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11830.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed the phantom thief component, again." diff --git a/html/changelogs/AutoChangeLog-pr-11831.yml b/html/changelogs/AutoChangeLog-pr-11831.yml new file mode 100644 index 0000000000..22b0e71692 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11831.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "fixed a few floaty sprite accessories." diff --git a/html/changelogs/AutoChangeLog-pr-11834.yml b/html/changelogs/AutoChangeLog-pr-11834.yml new file mode 100644 index 0000000000..05d1b245b1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11834.yml @@ -0,0 +1,5 @@ +author: "Bhijn" +delete-after: True +changes: + - server: "Fail2Topic now supports Linux. Do beware that this requires some sysop experience to properly set up!" + - config: "Fail2Topic is now disabled by default, and the out-of-the-box config files have been updated to be a little more detailed." diff --git a/html/changelogs/AutoChangeLog-pr-11838.yml b/html/changelogs/AutoChangeLog-pr-11838.yml new file mode 100644 index 0000000000..464448c138 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11838.yml @@ -0,0 +1,4 @@ +author: "kappa-sama" +delete-after: True +changes: + - rscdel: "normies can no longer steal circuit codes" diff --git a/icons/mob/actions/backgrounds.dmi b/icons/mob/actions/backgrounds.dmi index 3697fe4ff5..07839588ce 100644 Binary files a/icons/mob/actions/backgrounds.dmi and b/icons/mob/actions/backgrounds.dmi differ diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 578970a21c..1e09dce605 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/feet_digi.dmi b/icons/mob/clothing/feet_digi.dmi index fbc105b634..626c67a71c 100644 Binary files a/icons/mob/clothing/feet_digi.dmi and b/icons/mob/clothing/feet_digi.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index c499c236e3..f2ea9fa55d 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi index de59a136d9..78073222ca 100644 Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index 195e4ecd67..a2ea222a68 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/suit_digi.dmi b/icons/mob/clothing/suit_digi.dmi index 67ad9f7e1a..5287bac43c 100644 Binary files a/icons/mob/clothing/suit_digi.dmi and b/icons/mob/clothing/suit_digi.dmi differ diff --git a/icons/mob/clothing/uniform.dmi b/icons/mob/clothing/uniform.dmi index fe0b080dc6..4485a9a5f8 100644 Binary files a/icons/mob/clothing/uniform.dmi and b/icons/mob/clothing/uniform.dmi differ diff --git a/icons/mob/clothing/uniform_digi.dmi b/icons/mob/clothing/uniform_digi.dmi index 80e8f80b94..6827581b85 100644 Binary files a/icons/mob/clothing/uniform_digi.dmi and b/icons/mob/clothing/uniform_digi.dmi differ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index ea946f60d9..60c413c372 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/icons/obj/clothing/cloaks.dmi b/icons/obj/clothing/cloaks.dmi index dd1ae7d727..6f4de62cc0 100644 Binary files a/icons/obj/clothing/cloaks.dmi and b/icons/obj/clothing/cloaks.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 07d9c8cee6..2e0906ea20 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi index 0bdaa36e62..c4c9c94f48 100644 Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index bd8d52a1e6..c4e000b700 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index 530cd61e6f..607c26bb62 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi index 55ec7669ba..dfebe38155 100644 Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi index 712ea11a3b..c93865ca77 100644 Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi index e746d8f43d..c7c31581f3 100644 Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi index 43e231cbab..62843e3f54 100644 Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi index ace24db5ff..a647bebd57 100644 Binary files a/icons/obj/module.dmi and b/icons/obj/module.dmi differ diff --git a/icons/turf/mining.dmi b/icons/turf/mining.dmi index 6561438228..335cff453e 100644 Binary files a/icons/turf/mining.dmi and b/icons/turf/mining.dmi differ diff --git a/icons/turf/smoothrocks.dmi b/icons/turf/smoothrocks.dmi index 20314cff5b..ba2bbce955 100644 Binary files a/icons/turf/smoothrocks.dmi and b/icons/turf/smoothrocks.dmi differ diff --git a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm index 6bbe947f54..1cea2dd916 100644 --- a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm @@ -23,13 +23,13 @@ icon_state = "knotted" name = "Knotted" taur_icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' - taur_dimension_y = 64 + taur_dimension_x = 64 /datum/sprite_accessory/penis/flared icon_state = "flared" name = "Flared" taur_icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' - taur_dimension_y = 64 + taur_dimension_x = 64 /datum/sprite_accessory/penis/barbknot icon_state = "barbknot" @@ -39,7 +39,7 @@ icon_state = "tapered" name = "Tapered" taur_icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' - taur_dimension_y = 64 + taur_dimension_x = 64 /datum/sprite_accessory/penis/tentacle icon_state = "tentacle" diff --git a/modular_citadel/code/modules/clothing/suits/polychromic_cloaks.dm b/modular_citadel/code/modules/clothing/suits/polychromic_cloaks.dm deleted file mode 100644 index 5cf2fccb92..0000000000 --- a/modular_citadel/code/modules/clothing/suits/polychromic_cloaks.dm +++ /dev/null @@ -1,38 +0,0 @@ -/obj/item/clothing/neck/cloak/polychromic //enables all three overlays to reduce copypasta and defines basic stuff - name = "polychromic cloak" - desc = "For when you want to show off your horrible colour coordination skills." - icon = 'modular_citadel/icons/polyclothes/item/neck.dmi' - mob_overlay_icon = 'modular_citadel/icons/polyclothes/mob/neck.dmi' - icon_state = "polyce" - item_state = "qmcloak" - hasprimary = TRUE - hassecondary = TRUE - hastertiary = TRUE - primary_color = "#FFFFFF" //RGB in hexcode - secondary_color = "#FFFFFF" - tertiary_color = "#808080" - -/obj/item/clothing/neck/cloak/polychromic/worn_overlays(isinhands, icon_file, style_flags = NONE) //this is where the main magic happens. Also mandates that ALL polychromic stuff MUST USE mob_overlay_icon - . = ..() - if(hasprimary | hassecondary | hastertiary) - if(!isinhands) //prevents the worn sprites from showing up if you're just holding them - if(hasprimary) //checks if overlays are enabled - var/mutable_appearance/primary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-primary") //automagical sprite selection - primary_worn.color = primary_color //colors the overlay - . += primary_worn //adds the overlay onto the buffer list to draw on the mob sprite. - if(hassecondary) - var/mutable_appearance/secondary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-secondary") - secondary_worn.color = secondary_color - . += secondary_worn - if(hastertiary) - var/mutable_appearance/tertiary_worn = mutable_appearance(mob_overlay_icon, "[icon_state]-tertiary") - tertiary_worn.color = tertiary_color - . += tertiary_worn - -/obj/item/clothing/neck/cloak/polychromic/polyce //DONATOR ITEM - name = "polychromic embroidered cloak" - desc = "A fancy cloak embroidered with polychromatic thread in a pattern that reminds one of the wielders of unlimited power." - icon_state = "polyce" - primary_color = "#808080" //RGB in hexcode - secondary_color = "#8CC6FF" - tertiary_color = "#FF3535" \ No newline at end of file diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm index a9b502d629..bd377d6081 100644 --- a/modular_citadel/code/modules/custom_loadout/custom_items.dm +++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm @@ -563,3 +563,8 @@ unique_reskin = list("Goodboye" = "fritz", "Badboye" = "fritz_bad") mutantrace_variation = NONE +/obj/item/clothing/neck/cloak/polychromic/polyce + name = "polychromic embroidered cloak" + desc = "A fancy cloak embroidered with polychromatic thread in a pattern that reminds one of the wielders of unlimited power." + icon_state = "polyce" + poly_colors = list("#808080", "#8CC6FF", "#FF3535") diff --git a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm index 49a8a26f35..49d48e0000 100644 --- a/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/modular_citadel/code/modules/projectiles/guns/energy/energy_gun.dm @@ -39,7 +39,7 @@ obj/item/gun/energy/e_gun/cx/AltClick(mob/living/user) body_color = sanitize_hexcolor(body_color_input, desired_format=6, include_crunch=1) update_icon() -obj/item/gun/energy/e_gun/cx/worn_overlays(isinhands, icon_file, style_flags = NONE) +obj/item/gun/energy/e_gun/cx/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) . = ..() if(isinhands) var/mutable_appearance/body_inhand = mutable_appearance(icon_file, "cxe_body") diff --git a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm index 05b5c195c2..a4b6429bea 100644 --- a/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm +++ b/modular_citadel/code/modules/projectiles/guns/pumpenergy.dm @@ -87,7 +87,7 @@ . = ..() . += "Alt-click to change firing modes." -/obj/item/gun/energy/pumpaction/worn_overlays(isinhands, icon_file, style_flags = NONE) //ammo counter for inhands +/obj/item/gun/energy/pumpaction/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE) //ammo counter for inhands . = ..() var/ratio = CEILING((cell.charge / cell.maxcharge) * charge_sections, 1) var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] diff --git a/modular_citadel/code/modules/reagents/objects/clothes.dm b/modular_citadel/code/modules/reagents/objects/clothes.dm index 4707d5b460..34af39bbe0 100644 --- a/modular_citadel/code/modules/reagents/objects/clothes.dm +++ b/modular_citadel/code/modules/reagents/objects/clothes.dm @@ -5,7 +5,7 @@ name = "Synthetic hat" icon = 'icons/obj/clothing/hats.dmi' icon_state = "cowboy" - desc = "A sythesized hat, you can't seem to take it off. And tips their hat." + desc = "A synthesized hat, you can't seem to take it off. And tips their hat." armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) //item_flags = NODROP //Tips their hat! diff --git a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi index e8efbec216..9dbed5e9f0 100644 Binary files a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi differ diff --git a/modular_citadel/icons/polyclothes/item/neck.dmi b/modular_citadel/icons/polyclothes/item/neck.dmi deleted file mode 100644 index e2792cf9d0..0000000000 Binary files a/modular_citadel/icons/polyclothes/item/neck.dmi and /dev/null differ diff --git a/modular_citadel/icons/polyclothes/mob/neck.dmi b/modular_citadel/icons/polyclothes/mob/neck.dmi deleted file mode 100644 index 529c64caa2..0000000000 Binary files a/modular_citadel/icons/polyclothes/mob/neck.dmi and /dev/null differ diff --git a/tgstation.dme b/tgstation.dme old mode 100644 new mode 100755 index 7d7dcea52f..26bb4e2e5a --- a/tgstation.dme +++ b/tgstation.dme @@ -59,7 +59,7 @@ #include "code\__DEFINES\is_helpers.dm" #include "code\__DEFINES\jobs.dm" #include "code\__DEFINES\language.dm" -#include "code\__DEFINES\layers.dm" +#include "code\__DEFINES\layers_planes.dm" #include "code\__DEFINES\lighting.dm" #include "code\__DEFINES\logging.dm" #include "code\__DEFINES\machines.dm" @@ -104,6 +104,7 @@ #include "code\__DEFINES\stat.dm" #include "code\__DEFINES\stat_tracking.dm" #include "code\__DEFINES\status_effects.dm" +#include "code\__DEFINES\storage.dm" #include "code\__DEFINES\subsystems.dm" #include "code\__DEFINES\tgs.config.dm" #include "code\__DEFINES\tgs.dm" @@ -226,6 +227,7 @@ #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\screen_objects.dm" #include "code\_onclick\hud\swarmer.dm" +#include "code\_onclick\hud\screen_objects\storage.dm" #include "code\controllers\admin.dm" #include "code\controllers\configuration_citadel.dm" #include "code\controllers\controller.dm" @@ -437,6 +439,7 @@ #include "code\datums\components\fantasy\prefixes.dm" #include "code\datums\components\fantasy\suffixes.dm" #include "code\datums\components\storage\storage.dm" +#include "code\datums\components\storage\ui.dm" #include "code\datums\components\storage\concrete\_concrete.dm" #include "code\datums\components\storage\concrete\bag_of_holding.dm" #include "code\datums\components\storage\concrete\bluespace.dm" @@ -510,6 +513,7 @@ #include "code\datums\elements\flavor_text.dm" #include "code\datums\elements\ghost_role_eligibility.dm" #include "code\datums\elements\mob_holder.dm" +#include "code\datums\elements\polychromic.dm" #include "code\datums\elements\spellcasting.dm" #include "code\datums\elements\swimming.dm" #include "code\datums\elements\sword_point.dm" @@ -1971,6 +1975,7 @@ #include "code\modules\hydroponics\grown\cotton.dm" #include "code\modules\hydroponics\grown\eggplant.dm" #include "code\modules\hydroponics\grown\flowers.dm" +#include "code\modules\hydroponics\grown\garlic.dm" #include "code\modules\hydroponics\grown\grass_carpet.dm" #include "code\modules\hydroponics\grown\kudzu.dm" #include "code\modules\hydroponics\grown\melon.dm" @@ -3290,7 +3295,6 @@ #include "modular_citadel\code\modules\client\verbs\who.dm" #include "modular_citadel\code\modules\clothing\neck.dm" #include "modular_citadel\code\modules\clothing\trek.dm" -#include "modular_citadel\code\modules\clothing\suits\polychromic_cloaks.dm" #include "modular_citadel\code\modules\clothing\suits\suits.dm" #include "modular_citadel\code\modules\custom_loadout\custom_items.dm" #include "modular_citadel\code\modules\custom_loadout\load_to_mob.dm"