Merge branch 'master' into Ghommie-cit679
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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(): ()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
#define isshuttleturf(T) (length(T.baseturfs) && (/turf/baseturf_skipover/shuttle in T.baseturfs))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
))
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]"
|
||||
|
||||
@@ -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: [.].")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
+51
-52
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = "<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>"
|
||||
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, "<span class='warning'>[host] is full, make some space!</span>")
|
||||
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, "<span class='warning'>[host] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(I.w_class > max_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too big for [host]!</span>")
|
||||
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, "<span class='warning'>[I] won't fit in [host], make some space!</span>")
|
||||
return FALSE
|
||||
// STORAGE LIMITS
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_ITEMS)
|
||||
if(real_location.contents.len >= max_items)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] has too many things in it, make some space!</span>")
|
||||
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, "<span class='warning'>[I] is too long for [host]!</span>")
|
||||
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, "<span class='warning'>[I] won't fit in [host], make some space!</span>")
|
||||
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, "<span class='warning'>[I] is too spacious to fit in [host], make some space!</span>")
|
||||
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("<span class='warning'>[user] draws [I] from [parent]!</span>", "<span class='notice'>You draw [I] from [parent].</span>")
|
||||
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)
|
||||
|
||||
@@ -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 = "<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>"
|
||||
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, "<span class='warning'>[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!</span>")
|
||||
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, "<span class='warning'>[parent] rendered in overrun mode due to more items inside than the maximum volume supports.</span>")
|
||||
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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/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)
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
+1
-4
@@ -584,11 +584,8 @@
|
||||
stoplag(1)
|
||||
qdel(progress)
|
||||
to_chat(user, "<span class='notice'>You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.</span>")
|
||||
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)
|
||||
|
||||
@@ -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, "<span class='danger'>Your blood is too thin to turn this corpse!</span>")
|
||||
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, "<span class='danger'>[target] isn't self-aware enough to be made into a Vassal.</span>")
|
||||
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, "<span class='danger'>[target] is already your loyal Vassal!</span>")
|
||||
else
|
||||
if (display_warning)
|
||||
if(display_warning)
|
||||
to_chat(creator, "<span class='danger'>[target] is the loyal Vassal of another Bloodsucker!</span>")
|
||||
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, "<span class='danger'>[target] resists the power of your blood to dominate their mind!</span>")
|
||||
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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@
|
||||
. = ..()
|
||||
. += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
to_chat(user, "<span class='notice'> [M] is at full health.</span>")
|
||||
return FALSE
|
||||
user.visible_message("<span class='green'>[user] applies \the [src] on [M].</span>", "<span class='green'>You apply \the [src] on [M].</span>")
|
||||
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, "<span class='notice'>You can't heal [M] with the \the [src]!</span>")
|
||||
|
||||
/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
else
|
||||
I.forceMove(drop_location())
|
||||
to_chat(user, "<span class='notice'>You find [I] in the cistern.</span>")
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, "<span class='warning'>Without a heart, you are incapable of [displaymessage].</span>")
|
||||
@@ -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)
|
||||
|
||||
@@ -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, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
|
||||
@@ -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, "<span class='notice'>Your flesh knits as it regrows [L]!</span>")
|
||||
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, "<span class='notice'>Your flesh knits as it regrows your [L]!</span>")
|
||||
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, "<span class='notice'>Your body expels the [BP]!</span>")
|
||||
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, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
|
||||
sleep(30) //To avoid spam
|
||||
if (poweron_masquerade == TRUE)
|
||||
if(poweron_masquerade == TRUE)
|
||||
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
|
||||
// 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("<span class='warning'>[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.</span>", \
|
||||
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
|
||||
"<span class='italics'>You hear a dry, crackling sound.</span>")
|
||||
sleep(50)
|
||||
owner.current.dust()
|
||||
// Fledglings get Gibbed
|
||||
else
|
||||
owner.current.visible_message("<span class='warning'>[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.</span>", \
|
||||
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
|
||||
"<span class='italics'>You hear a wet, bursting sound.</span>")
|
||||
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
|
||||
|
||||
@@ -93,6 +93,14 @@
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>You have a stake in your chest! Your powers are useless.</span>")
|
||||
return FALSE
|
||||
if(istype(owner.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'The necklace on your neck is interfering with your powers!</span>")
|
||||
return FALSE
|
||||
if(owner.reagents?.has_reagent(/datum/reagent/consumable/garlic))
|
||||
if(display_error)
|
||||
to_chat(owner, "<span class='warning'>Garlic in your blood is interfering with your powers!</span>")
|
||||
return FALSE
|
||||
// Incap?
|
||||
if(must_be_capacitated)
|
||||
var/mob/living/L = owner
|
||||
|
||||
@@ -141,23 +141,23 @@
|
||||
if(!bloodsuckerdatum.warn_sun_locker)
|
||||
to_chat(M, "<span class='warning'>Your skin sizzles. The [M.current.loc] doesn't protect well against UV bombardment.</span>")
|
||||
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, "<span class='userdanger'>The solar flare sets your skin ablaze!</span>")
|
||||
else
|
||||
to_chat(M, "<span class='userdanger'>The solar flare scalds your neophyte skin!</span>")
|
||||
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)
|
||||
|
||||
|
||||
@@ -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, "<span class='userdanger'>You are [fullname], a bloodsucking vampire!</span><br>")
|
||||
to_chat(owner, "<span class='userdanger'>You are [fullname], a strain of vampire dubbed bloodsucker!</span><br>")
|
||||
owner.announce_objectives()
|
||||
to_chat(owner, "<span class='boldannounce'>* 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!</span><br>")
|
||||
//to_chat(owner, "<span class='boldannounce'>As an immortal, your power is linked to your age. The older you grow, the more abilities you will have access to.<span>")
|
||||
var/vamp_greet
|
||||
vamp_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
|
||||
vamp_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
|
||||
vamp_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
|
||||
vamp_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
|
||||
vamp_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
|
||||
to_chat(owner, vamp_greet)
|
||||
var/bloodsucker_greet
|
||||
bloodsucker_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
|
||||
bloodsucker_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
|
||||
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
|
||||
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
|
||||
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
|
||||
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 <b>[fullname]</b>.<br>"
|
||||
@@ -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, "<span class='announce'>You have earned a title! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
|
||||
// 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, "<span class='announce'>You have earned a reputation! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
|
||||
|
||||
// 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, "<EM><span class='notice'>You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.</span></EM>")
|
||||
if(vamplevel_unspent >= 2)
|
||||
if(bloodsucker_level_unspent >= 2)
|
||||
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.</span><br>")
|
||||
|
||||
/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, "<span class='warning'>Return to your coffin to advance your Rank.</span>")
|
||||
@@ -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, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, health, feed rate, regen rate, and maximum blood have all increased!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>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!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Your existing powers have all ranked up as well!</span>")
|
||||
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 = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
|
||||
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
|
||||
|
||||
/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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
. += {"<span class='cult'>This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service.</span>"}
|
||||
. += {"<span class='cult'>You need to first secure the vassal rack by clicking on it while it is in your lair.</span>"}
|
||||
. += {"<span class='cult'>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.</span>"}
|
||||
. += {"<span class='cult'>Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant.</span>"}
|
||||
. += {"<span class='cult'>To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools.</span>"}
|
||||
. += {"<span class='cult'> You have only the power for [B.bloodsucker_level - B.count_vassals(user.mind)] vassals</span>"}
|
||||
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
|
||||
. += {"<span class='cult'>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, "<span class='danger'>Until this rack is secured in place, it cannot serve its purpose.</span>")
|
||||
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("<span class='danger'>[user] tries to release themself from the rack!</span>",\
|
||||
"<span class='danger'>You attempt to release yourself from the rack!</span>") // For sound if not seen --> "<span class='italics'>You hear a squishy wet noise.</span>")
|
||||
@@ -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, "<span class='danger'>You don't have a lair. Claim a coffin to make that location your lair.</span>")
|
||||
if(bloodsuckerdatum.lair != get_area(src))
|
||||
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [bloodsuckerdatum.lair].</span>")
|
||||
if(B.lair != get_area(src))
|
||||
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [B.lair].</span>")
|
||||
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, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
|
||||
return
|
||||
if(B.count_vassals(user.mind) > B.bloodsucker_level)
|
||||
to_chat(user, "<span class='notice'>Your power is yet too weak to bring more vassals under your control....</span>")
|
||||
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, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!</span>")
|
||||
if(user.blood_volume < CONVERT_COST)
|
||||
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [CONVERT_COST - user.blood_volume] units more!</span>")
|
||||
useLock = FALSE
|
||||
return
|
||||
bloodsuckerdatum.AddBloodVolume(-convert_cost)
|
||||
target.add_mob_blood(user)
|
||||
B.AddBloodVolume(-CONVERT_COST)
|
||||
target.add_mob_blood(user, "<span class='danger'>Youve used [CONVERT_COST] amount of blood to gain a new vassal!</span>")
|
||||
to_chat(user, )
|
||||
user.visible_message("<span class='notice'>[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!</span>", \
|
||||
"<span class='notice'>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.</span>")
|
||||
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, "<span class='danger'><i>The ritual has been interrupted!</i></span>")
|
||||
// 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))
|
||||
. += {"<span class='cult'>This is a magical candle which drains at the sanity of mortals who are not under your command while it is active.</span>"}
|
||||
. += {"<span class='cult'>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.</span>"}
|
||||
/* 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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
to_chat(user, "<span class='notice'>You lean quietly toward [target] and secretly draw out your fangs...</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You pull [target] close to you and draw out your fangs...</span>")
|
||||
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, "<span class='warning'>Your feeding was interrupted.</span>")
|
||||
//DeactivatePower(user,target)
|
||||
return
|
||||
@@ -166,7 +166,7 @@
|
||||
var/deadmessage = target.stat == DEAD ? "" : " <i>[target.p_they(TRUE)] looks dazed, and will not remember this.</i>"
|
||||
user.visible_message("<span class='notice'>[user] puts [target]'s wrist up to [user.p_their()] mouth.</span>", \
|
||||
"<span class='notice'>You secretly slip your fangs into [target]'s wrist.[deadmessage]</span>", \
|
||||
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, "<span class='notice'>Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.</span>")
|
||||
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, "<span class='notice'>You are full. Further blood will be wasted.</span>")
|
||||
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, "<span class='warning'>Your victim's blood volume is fatally low!</span>")
|
||||
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)
|
||||
|
||||
@@ -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, "<span class='notice'>You trip off the [V], your muscles too heavy for it to support you.</span>")
|
||||
else
|
||||
V.unbuckle_mob(user, force = TRUE)
|
||||
to_chat(user, "<span class='notice'>You fall off the [V], your weight making you too heavy to be supported by it.</span>")
|
||||
// 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.
|
||||
|
||||
@@ -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?"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!</span>")
|
||||
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, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!</b></span>")
|
||||
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, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -416,6 +416,57 @@
|
||||
to_chat(S, "<span class='warning'>Destroying this object would cause a catastrophic chain reaction. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/ore_silo/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>Destroying this object, however tempting it's, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/rnd/server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>Destroying this object, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) //pool's closed, but not.
|
||||
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/structure/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
|
||||
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, "<span class='warning'>Destroying this holographic barrier may not benefit us. Aborting.</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/bsa_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/bsa/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/dna_vault/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/structure/filler/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/computer/sat_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/satellite/meteor_shield/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
|
||||
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, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
|
||||
return FALSE
|
||||
var/resource_gain = target.IntegrateAmount()
|
||||
if(resources + resource_gain > max_resources)
|
||||
to_chat(src, "<span class='warning'>We cannot hold more materials!</span>")
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 += "<a href='?_src_=prefs;preference=name;task=input'>[real_name]</a><BR>"
|
||||
dat += "<a href='?_src_=prefs;preference=nameless'>Be nameless: [nameless ? "Yes" : "No"]</a><BR>"
|
||||
|
||||
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
|
||||
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender;task=input'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
|
||||
dat += "<b>Age:</b> <a style='display:block;width:30px' href='?_src_=prefs;preference=age;task=input'>[age]</a><BR>"
|
||||
|
||||
dat += "<b>Special Names:</b><BR>"
|
||||
@@ -345,7 +346,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
else
|
||||
dat += "[TextPreview(features["flavor_text"])]...<BR>"
|
||||
dat += "<h2>Body</h2>"
|
||||
dat += "<b>Gender:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
|
||||
dat += "<b>Gender:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=gender;task=input'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
|
||||
if(gender != NEUTER && pref_species.sexes)
|
||||
dat += "<b>Body Model:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=body_model'>[features["body_model"] == MALE ? "Masculine" : "Feminine"]</a><BR>"
|
||||
dat += "<b>Species:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=species;task=input'>[pref_species.name]</a><BR>"
|
||||
@@ -379,6 +380,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[features["mcolor3"]];'> </span> <a href='?_src_=prefs;preference=mutant_color3;task=input'>Change</a><BR>"
|
||||
mutant_colors = TRUE
|
||||
|
||||
if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max))
|
||||
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]]%</a><br>"
|
||||
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 += "</span>"
|
||||
. += how_cool_are_your_threads.Join()
|
||||
if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled
|
||||
. += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/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, "<span class='warning'>You have moved too far away!</span>")
|
||||
return
|
||||
sensor_mode = modes.Find(switchMode) - 1
|
||||
|
||||
if (src.loc == usr)
|
||||
switch(sensor_mode)
|
||||
if(0)
|
||||
to_chat(usr, "<span class='notice'>You disable your suit's remote sensing equipment.</span>")
|
||||
if(1)
|
||||
to_chat(usr, "<span class='notice'>Your suit will now only report whether you are alive or dead.</span>")
|
||||
if(2)
|
||||
to_chat(usr, "<span class='notice'>Your suit will now only report your exact vital lifesigns.</span>")
|
||||
if(3)
|
||||
to_chat(usr, "<span class='notice'>Your suit will now report your exact vital lifesigns as well as your coordinate position.</span>")
|
||||
|
||||
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, "<span class='notice'>Your suit will now report your exact vital lifesigns as well as your coordinate position.</span>")
|
||||
|
||||
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, "<span class='warning'>You cannot wear this suit any differently!</span>")
|
||||
return
|
||||
if(toggle_jumpsuit_adjust())
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit to wear it more casually.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>You adjust the suit back to normal.</span>")
|
||||
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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
else
|
||||
. += "<span class='notice'>[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)
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
user.visible_message("<span class='suicide'>\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!</span>")
|
||||
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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user