diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 8acc1d8f..e9d90e23 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -1,204 +1,205 @@ -/*ALL DEFINES RELATED TO COMBAT GO HERE*/ - -//Damage and status effect defines - -//Damage defines //TODO: merge these down to reduce on defines -#define BRUTE "brute" -#define BURN "fire" -#define TOX "tox" -#define OXY "oxy" -#define CLONE "clone" -#define STAMINA "stamina" -#define BRAIN "brain" - -//bitflag damage defines used for suicide_act -#define BRUTELOSS (1<<0) -#define FIRELOSS (1<<1) -#define TOXLOSS (1<<2) -#define OXYLOSS (1<<3) -#define SHAME (1<<4) -#define MANUAL_SUICIDE (1<<5) //suicide_act will do the actual killing. - -#define EFFECT_STUN "stun" -#define EFFECT_KNOCKDOWN "knockdown" -#define EFFECT_UNCONSCIOUS "unconscious" -#define EFFECT_IRRADIATE "irradiate" -#define EFFECT_STUTTER "stutter" -#define EFFECT_SLUR "slur" -#define EFFECT_EYE_BLUR "eye_blur" -#define EFFECT_DROWSY "drowsy" -#define EFFECT_JITTER "jitter" - -//Bitflags defining which status effects could be or are inflicted on a mob -#define CANSTUN (1<<0) -#define CANKNOCKDOWN (1<<1) -#define CANUNCONSCIOUS (1<<2) -#define CANPUSH (1<<3) -#define GODMODE (1<<4) - -//Health Defines -#define HEALTH_THRESHOLD_CRIT 0 -#define HEALTH_THRESHOLD_FULLCRIT -30 -#define HEALTH_THRESHOLD_DEAD -100 - -//Actual combat defines - -//click cooldowns, in tenths of a second, used for various combat actions -#define CLICK_CD_MELEE 8 -#define CLICK_CD_RANGE 4 -#define CLICK_CD_RAPID 2 -#define CLICK_CD_CLICK_ABILITY 6 -#define CLICK_CD_BREAKOUT 100 -#define CLICK_CD_HANDCUFFED 10 -#define CLICK_CD_RESIST 20 -#define CLICK_CD_GRABBING 10 - -//Cuff resist speeds -#define FAST_CUFFBREAK 1 -#define INSTANT_CUFFBREAK 2 - -//Grab levels -#define GRAB_PASSIVE 0 -#define GRAB_AGGRESSIVE 1 -#define GRAB_NECK 2 -#define GRAB_KILL 3 - -//slowdown when in softcrit -#define SOFTCRIT_ADD_SLOWDOWN 6 - -//Attack types for checking shields/hit reactions -#define MELEE_ATTACK 1 -#define UNARMED_ATTACK 2 -#define PROJECTILE_ATTACK 3 -#define THROWN_PROJECTILE_ATTACK 4 -#define LEAP_ATTACK 5 - -//attack visual effects -#define ATTACK_EFFECT_PUNCH "punch" -#define ATTACK_EFFECT_KICK "kick" -#define ATTACK_EFFECT_SMASH "smash" -#define ATTACK_EFFECT_CLAW "claw" -#define ATTACK_EFFECT_DISARM "disarm" -#define ATTACK_EFFECT_ASS_SLAP "ass_slap" -#define ATTACK_EFFECT_FACE_SLAP "face_slap" -#define ATTACK_EFFECT_BITE "bite" -#define ATTACK_EFFECT_MECHFIRE "mech_fire" -#define ATTACK_EFFECT_MECHTOXIN "mech_toxin" -#define ATTACK_EFFECT_BOOP "boop" //Honk - -//intent defines -#define INTENT_HELP "help" -#define INTENT_GRAB "grab" -#define INTENT_DISARM "disarm" -#define INTENT_HARM "harm" -//NOTE: INTENT_HOTKEY_* defines are not actual intents! -//they are here to support hotkeys -#define INTENT_HOTKEY_LEFT "left" -#define INTENT_HOTKEY_RIGHT "right" - -//the define for visible message range in combat -#define COMBAT_MESSAGE_RANGE 3 - -//Shove knockdown lengths (deciseconds) -#define SHOVE_KNOCKDOWN_SOLID 30 -#define SHOVE_KNOCKDOWN_HUMAN 30 -#define SHOVE_KNOCKDOWN_TABLE 30 -#define SHOVE_KNOCKDOWN_COLLATERAL 10 -//Shove slowdown -#define SHOVE_SLOWDOWN_ID "shove_slowdown" -#define SHOVE_SLOWDOWN_LENGTH 30 -#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier -//Shove disarming item list -GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( - /obj/item/gun))) - - -//Combat object defines - -//Embedded objects -#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user) -#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object) -#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp) -#define EMBEDDED_PAIN_MULTIPLIER 2 //Coefficient of multiplication for the damage the item does while embedded (this*item.w_class) -#define EMBEDDED_FALL_PAIN_MULTIPLIER 5 //Coefficient of multiplication for the damage the item does when it falls out (this*item.w_class) -#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class) -#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1) -#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class) -#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class) - -//Gun weapon weight -#define WEAPON_LIGHT 1 -#define WEAPON_MEDIUM 2 -#define WEAPON_HEAVY 3 -//Gun trigger guards -#define TRIGGER_GUARD_ALLOW_ALL -1 -#define TRIGGER_GUARD_NONE 0 -#define TRIGGER_GUARD_NORMAL 1 -//E-gun self-recharge values -#define EGUN_NO_SELFCHARGE 0 -#define EGUN_SELFCHARGE 1 -#define EGUN_SELFCHARGE_BORG 2 - -//Object/Item sharpness -#define IS_BLUNT 0 -#define IS_SHARP 1 -#define IS_SHARP_ACCURATE 2 - -//His Grace. -#define HIS_GRACE_SATIATED 0 //He hungers not. If bloodthirst is set to this, His Grace is asleep. -#define HIS_GRACE_PECKISH 20 //Slightly hungry. -#define HIS_GRACE_HUNGRY 60 //Getting closer. Increases damage up to a minimum of 20. -#define HIS_GRACE_FAMISHED 100 //Dangerous. Increases damage up to a minimum of 25 and cannot be dropped. -#define HIS_GRACE_STARVING 120 //Incredibly close to breaking loose. Increases damage up to a minimum of 30. -#define HIS_GRACE_CONSUME_OWNER 140 //His Grace consumes His owner at this point and becomes aggressive. -#define HIS_GRACE_FALL_ASLEEP 160 //If it reaches this point, He falls asleep and resets. - -#define HIS_GRACE_FORCE_BONUS 4 //How much force is gained per kill. - -#define EXPLODE_NONE 0 //Don't even ask me why we need this. -#define EXPLODE_DEVASTATE 1 -#define EXPLODE_HEAVY 2 -#define EXPLODE_LIGHT 3 - -#define EMP_HEAVY 1 -#define EMP_LIGHT 2 - -#define GRENADE_CLUMSY_FUMBLE 1 -#define GRENADE_NONCLUMSY_FUMBLE 2 -#define GRENADE_NO_FUMBLE 3 - -#define BODY_ZONE_HEAD "head" -#define BODY_ZONE_CHEST "chest" -#define BODY_ZONE_L_ARM "l_arm" -#define BODY_ZONE_R_ARM "r_arm" -#define BODY_ZONE_L_LEG "l_leg" -#define BODY_ZONE_R_LEG "r_leg" - -#define BODY_ZONE_PRECISE_EYES "eyes" -#define BODY_ZONE_PRECISE_MOUTH "mouth" -#define BODY_ZONE_PRECISE_GROIN "groin" -#define BODY_ZONE_PRECISE_L_HAND "l_hand" -#define BODY_ZONE_PRECISE_R_HAND "r_hand" -#define BODY_ZONE_PRECISE_L_FOOT "l_foot" -#define BODY_ZONE_PRECISE_R_FOOT "r_foot" - -//We will round to this value in damage calculations. -#define DAMAGE_PRECISION 0.1 - -//bullet_act() return values -#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting. -#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting. -#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default. -#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs. - -//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) -#define TOTAL_MASS_TINY_ITEM 1.25 -#define TOTAL_MASS_SMALL_ITEM 2.5 -#define TOTAL_MASS_NORMAL_ITEM 3.75 -#define TOTAL_MASS_BULKY_ITEM 5 -#define TOTAL_MASS_HUGE_ITEM 6.25 -#define TOTAL_MASS_GIGANTIC_ITEM 7.5 - -#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. -#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. -#define TOTAL_MASS_TOY_SWORD 1.5 +/*ALL DEFINES RELATED TO COMBAT GO HERE*/ + +//Damage and status effect defines + +//Damage defines //TODO: merge these down to reduce on defines +#define BRUTE "brute" +#define BURN "fire" +#define TOX "tox" +#define OXY "oxy" +#define CLONE "clone" +#define STAMINA "stamina" +#define BRAIN "brain" + +//bitflag damage defines used for suicide_act +#define BRUTELOSS (1<<0) +#define FIRELOSS (1<<1) +#define TOXLOSS (1<<2) +#define OXYLOSS (1<<3) +#define SHAME (1<<4) +#define MANUAL_SUICIDE (1<<5) //suicide_act will do the actual killing. + +#define EFFECT_STUN "stun" +#define EFFECT_KNOCKDOWN "knockdown" +#define EFFECT_UNCONSCIOUS "unconscious" +#define EFFECT_IRRADIATE "irradiate" +#define EFFECT_STUTTER "stutter" +#define EFFECT_SLUR "slur" +#define EFFECT_EYE_BLUR "eye_blur" +#define EFFECT_DROWSY "drowsy" +#define EFFECT_JITTER "jitter" + +//Bitflags defining which status effects could be or are inflicted on a mob +#define CANSTUN (1<<0) +#define CANKNOCKDOWN (1<<1) +#define CANUNCONSCIOUS (1<<2) +#define CANPUSH (1<<3) +#define GODMODE (1<<4) + +//Health Defines +#define HEALTH_THRESHOLD_CRIT 0 +#define HEALTH_THRESHOLD_FULLCRIT -30 +#define HEALTH_THRESHOLD_DEAD -100 + +//Actual combat defines + +//click cooldowns, in tenths of a second, used for various combat actions +#define CLICK_CD_MELEE 8 +#define CLICK_CD_RANGE 4 +#define CLICK_CD_RAPID 2 +#define CLICK_CD_CLICK_ABILITY 6 +#define CLICK_CD_BREAKOUT 100 +#define CLICK_CD_HANDCUFFED 10 +#define CLICK_CD_RESIST 20 +#define CLICK_CD_GRABBING 10 + +//Cuff resist speeds +#define FAST_CUFFBREAK 1 +#define INSTANT_CUFFBREAK 2 + +//Grab levels +#define GRAB_PASSIVE 0 +#define GRAB_AGGRESSIVE 1 +#define GRAB_NECK 2 +#define GRAB_KILL 3 + +//slowdown when in softcrit +#define SOFTCRIT_ADD_SLOWDOWN 6 + +//Attack types for checking shields/hit reactions +#define MELEE_ATTACK 1 +#define UNARMED_ATTACK 2 +#define PROJECTILE_ATTACK 3 +#define THROWN_PROJECTILE_ATTACK 4 +#define LEAP_ATTACK 5 + +//attack visual effects +#define ATTACK_EFFECT_PUNCH "punch" +#define ATTACK_EFFECT_KICK "kick" +#define ATTACK_EFFECT_SMASH "smash" +#define ATTACK_EFFECT_CLAW "claw" +#define ATTACK_EFFECT_DISARM "disarm" +#define ATTACK_EFFECT_ASS_SLAP "ass_slap" +#define ATTACK_EFFECT_FACE_SLAP "face_slap" +#define ATTACK_EFFECT_BITE "bite" +#define ATTACK_EFFECT_MECHFIRE "mech_fire" +#define ATTACK_EFFECT_MECHTOXIN "mech_toxin" +#define ATTACK_EFFECT_BOOP "boop" //Honk + +//intent defines +#define INTENT_HELP "help" +#define INTENT_GRAB "grab" +#define INTENT_DISARM "disarm" +#define INTENT_HARM "harm" +//NOTE: INTENT_HOTKEY_* defines are not actual intents! +//they are here to support hotkeys +#define INTENT_HOTKEY_LEFT "left" +#define INTENT_HOTKEY_RIGHT "right" + +//the define for visible message range in combat +#define COMBAT_MESSAGE_RANGE 3 +#define DEFAULT_MESSAGE_RANGE 7 + +//Shove knockdown lengths (deciseconds) +#define SHOVE_KNOCKDOWN_SOLID 30 +#define SHOVE_KNOCKDOWN_HUMAN 30 +#define SHOVE_KNOCKDOWN_TABLE 30 +#define SHOVE_KNOCKDOWN_COLLATERAL 10 +//Shove slowdown +#define SHOVE_SLOWDOWN_ID "shove_slowdown" +#define SHOVE_SLOWDOWN_LENGTH 30 +#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier +//Shove disarming item list +GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( + /obj/item/gun))) + + +//Combat object defines + +//Embedded objects +#define EMBEDDED_PAIN_CHANCE 15 //Chance for embedded objects to cause pain (damage user) +#define EMBEDDED_ITEM_FALLOUT 5 //Chance for embedded object to fall out (causing pain but removing the object) +#define EMBED_CHANCE 45 //Chance for an object to embed into somebody when thrown (if it's sharp) +#define EMBEDDED_PAIN_MULTIPLIER 2 //Coefficient of multiplication for the damage the item does while embedded (this*item.w_class) +#define EMBEDDED_FALL_PAIN_MULTIPLIER 5 //Coefficient of multiplication for the damage the item does when it falls out (this*item.w_class) +#define EMBEDDED_IMPACT_PAIN_MULTIPLIER 4 //Coefficient of multiplication for the damage the item does when it first embeds (this*item.w_class) +#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1) +#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class) +#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class) + +//Gun weapon weight +#define WEAPON_LIGHT 1 +#define WEAPON_MEDIUM 2 +#define WEAPON_HEAVY 3 +//Gun trigger guards +#define TRIGGER_GUARD_ALLOW_ALL -1 +#define TRIGGER_GUARD_NONE 0 +#define TRIGGER_GUARD_NORMAL 1 +//E-gun self-recharge values +#define EGUN_NO_SELFCHARGE 0 +#define EGUN_SELFCHARGE 1 +#define EGUN_SELFCHARGE_BORG 2 + +//Object/Item sharpness +#define IS_BLUNT 0 +#define IS_SHARP 1 +#define IS_SHARP_ACCURATE 2 + +//His Grace. +#define HIS_GRACE_SATIATED 0 //He hungers not. If bloodthirst is set to this, His Grace is asleep. +#define HIS_GRACE_PECKISH 20 //Slightly hungry. +#define HIS_GRACE_HUNGRY 60 //Getting closer. Increases damage up to a minimum of 20. +#define HIS_GRACE_FAMISHED 100 //Dangerous. Increases damage up to a minimum of 25 and cannot be dropped. +#define HIS_GRACE_STARVING 120 //Incredibly close to breaking loose. Increases damage up to a minimum of 30. +#define HIS_GRACE_CONSUME_OWNER 140 //His Grace consumes His owner at this point and becomes aggressive. +#define HIS_GRACE_FALL_ASLEEP 160 //If it reaches this point, He falls asleep and resets. + +#define HIS_GRACE_FORCE_BONUS 4 //How much force is gained per kill. + +#define EXPLODE_NONE 0 //Don't even ask me why we need this. +#define EXPLODE_DEVASTATE 1 +#define EXPLODE_HEAVY 2 +#define EXPLODE_LIGHT 3 + +#define EMP_HEAVY 1 +#define EMP_LIGHT 2 + +#define GRENADE_CLUMSY_FUMBLE 1 +#define GRENADE_NONCLUMSY_FUMBLE 2 +#define GRENADE_NO_FUMBLE 3 + +#define BODY_ZONE_HEAD "head" +#define BODY_ZONE_CHEST "chest" +#define BODY_ZONE_L_ARM "l_arm" +#define BODY_ZONE_R_ARM "r_arm" +#define BODY_ZONE_L_LEG "l_leg" +#define BODY_ZONE_R_LEG "r_leg" + +#define BODY_ZONE_PRECISE_EYES "eyes" +#define BODY_ZONE_PRECISE_MOUTH "mouth" +#define BODY_ZONE_PRECISE_GROIN "groin" +#define BODY_ZONE_PRECISE_L_HAND "l_hand" +#define BODY_ZONE_PRECISE_R_HAND "r_hand" +#define BODY_ZONE_PRECISE_L_FOOT "l_foot" +#define BODY_ZONE_PRECISE_R_FOOT "r_foot" + +//We will round to this value in damage calculations. +#define DAMAGE_PRECISION 0.1 + +//bullet_act() return values +#define BULLET_ACT_HIT "HIT" //It's a successful hit, whatever that means in the context of the thing it's hitting. +#define BULLET_ACT_BLOCK "BLOCK" //It's a blocked hit, whatever that means in the context of the thing it's hitting. +#define BULLET_ACT_FORCE_PIERCE "PIERCE" //It pierces through the object regardless of the bullet being piercing by default. +#define BULLET_ACT_TURF "TURF" //It hit us but it should hit something on the same turf too. Usually used for turfs. + +//items total mass, used to calculate their attacks' stamina costs. If not defined, the cost will be (w_class * 1.25) +#define TOTAL_MASS_TINY_ITEM 1.25 +#define TOTAL_MASS_SMALL_ITEM 2.5 +#define TOTAL_MASS_NORMAL_ITEM 3.75 +#define TOTAL_MASS_BULKY_ITEM 5 +#define TOTAL_MASS_HUGE_ITEM 6.25 +#define TOTAL_MASS_GIGANTIC_ITEM 7.5 + +#define TOTAL_MASS_HAND_REPLACEMENT 5 //standard punching stamina cost. most hand replacements are huge items anyway. +#define TOTAL_MASS_MEDIEVAL_WEAPON 3.6 //very, very generic average sword/warpick/etc. weight in pounds. +#define TOTAL_MASS_TOY_SWORD 1.5 diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index e0b916cb..05d31154 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -81,3 +81,7 @@ #define MAX_NAME_LEN 42 #define MAX_BROADCAST_LEN 512 #define MAX_CHARTER_LEN 80 + +// Audio/Visual Flags. Used to determine what sense are required to notice a message. +#define MSG_VISUAL (1<<0) +#define MSG_AUDIBLE (1<<1) \ No newline at end of file diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 8a47af52..fb063f94 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -58,6 +58,10 @@ var/screen_start_y = 2 //End + var/limited_random_access = FALSE //Quick if statement in accessible_items to determine if we care at all about what people can access at once. + var/limited_random_access_stack_position = 0 //If >0, can only access top items + var/limited_random_access_stack_bottom_up = FALSE //If TRUE, above becomes bottom items + /datum/component/storage/Initialize(datum/component/storage/concrete/master) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE @@ -626,9 +630,9 @@ if(M == viewing) to_chat(usr, "You put [I] [insert_preposition]to [parent].") else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is... - viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", 1) + viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", MSG_VISUAL) else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance... - viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", 1) + viewing.show_message("[M] puts [I] [insert_preposition]to [parent].", MSG_VISUAL) /datum/component/storage/proc/update_icon() if(isobj(parent)) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 3573b4a4..7e2a6bcf 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -1042,7 +1042,7 @@ GLOBAL_LIST_EMPTY(PDAs) if (ismob(loc)) var/mob/M = loc - M.show_message("Your [src] explodes!", 1) + M.show_message("Your [src] explodes!", MSG_VISUAL, "You hear a loud *pop*!", MSG_AUDIBLE) else visible_message("[src] explodes!", "You hear a loud *pop*!") diff --git a/code/game/objects/items/devices/PDA/virus_cart.dm b/code/game/objects/items/devices/PDA/virus_cart.dm index 28bc559b..d9039946 100644 --- a/code/game/objects/items/devices/PDA/virus_cart.dm +++ b/code/game/objects/items/devices/PDA/virus_cart.dm @@ -72,12 +72,12 @@ difficulty += 2 var/datum/component/uplink/hidden_uplink = target.GetComponent(/datum/component/uplink) if(!target.detonatable || prob(difficulty * 15) || (hidden_uplink)) - U.show_message("An error flashes on your [src].", 1) + U.show_message("An error flashes on your [src].", MSG_VISUAL) else message_admins("[!is_special_character(U) ? "Non-antag " : ""][ADMIN_LOOKUPFLW(U)] triggered a PDA explosion on [target.name] at [ADMIN_VERBOSEJMP(target)].") var/message_log = "triggered a PDA explosion on [target.name] at [AREACOORD(target)]." U.log_message(message_log, LOG_ATTACK) - U.show_message("Success!", 1) + U.show_message("Success!", MSG_VISUAL) target.explode() else to_chat(U, "PDA not found.") diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm index f178524c..48ecf827 100644 --- a/code/game/objects/items/grenades/flashbang.dm +++ b/code/game/objects/items/grenades/flashbang.dm @@ -1,36 +1,36 @@ -/obj/item/grenade/flashbang - name = "flashbang" - icon_state = "flashbang" - item_state = "flashbang" - lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' - var/flashbang_range = 7 //how many tiles away the mob will be stunned. - -/obj/item/grenade/flashbang/prime() - update_mob() - var/flashbang_turf = get_turf(src) - if(!flashbang_turf) - return - do_sparks(rand(5, 9), FALSE, src) - playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9) - new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 4, 2) - for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) - bang(get_turf(M), M) - qdel(src) - -/obj/item/grenade/flashbang/proc/bang(turf/T , mob/living/M) - if(M.stat == DEAD) //They're dead! - return - M.show_message("BANG", 2) - var/distance = max(0,get_dist(get_turf(src),T)) - -//Flash - if(M.flash_act(affect_silicon = 1)) - M.Knockdown(max(200/max(1,distance), 60)) -//Bang - if(!distance || loc == M || loc == M.loc) //Stop allahu akbarring rooms with this. - M.Knockdown(200) - M.soundbang_act(1, 200, 10, 15) - - else - M.soundbang_act(1, max(200/max(1,distance), 60), rand(0, 5)) +/obj/item/grenade/flashbang + name = "flashbang" + icon_state = "flashbang" + item_state = "flashbang" + lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' + var/flashbang_range = 7 //how many tiles away the mob will be stunned. + +/obj/item/grenade/flashbang/prime() + update_mob() + var/flashbang_turf = get_turf(src) + if(!flashbang_turf) + return + do_sparks(rand(5, 9), FALSE, src) + playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 100, TRUE, 8, 0.9) + new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 4, 2) + for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf)) + bang(get_turf(M), M) + qdel(src) + +/obj/item/grenade/flashbang/proc/bang(turf/T , mob/living/M) + if(M.stat == DEAD) //They're dead! + return + M.show_message("BANG", MSG_AUDIBLE) + var/distance = max(0,get_dist(get_turf(src),T)) + +//Flash + if(M.flash_act(affect_silicon = 1)) + M.Knockdown(max(200/max(1,distance), 60)) +//Bang + if(!distance || loc == M || loc == M.loc) //Stop allahu akbarring rooms with this. + M.Knockdown(200) + M.soundbang_act(1, 200, 10, 15) + + else + M.soundbang_act(1, max(200/max(1,distance), 60), rand(0, 5)) diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 36043328..c50b0fae 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -158,7 +158,7 @@ //we are not catholic if(young == TRUE || Kisser.young == TRUE) - user.show_message("[src] plays tag with [Kisser].", 1, + user.show_message("[src] plays tag with [Kisser].", MSG_VISUAL, "They're happy.", 0) Kisser.cheer_up() cheer_up() @@ -166,10 +166,10 @@ //never again else if(Kisser in scorned) //message, visible, alternate message, neither visible nor audible - user.show_message("[src] rejects the advances of [Kisser]!", 1, + user.show_message("[src] rejects the advances of [Kisser]!", MSG_VISUAL, "That didn't feel like it worked.", 0) else if(src in Kisser.scorned) - user.show_message("[Kisser] realises who [src] is and turns away.", 1, + user.show_message("[Kisser] realises who [src] is and turns away.", MSG_VISUAL, "That didn't feel like it worked.", 0) //first comes love @@ -190,7 +190,7 @@ new_lover(Kisser) Kisser.new_lover(src) else - user.show_message("[src] rejects the advances of [Kisser], maybe next time?", 1, + user.show_message("[src] rejects the advances of [Kisser], maybe next time?", MSG_VISUAL, "That didn't feel like it worked, this time.", 0) //then comes marriage diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 70029d00..4a7b16c4 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -1,1358 +1,1358 @@ -/* - * Everything derived from the common cardboard box. - * Basically everything except the original is a kit (starts full). - * - * Contains: - * Empty box, starter boxes (survival/engineer), - * Latex glove and sterile mask boxes, - * Syringe, beaker, dna injector boxes, - * Blanks, flashbangs, and EMP grenade boxes, - * Tracking and chemical implant boxes, - * Prescription glasses and drinking glass boxes, - * Condiment bottle and silly cup boxes, - * Donkpocket and monkeycube boxes, - * ID and security PDA cart boxes, - * Handcuff, mousetrap, and pillbottle boxes, - * Snap-pops and matchboxes, - * Replacement light boxes, - * Ammo types, - * Action Figure Boxes, - * Various paper bags, - * Colored boxes - * - * For syndicate call-ins see uplink_kits.dm - */ - -/obj/item/storage/box - name = "box" - desc = "It's just an ordinary box." - icon_state = "box" - item_state = "syringe_kit" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - resistance_flags = FLAMMABLE - var/foldable = /obj/item/stack/sheet/cardboard - var/illustration = "writing" - rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //exploits ahoy - -/obj/item/storage/box/Initialize(mapload) - . = ..() - update_icon() - -/obj/item/storage/box/suicide_act(mob/living/carbon/user) - var/obj/item/bodypart/head/myhead = user.get_bodypart(BODY_ZONE_HEAD) - if(myhead) - user.visible_message("[user] puts [user.p_their()] head into \the [src], and begins closing it! It looks like [user.p_theyre()] trying to commit suicide!") - myhead.dismember() - myhead.forceMove(src)//force your enemies to kill themselves with your head collection box! - playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) - return BRUTELOSS - user.visible_message("[user] beating [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS - -/obj/item/storage/box/update_icon() - . = ..() - if(illustration) - cut_overlays() - add_overlay(illustration) - -/obj/item/storage/box/attack_self(mob/user) - ..() - - if(!foldable) - return - if(contents.len) - to_chat(user, "You can't fold this box with items still inside!") - return - if(!ispath(foldable)) - return - - to_chat(user, "You fold [src] flat.") - var/obj/item/I = new foldable - qdel(src) - user.put_in_hands(I) - -/obj/item/storage/box/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/stack/packageWrap)) - return 0 - return ..() - -//Disk boxes -/obj/item/storage/box/disks - name = "diskette box" - illustration = "disk_kit" - -/obj/item/storage/box/disks/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/disk/data(src) - -/obj/item/storage/box/disks_plantgene - name = "plant data disks box" - illustration = "disk_kit" - -/obj/item/storage/box/disks_plantgene/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/disk/plantgene(src) - -/obj/item/storage/box/disks_nanite - name = "nanite program disks box" - illustration = "disk_kit" - -/obj/item/storage/box/disks_nanite/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/disk/nanite_program(src) - -// Ordinary survival box -/obj/item/storage/box/survival/PopulateContents() - new /obj/item/clothing/mask/breath(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -/obj/item/storage/box/survival/radio/PopulateContents() - ..() // we want the survival stuff too. - new /obj/item/radio/off(src) - -/obj/item/storage/box/survival_mining/PopulateContents() - new /obj/item/clothing/mask/gas/explorer(src) - new /obj/item/crowbar/red(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -// Engineer survival box -/obj/item/storage/box/engineer/PopulateContents() - new /obj/item/clothing/mask/breath(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen/engi(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -/obj/item/storage/box/engineer/radio/PopulateContents() - ..() // we want the regular items too. - new /obj/item/radio/off(src) - -// Syndie survival box -/obj/item/storage/box/syndie/PopulateContents() - new /obj/item/clothing/mask/gas/syndicate(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen/engi(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -// Security survival box -/obj/item/storage/box/security/PopulateContents() - new /obj/item/clothing/mask/gas/sechailer(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -/obj/item/storage/box/security/radio/PopulateContents() - ..() // we want the regular stuff too - new /obj/item/radio/off(src) - -/obj/item/storage/box/seclooking - icon_state = "secbox" - illustration = null - -/obj/item/storage/box/cells - name = "box of powercells" - desc = "Contains powercells." - illustration = "power_cell" - -/obj/item/storage/box/ammoshells - name = "box of loose ammo" - desc = "Contains loose ammo." - illustration = "loose_ammo" - -/obj/item/storage/box/otwo - name = "box of o2 supplies" - desc = "Contains o2 supplies." - illustration = "02" - -/obj/item/storage/box/otwo/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/tank/internals/emergency_oxygen/engi(src) - -/obj/item/storage/box/gloves - name = "box of latex gloves" - desc = "Contains sterile latex gloves." - illustration = "latex" - -/obj/item/storage/box/gloves/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/clothing/gloves/color/latex(src) - -/obj/item/storage/box/masks - name = "box of sterile masks" - desc = "This box contains sterile medical masks." - illustration = "sterile" - -/obj/item/storage/box/masks/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/clothing/mask/surgical(src) - -/obj/item/storage/box/syringes - name = "box of syringes" - desc = "A box full of syringes." - illustration = "syringe" - -/obj/item/storage/box/syringes/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/syringe(src) - -/obj/item/storage/box/medipens - name = "box of medipens" - desc = "A box full of epinephrine MediPens." - illustration = "syringe" - -/obj/item/storage/box/medipens/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/hypospray/medipen(src) - -/obj/item/storage/box/medipens/utility - name = "stimpack value kit" - desc = "A box with several stimpack medipens for the economical miner." - illustration = "syringe" - -/obj/item/storage/box/medipens/utility/PopulateContents() - ..() // includes regular medipens. - for(var/i in 1 to 5) - new /obj/item/reagent_containers/hypospray/medipen/stimpack(src) - -/obj/item/storage/box/beakers - name = "box of beakers" - illustration = "beaker" - -/obj/item/storage/box/beakers/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/glass/beaker( src ) - -/obj/item/storage/box/beakers/bluespace - name = "box of bluespace beakers" - illustration = "beaker" - -/obj/item/storage/box/beakers/bluespace/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/glass/beaker/bluespace(src) - -/obj/item/storage/box/medsprays - name = "box of medical sprayers" - desc = "A box full of medical sprayers, with unscrewable caps and precision spray heads." - -/obj/item/storage/box/medsprays/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/medspray( src ) - -/obj/item/storage/box/injectors - name = "box of DNA injectors" - desc = "This box contains injectors, it seems." - -/obj/item/storage/box/injectors/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/dnainjector/h2m(src) - for(var/i in 1 to 3) - new /obj/item/dnainjector/m2h(src) - -/obj/item/storage/box/flashbangs - name = "box of flashbangs (WARNING)" - desc = "WARNING: These devices are extremely dangerous and can cause blindness or deafness in repeated use." - icon_state = "secbox" - illustration = "flashbang" - -/obj/item/storage/box/flashbangs/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/grenade/flashbang(src) - -/obj/item/storage/box/flashes - name = "box of flashbulbs" - desc = "WARNING: Flashes can cause serious eye damage, protective eyewear is required." - icon_state = "secbox" - illustration = "flashbang" - -/obj/item/storage/box/flashes/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/assembly/flash/handheld(src) - -/obj/item/storage/box/wall_flash - name = "wall-mounted flash kit" - desc = "This box contains everything necessary to build a wall-mounted flash. WARNING: Flashes can cause serious eye damage, protective eyewear is required." - illustration = "flashbang" - -/obj/item/storage/box/wall_flash/PopulateContents() - var/id = rand(1000, 9999) - // FIXME what if this conflicts with an existing one? - - new /obj/item/wallframe/button(src) - new /obj/item/electronics/airlock(src) - var/obj/item/assembly/control/flasher/remote = new(src) - remote.id = id - var/obj/item/wallframe/flasher/frame = new(src) - frame.id = id - new /obj/item/assembly/flash/handheld(src) - new /obj/item/screwdriver(src) - -/obj/item/storage/box/teargas - name = "box of tear gas grenades (WARNING)" - desc = "WARNING: These devices are extremely dangerous and can cause blindness and skin irritation." - illustration = "flashbang" - -/obj/item/storage/box/teargas/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/grenade/chem_grenade/teargas(src) - -/obj/item/storage/box/emps - name = "box of emp grenades" - desc = "A box with 5 emp grenades." - illustration = "flashbang" - -/obj/item/storage/box/emps/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/grenade/empgrenade(src) - -/obj/item/storage/box/trackimp - name = "boxed tracking implant kit" - desc = "Box full of scum-bag tracking utensils." - illustration = "implant" - -/obj/item/storage/box/trackimp/PopulateContents() - for(var/i in 1 to 4) - new /obj/item/implantcase/tracking(src) - new /obj/item/implanter(src) - new /obj/item/implantpad(src) - new /obj/item/locator(src) - -/obj/item/storage/box/minertracker - name = "boxed tracking implant kit" - desc = "For finding those who have died on the accursed lavaworld." - illustration = "implant" - -/obj/item/storage/box/minertracker/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/implantcase/tracking(src) - new /obj/item/implanter(src) - new /obj/item/implantpad(src) - new /obj/item/locator(src) - -/obj/item/storage/box/chemimp - name = "boxed chemical implant kit" - desc = "Box of stuff used to implant chemicals." - illustration = "implant" - -/obj/item/storage/box/chemimp/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/implantcase/chem(src) - new /obj/item/implanter(src) - new /obj/item/implantpad(src) - -/obj/item/storage/box/exileimp - name = "boxed exile implant kit" - desc = "Box of exile implants. It has a picture of a clown being booted through the Gateway." - illustration = "implant" - -/obj/item/storage/box/exileimp/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/implantcase/exile(src) - new /obj/item/implanter(src) - -/obj/item/storage/box/bodybags - name = "body bags" - desc = "The label indicates that it contains body bags." - illustration = "bodybags" - -/obj/item/storage/box/bodybags/PopulateContents() - ..() - for(var/i in 1 to 7) - new /obj/item/bodybag(src) - -/obj/item/storage/box/rxglasses - name = "box of prescription glasses" - desc = "This box contains nerd glasses." - illustration = "glasses" - -/obj/item/storage/box/rxglasses/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/clothing/glasses/regular(src) - -/obj/item/storage/box/drinkingglasses - name = "box of drinking glasses" - desc = "It has a picture of drinking glasses on it." - -/obj/item/storage/box/drinkingglasses/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/drinks/drinkingglass(src) - -/obj/item/storage/box/condimentbottles - name = "box of condiment bottles" - desc = "It has a large ketchup smear on it." - -/obj/item/storage/box/condimentbottles/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/condiment(src) - -/obj/item/storage/box/cups - name = "box of paper cups" - desc = "It has pictures of paper cups on the front." - -/obj/item/storage/box/cups/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/food/drinks/sillycup( src ) - -/obj/item/storage/box/donkpockets - name = "box of donk-pockets" - desc = "Instructions: Heat in microwave. Product will cool if not eaten within seven minutes." - icon_state = "donkpocketbox" - illustration=null - -/obj/item/storage/box/donkpockets/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket)) - -/obj/item/storage/box/donkpockets/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket(src) - -/obj/item/storage/box/donkpockets/donkpocketspicy - name = "box of spicy-flavoured donk-pockets" - icon_state = "donkpocketboxspicy" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/spicy - -/obj/item/storage/box/donkpockets/donkpocketspicy/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/spicy)) - -/obj/item/storage/box/donkpockets/donkpocketspicy/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/spicy(src) - -/obj/item/storage/box/donkpockets/donkpocketteriyaki - name = "box of teriyaki-flavoured donk-pockets" - icon_state = "donkpocketboxteriyaki" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/teriyaki - -/obj/item/storage/box/donkpockets/donkpocketteriyaki/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/teriyaki)) - -/obj/item/storage/box/donkpockets/donkpocketteriyaki/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/teriyaki(src) - -/obj/item/storage/box/donkpockets/donkpocketpizza - name = "box of pizza-flavoured donk-pockets" - icon_state = "donkpocketboxpizza" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/pizza - -/obj/item/storage/box/donkpockets/donkpocketpizza/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/pizza)) - -/obj/item/storage/box/donkpockets/donkpocketpizza/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/pizza(src) - -/obj/item/storage/box/donkpockets/donkpocketgondola - name = "box of gondola-flavoured donk-pockets" - icon_state = "donkpocketboxgondola" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/gondola - -/obj/item/storage/box/donkpockets/donkpocketgondola/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/gondola)) - -/obj/item/storage/box/donkpockets/donkpocketgondola/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/gondola(src) - -/obj/item/storage/box/donkpockets/donkpocketberry - name = "box of berry-flavoured donk-pockets" - icon_state = "donkpocketboxberry" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/berry - -/obj/item/storage/box/donkpockets/donkpocketberry/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/berry)) - -/obj/item/storage/box/donkpockets/donkpocketberry/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/berry(src) - -/obj/item/storage/box/donkpockets/donkpockethonk - name = "box of banana-flavoured donk-pockets" - icon_state = "donkpocketboxbanana" - var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/honk - -/obj/item/storage/box/donkpockets/donkpockethonk/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/honk)) - -/obj/item/storage/box/donkpockets/donkpockethonk/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/reagent_containers/food/snacks/donkpocket/honk(src) - -/obj/item/storage/box/monkeycubes - name = "monkey cube box" - desc = "Drymate brand monkey cubes. Just add water!" - icon_state = "monkeycubebox" - illustration = null - -/obj/item/storage/box/monkeycubes/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_items = 7 - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/monkeycube)) - -/obj/item/storage/box/monkeycubes/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/food/snacks/monkeycube(src) - -/obj/item/storage/box/ids - name = "box of spare IDs" - desc = "Has so many empty IDs." - illustration = "id" - -/obj/item/storage/box/ids/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/card/id(src) - -//Some spare PDAs in a box -/obj/item/storage/box/PDAs - name = "spare PDAs" - desc = "A box of spare PDA microcomputers." - illustration = "pda" - -/obj/item/storage/box/PDAs/PopulateContents() - new /obj/item/pda(src) - new /obj/item/pda(src) - new /obj/item/pda(src) - new /obj/item/pda(src) - new /obj/item/cartridge/head(src) - - var/newcart = pick( /obj/item/cartridge/engineering, - /obj/item/cartridge/security, - /obj/item/cartridge/medical, - /obj/item/cartridge/signal/toxins, - /obj/item/cartridge/quartermaster) - new newcart(src) - -/obj/item/storage/box/silver_ids - name = "box of spare silver IDs" - desc = "Shiny IDs for important people." - illustration = "id" - -/obj/item/storage/box/silver_ids/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/card/id/silver(src) - -/obj/item/storage/box/prisoner - name = "box of prisoner IDs" - desc = "Take away their last shred of dignity, their name." - illustration = "id" - -/obj/item/storage/box/prisoner/PopulateContents() - ..() - new /obj/item/card/id/prisoner/one(src) - new /obj/item/card/id/prisoner/two(src) - new /obj/item/card/id/prisoner/three(src) - new /obj/item/card/id/prisoner/four(src) - new /obj/item/card/id/prisoner/five(src) - new /obj/item/card/id/prisoner/six(src) - new /obj/item/card/id/prisoner/seven(src) - -/obj/item/storage/box/seccarts - name = "box of PDA security cartridges" - desc = "A box full of PDA cartridges used by Security." - illustration = "pda" - -/obj/item/storage/box/seccarts/PopulateContents() - new /obj/item/cartridge/detective(src) - for(var/i in 1 to 6) - new /obj/item/cartridge/security(src) - -/obj/item/storage/box/firingpins - name = "box of standard firing pins" - desc = "A box full of standard firing pins, to allow newly-developed firearms to operate." - illustration = "firing_pins" - -/obj/item/storage/box/firingpins/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/firing_pin(src) - -/obj/item/storage/box/lasertagpins - name = "box of laser tag firing pins" - desc = "A box full of laser tag firing pins, to allow newly-developed firearms to require wearing brightly coloured plastic armor before being able to be used." - illustration = "firing_pins" - -/obj/item/storage/box/lasertagpins/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/firing_pin/tag/red(src) - new /obj/item/firing_pin/tag/blue(src) - -/obj/item/storage/box/handcuffs - name = "box of spare handcuffs" - desc = "A box full of handcuffs." - icon_state = "secbox" - illustration = "handcuff" - -/obj/item/storage/box/handcuffs/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/restraints/handcuffs(src) - -/obj/item/storage/box/zipties - name = "box of spare zipties" - desc = "A box full of zipties." - icon_state = "secbox" - illustration = "handcuff" - -/obj/item/storage/box/zipties/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/restraints/handcuffs/cable/zipties(src) - -/obj/item/storage/box/alienhandcuffs - name = "box of spare handcuffs" - desc = "A box full of handcuffs." - icon_state = "alienbox" - illustration = "handcuff" - -/obj/item/storage/box/alienhandcuffs/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/restraints/handcuffs/alien(src) - -/obj/item/storage/box/fakesyndiesuit - name = "boxed space suit and helmet" - desc = "A sleek, sturdy box used to hold replica spacesuits." - icon_state = "syndiebox" - -/obj/item/storage/box/fakesyndiesuit/PopulateContents() - new /obj/item/clothing/head/syndicatefake(src) - new /obj/item/clothing/suit/syndicatefake(src) - -/obj/item/storage/box/mousetraps - name = "box of Pest-B-Gon mousetraps" - desc = "Keep out of reach of children." - illustration = "mousetraps" - -/obj/item/storage/box/mousetraps/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/assembly/mousetrap(src) - -/obj/item/storage/box/pillbottles - name = "box of pill bottles" - desc = "It has pictures of pill bottles on its front." - illustration = "pillbox" - -/obj/item/storage/box/pillbottles/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/storage/pill_bottle(src) - -/obj/item/storage/box/snappops - name = "snap pop box" - desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children." - icon = 'icons/obj/toy.dmi' - icon_state = "spbox" - -/obj/item/storage/box/snappops/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.can_hold = typecacheof(list(/obj/item/toy/snappop)) - STR.max_items = 8 - -/obj/item/storage/box/snappops/PopulateContents() - SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/toy/snappop) - -/obj/item/storage/box/matches - name = "matchbox" - desc = "A small box of Almost But Not Quite Plasma Premium Matches." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "matchbox" - item_state = "zippo" - w_class = WEIGHT_CLASS_TINY - slot_flags = ITEM_SLOT_BELT - -/obj/item/storage/box/matches/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_items = 10 - STR.can_hold = typecacheof(list(/obj/item/match)) - -/obj/item/storage/box/matches/PopulateContents() - SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/match) - -/obj/item/storage/box/matches/attackby(obj/item/match/W as obj, mob/user as mob, params) - if(istype(W, /obj/item/match)) - W.matchignite() - -/obj/item/storage/box/lights - name = "box of replacement bulbs" - icon = 'icons/obj/storage.dmi' - illustration = "light" - desc = "This box is shaped on the inside so that only light tubes and bulbs fit." - item_state = "syringe_kit" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - foldable = /obj/item/stack/sheet/cardboard //BubbleWrap - -/obj/item/storage/box/lights/ComponentInitialize() - . = ..() - var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_items = 21 - STR.can_hold = typecacheof(list(/obj/item/light/tube, /obj/item/light/bulb)) - STR.max_combined_w_class = 21 - STR.click_gather = TRUE - -/obj/item/storage/box/lights/bulbs/PopulateContents() - for(var/i in 1 to 21) - new /obj/item/light/bulb(src) - -/obj/item/storage/box/lights/tubes - name = "box of replacement tubes" - illustration = "lighttube" - -/obj/item/storage/box/lights/tubes/PopulateContents() - for(var/i in 1 to 21) - new /obj/item/light/tube(src) - -/obj/item/storage/box/lights/mixed - name = "box of replacement lights" - illustration = "lightmixed" - -/obj/item/storage/box/lights/mixed/PopulateContents() - for(var/i in 1 to 14) - new /obj/item/light/tube(src) - for(var/i in 1 to 7) - new /obj/item/light/bulb(src) - -/obj/item/storage/box/deputy - name = "box of deputy armbands" - desc = "To be issued to those authorized to act as deputy of security." - -/obj/item/storage/box/deputy/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/clothing/accessory/armband/deputy(src) - -/obj/item/storage/box/metalfoam - name = "box of metal foam grenades" - desc = "To be used to rapidly seal hull breaches." - illustration = "flashbang" - -/obj/item/storage/box/metalfoam/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/grenade/chem_grenade/metalfoam(src) - -/obj/item/storage/box/smart_metal_foam - name = "box of smart metal foam grenades" - desc = "Used to rapidly seal hull breaches. This variety conforms to the walls of its area." - illustration = "flashbang" - -/obj/item/storage/box/smart_metal_foam/PopulateContents() - for(var/i in 1 to 7) - new/obj/item/grenade/chem_grenade/smart_metal_foam(src) - -/obj/item/storage/box/hug - name = "box of hugs" - desc = "A special box for sensitive people." - icon_state = "hugbox" - illustration = "heart" - foldable = null - -/obj/item/storage/box/hug/suicide_act(mob/user) - user.visible_message("[user] clamps the box of hugs on [user.p_their()] jugular! Guess it wasn't such a hugbox after all..") - return (BRUTELOSS) - -/obj/item/storage/box/hug/attack_self(mob/user) - ..() - user.changeNext_move(CLICK_CD_MELEE) - playsound(loc, "rustle", 50, 1, -5) - user.visible_message("[user] hugs \the [src].","You hug \the [src].") - -/////clown box & honkbot assembly -/obj/item/storage/box/clown - name = "clown box" - desc = "A colorful cardboard box for the clown" - illustration = "clown" - -/obj/item/storage/box/clown/attackby(obj/item/I, mob/user, params) - if((istype(I, /obj/item/bodypart/l_arm/robot)) || (istype(I, /obj/item/bodypart/r_arm/robot))) - if(contents.len) //prevent accidently deleting contents - to_chat(user, "You need to empty [src] out first!") - return - if(!user.temporarilyRemoveItemFromInventory(I)) - return - qdel(I) - to_chat(user, "You add some wheels to the [src]! You've got an honkbot assembly now! Honk!") - var/obj/item/bot_assembly/honkbot/A = new - qdel(src) - user.put_in_hands(A) - else - return ..() - -////// -/obj/item/storage/box/hug/medical/PopulateContents() - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - -// Clown survival box -/obj/item/storage/box/hug/survival/PopulateContents() - new /obj/item/clothing/mask/breath(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - - if(!isplasmaman(loc)) - new /obj/item/tank/internals/emergency_oxygen(src) - else - new /obj/item/tank/internals/plasmaman/belt(src) - -/obj/item/storage/box/rubbershot - name = "box of rubber shots" - desc = "A box full of rubber shots, designed for riot shotguns." - icon_state = "rubbershot_box" - illustration = null - -/obj/item/storage/box/rubbershot/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun/rubbershot(src) - -/obj/item/storage/box/lethalshot - name = "box of buckshot (Lethal)" - desc = "A box full of lethal shots, designed for riot shotguns." - icon_state = "lethalshot_box" - illustration = null - -/obj/item/storage/box/lethalshot/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun/buckshot(src) - -/obj/item/storage/box/beanbag - name = "box of beanbags" - desc = "A box full of beanbag shells." - icon_state = "rubbershot_box" - illustration = null - -/obj/item/storage/box/beanbag/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/ammo_casing/shotgun/beanbag(src) - -/obj/item/storage/box/lethalslugs - name = "box of 12g shotgun slugs" - desc = "A box full of lethal 12g slug, designed for riot shotguns." - icon_state = "12g_box" - illustration = null - -/obj/item/storage/box/lethalslugs/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun(src) - -/obj/item/storage/box/stunslug - name = "box of stun slugs" - desc = "A box full of stun 12g slugs." - icon_state = "stunslug_box" - illustration = null - -/obj/item/storage/box/stunslug/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun/stunslug(src) - -/obj/item/storage/box/techsslug - name = "box of tech shotgun shells" - desc = "A box full of tech shotgun shells." - icon_state = "techslug_box" - illustration = null - -/obj/item/storage/box/techsslug/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun/techshell(src) - -/obj/item/storage/box/fireshot - name = "box of incendiary ammo" - desc = "A box full of incendiary ammo." - icon_state = "fireshot_box" - illustration = null - -/obj/item/storage/box/fireshot/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/ammo_casing/shotgun/incendiary(src) - -/obj/item/storage/box/actionfigure - name = "box of action figures" - desc = "The latest set of collectable action figures." - icon_state = "box" - -/obj/item/storage/box/actionfigure/PopulateContents() - for(var/i in 1 to 4) - var/randomFigure = pick(subtypesof(/obj/item/toy/figure)) - new randomFigure(src) - -/obj/item/storage/box/mechfigures - name = "box of mech figures" - desc = "The latest set of collectable mech figures." - icon_state = "box" - -/obj/item/storage/box/mechfigures/PopulateContents() - for(var/i in 1 to 4) - var/randomFigure = pick(subtypesof(/obj/item/toy/prize/)) - new randomFigure(src) - - - - -/obj/item/storage/box/papersack - name = "paper sack" - desc = "A sack neatly crafted out of paper." - icon_state = "paperbag_None" - item_state = "paperbag_None" - resistance_flags = FLAMMABLE - foldable = null - /// A list of all available papersack reskins - var/list/papersack_designs = list() - -/obj/item/storage/box/papersack/Initialize(mapload) - . = ..() - papersack_designs = sortList(list( - "None" = image(icon = src.icon, icon_state = "paperbag_None"), - "NanotrasenStandard" = image(icon = src.icon, icon_state = "paperbag_NanotrasenStandard"), - "SyndiSnacks" = image(icon = src.icon, icon_state = "paperbag_SyndiSnacks"), - "Heart" = image(icon = src.icon, icon_state = "paperbag_Heart"), - "SmileyFace" = image(icon = src.icon, icon_state = "paperbag_SmileyFace") - )) - -/obj/item/storage/box/papersack/update_icon_state() - if(contents.len == 0) - icon_state = "[item_state]" - else - icon_state = "[item_state]_closed" - -/obj/item/storage/box/papersack/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/pen)) - var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, .proc/check_menu, user, W), radius = 36, require_near = TRUE) - if(!choice) - return FALSE - if(icon_state == "paperbag_[choice]") - return FALSE - switch(choice) - if("None") - desc = "A sack neatly crafted out of paper." - if("NanotrasenStandard") - desc = "A standard Kinaris paper lunch sack for loyal employees on the go." - if("SyndiSnacks") - desc = "The design on this paper sack is a remnant of the notorious 'SyndieSnacks' program." - if("Heart") - desc = "A paper sack with a heart etched onto the side." - if("SmileyFace") - desc = "A paper sack with a crude smile etched onto the side." - else - return FALSE - to_chat(user, "You make some modifications to [src] using your pen.") - icon_state = "paperbag_[choice]" - item_state = "paperbag_[choice]" - return FALSE - else if(W.is_sharp()) - if(!contents.len) - if(item_state == "paperbag_None") - user.show_message("You cut eyeholes into [src].", 1) - new /obj/item/clothing/head/papersack(user.loc) - qdel(src) - return FALSE - else if(item_state == "paperbag_SmileyFace") - user.show_message("You cut eyeholes into [src] and modify the design.", 1) - new /obj/item/clothing/head/papersack/smiley(user.loc) - qdel(src) - return FALSE - return ..() - -/** - * check_menu: Checks if we are allowed to interact with a radial menu - * - * Arguments: - * * user The mob interacting with a menu - * * P The pen used to interact with a menu - */ -/obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P) - if(!istype(user)) - return FALSE - if(user.incapacitated()) - return FALSE - if(contents.len) - to_chat(user, "You can't modify [src] with items still inside!") - return FALSE - if(!P || !user.is_holding(P)) - to_chat(user, "You need a pen to modify [src]!") - return FALSE - return TRUE - -/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist. - name = "ingredients box" - illustration = "fruit" - var/theme_name - -/obj/item/storage/box/ingredients/Initialize() - . = ..() - if(theme_name) - name = "[name] ([theme_name])" - desc = "A box containing supplementary ingredients for the aspiring chef. The box's theme is '[theme_name]'." - item_state = "syringe_kit" - -/obj/item/storage/box/ingredients/wildcard - theme_name = "wildcard" - -/obj/item/storage/box/ingredients/wildcard/PopulateContents() - for(var/i in 1 to 7) - var/randomFood = pick(/obj/item/reagent_containers/food/snacks/grown/chili, - /obj/item/reagent_containers/food/snacks/grown/tomato, - /obj/item/reagent_containers/food/snacks/grown/carrot, - /obj/item/reagent_containers/food/snacks/grown/potato, - /obj/item/reagent_containers/food/snacks/grown/potato/sweet, - /obj/item/reagent_containers/food/snacks/grown/apple, - /obj/item/reagent_containers/food/snacks/chocolatebar, - /obj/item/reagent_containers/food/snacks/grown/cherries, - /obj/item/reagent_containers/food/snacks/grown/banana, - /obj/item/reagent_containers/food/snacks/grown/cabbage, - /obj/item/reagent_containers/food/snacks/grown/soybeans, - /obj/item/reagent_containers/food/snacks/grown/corn, - /obj/item/reagent_containers/food/snacks/grown/mushroom/plumphelmet, - /obj/item/reagent_containers/food/snacks/grown/mushroom/chanterelle) - new randomFood(src) - -/obj/item/storage/box/ingredients/fiesta - theme_name = "fiesta" - -/obj/item/storage/box/ingredients/fiesta/PopulateContents() - new /obj/item/reagent_containers/food/snacks/tortilla(src) - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/corn(src) - new /obj/item/reagent_containers/food/snacks/grown/soybeans(src) - new /obj/item/reagent_containers/food/snacks/grown/chili(src) - -/obj/item/storage/box/ingredients/italian - theme_name = "italian" - -/obj/item/storage/box/ingredients/italian/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/reagent_containers/food/snacks/grown/tomato(src) - new /obj/item/reagent_containers/food/snacks/meatball(src) - new /obj/item/reagent_containers/food/drinks/bottle/wine(src) - -/obj/item/storage/box/ingredients/vegetarian - theme_name = "vegetarian" - -/obj/item/storage/box/ingredients/vegetarian/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/carrot(src) - new /obj/item/reagent_containers/food/snacks/grown/eggplant(src) - new /obj/item/reagent_containers/food/snacks/grown/potato(src) - new /obj/item/reagent_containers/food/snacks/grown/apple(src) - new /obj/item/reagent_containers/food/snacks/grown/corn(src) - new /obj/item/reagent_containers/food/snacks/grown/tomato(src) - -/obj/item/storage/box/ingredients/american - theme_name = "american" - -/obj/item/storage/box/ingredients/american/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/potato(src) - new /obj/item/reagent_containers/food/snacks/grown/tomato(src) - new /obj/item/reagent_containers/food/snacks/grown/corn(src) - new /obj/item/reagent_containers/food/snacks/meatball(src) - -/obj/item/storage/box/ingredients/fruity - theme_name = "fruity" - -/obj/item/storage/box/ingredients/fruity/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/apple(src) - new /obj/item/reagent_containers/food/snacks/grown/citrus/orange(src) - new /obj/item/reagent_containers/food/snacks/grown/citrus/lemon(src) - new /obj/item/reagent_containers/food/snacks/grown/citrus/lime(src) - new /obj/item/reagent_containers/food/snacks/grown/watermelon(src) - -/obj/item/storage/box/ingredients/sweets - theme_name = "sweets" - -/obj/item/storage/box/ingredients/sweets/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/cherries(src) - new /obj/item/reagent_containers/food/snacks/grown/banana(src) - new /obj/item/reagent_containers/food/snacks/chocolatebar(src) - new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) - new /obj/item/reagent_containers/food/snacks/grown/apple(src) - -/obj/item/storage/box/ingredients/delights - theme_name = "delights" - -/obj/item/storage/box/ingredients/delights/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/grown/potato/sweet(src) - new /obj/item/reagent_containers/food/snacks/grown/bluecherries(src) - new /obj/item/reagent_containers/food/snacks/grown/vanillapod(src) - new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) - new /obj/item/reagent_containers/food/snacks/grown/berries(src) - -/obj/item/storage/box/ingredients/grains - theme_name = "grains" - -/obj/item/storage/box/ingredients/grains/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/reagent_containers/food/snacks/grown/oat(src) - new /obj/item/reagent_containers/food/snacks/grown/wheat(src) - new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) - new /obj/item/reagent_containers/honeycomb(src) - new /obj/item/seeds/poppy(src) - -/obj/item/storage/box/ingredients/carnivore - theme_name = "carnivore" - -/obj/item/storage/box/ingredients/carnivore/PopulateContents() - new /obj/item/reagent_containers/food/snacks/meat/slab/bear(src) - new /obj/item/reagent_containers/food/snacks/meat/slab/spider(src) - new /obj/item/reagent_containers/food/snacks/spidereggs(src) - new /obj/item/reagent_containers/food/snacks/carpmeat(src) - new /obj/item/reagent_containers/food/snacks/meat/slab/xeno(src) - new /obj/item/reagent_containers/food/snacks/meat/slab/corgi(src) - new /obj/item/reagent_containers/food/snacks/meatball(src) - -/obj/item/storage/box/ingredients/exotic - theme_name = "exotic" - -/obj/item/storage/box/ingredients/exotic/PopulateContents() - for(var/i in 1 to 2) - new /obj/item/reagent_containers/food/snacks/carpmeat(src) - new /obj/item/reagent_containers/food/snacks/grown/soybeans(src) - new /obj/item/reagent_containers/food/snacks/grown/cabbage(src) - new /obj/item/reagent_containers/food/snacks/grown/chili(src) - -/obj/item/storage/box/emptysandbags - name = "box of empty sandbags" - -/obj/item/storage/box/emptysandbags/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/emptysandbag(src) - -/obj/item/storage/box/rndboards - name = "\proper the liberator's legacy" - desc = "A box containing a gift for worthy golems." - -/obj/item/storage/box/rndboards/PopulateContents() - new /obj/item/circuitboard/machine/protolathe(src) - new /obj/item/circuitboard/machine/destructive_analyzer(src) - new /obj/item/circuitboard/machine/circuit_imprinter(src) - new /obj/item/circuitboard/computer/rdconsole(src) - -/obj/item/storage/box/silver_sulf - name = "box of silver sulfadiazine patches" - desc = "Contains patches used to treat burns." - -/obj/item/storage/box/silver_sulf/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - -/obj/item/storage/box/fountainpens - name = "box of fountain pens" - -/obj/item/storage/box/fountainpens/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/pen/fountain(src) - -/obj/item/storage/box/holy_grenades - name = "box of holy hand grenades" - desc = "Contains several grenades used to rapidly purge heresy." - illustration = "flashbang" - -/obj/item/storage/box/holy_grenades/PopulateContents() - for(var/i in 1 to 7) - new/obj/item/grenade/chem_grenade/holy(src) - -/obj/item/storage/box/stockparts/basic //for ruins where it's a bad idea to give access to an autolathe/protolathe, but still want to make stock parts accessible - name = "box of stock parts" - desc = "Contains a variety of basic stock parts." - -/obj/item/storage/box/stockparts/basic/PopulateContents() - new /obj/item/stock_parts/capacitor(src) - new /obj/item/stock_parts/capacitor(src) - new /obj/item/stock_parts/capacitor(src) - new /obj/item/stock_parts/scanning_module(src) - new /obj/item/stock_parts/scanning_module(src) - new /obj/item/stock_parts/scanning_module(src) - new /obj/item/stock_parts/manipulator(src) - new /obj/item/stock_parts/manipulator(src) - new /obj/item/stock_parts/manipulator(src) - new /obj/item/stock_parts/micro_laser(src) - new /obj/item/stock_parts/micro_laser(src) - new /obj/item/stock_parts/micro_laser(src) - new /obj/item/stock_parts/matter_bin(src) - new /obj/item/stock_parts/matter_bin(src) - new /obj/item/stock_parts/matter_bin(src) - -/obj/item/storage/box/stockparts/deluxe - name = "box of deluxe stock parts" - desc = "Contains a variety of deluxe stock parts." - icon_state = "syndiebox" - -/obj/item/storage/box/stockparts/deluxe/PopulateContents() - new /obj/item/stock_parts/capacitor/quadratic(src) - new /obj/item/stock_parts/capacitor/quadratic(src) - new /obj/item/stock_parts/capacitor/quadratic(src) - new /obj/item/stock_parts/scanning_module/triphasic(src) - new /obj/item/stock_parts/scanning_module/triphasic(src) - new /obj/item/stock_parts/scanning_module/triphasic(src) - new /obj/item/stock_parts/manipulator/femto(src) - new /obj/item/stock_parts/manipulator/femto(src) - new /obj/item/stock_parts/manipulator/femto(src) - new /obj/item/stock_parts/micro_laser/quadultra(src) - new /obj/item/stock_parts/micro_laser/quadultra(src) - new /obj/item/stock_parts/micro_laser/quadultra(src) - new /obj/item/stock_parts/matter_bin/bluespace(src) - new /obj/item/stock_parts/matter_bin/bluespace(src) - new /obj/item/stock_parts/matter_bin/bluespace(src) - -//Colored boxes. -/obj/item/storage/box/green - icon_state = "box_green" - illustration = null - -/obj/item/storage/box/blue - icon_state = "box_blue" - illustration = null - -/obj/item/storage/box/purple - icon_state = "box_purple" - illustration = null - -/obj/item/storage/box/red - icon_state = "box_red" - illustration = null - -/obj/item/storage/box/yellow - icon_state = "box_yellow" - illustration = null - -/obj/item/storage/box/brown - icon_state = "box_brown" - illustration = null - -/obj/item/storage/box/pink - icon_state = "box_pink" - illustration = null - -/obj/item/storage/box/mre //base MRE type. - name = "Kinaris MRE Ration Kit Menu 0" - desc = "A package containing food suspended in an outdated bluespace pocket which lasts for centuries. If you're lucky you may even be able to enjoy the meal without getting food poisoning." - icon_state = "mre" - illustration = null - var/can_expire = TRUE - var/spawner_chance = 2 - var/expiration_date - var/expiration_date_min = 2300 - var/expiration_date_max = 2700 - -/obj/item/storage/box/mre/Initialize() - . = ..() - if(can_expire) - expiration_date = rand(expiration_date_min, expiration_date_max) - desc += "\nAn expiry date is listed on it. It reads: [expiration_date]" - var/spess_current_year = GLOB.year_integer + 540 - if(expiration_date < spess_current_year) - var/gross_risk = min(round(spess_current_year - expiration_date * 0.1), 1) - var/toxic_risk = min(round(spess_current_year - expiration_date * 0.01), 1) - for(var/obj/item/reagent_containers/food/snacks/S in contents) - if(prob(gross_risk)) - ENABLE_BITFIELD(S.foodtype, GROSS) - if(prob(toxic_risk)) - ENABLE_BITFIELD(S.foodtype, TOXIC) - -/obj/item/storage/box/mre/menu1 - name = "\improper Kinaris MRE Ration Kit Menu 1" - -/obj/item/storage/box/mre/menu1/safe - desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." - spawner_chance = 0 - can_expire = FALSE - -/obj/item/storage/box/mre/menu1/PopulateContents() - new /obj/item/reagent_containers/food/snacks/breadslice/plain(src) - new /obj/item/reagent_containers/food/snacks/breadslice/creamcheese(src) - new /obj/item/reagent_containers/food/condiment/pack/ketchup(src) - new /obj/item/reagent_containers/food/snacks/chocolatebar(src) - new /obj/item/tank/internals/emergency_oxygen(src) - -/obj/item/storage/box/mre/menu2 - name = "\improper Kinaris MRE Ration Kit Menu 2" - -/obj/item/storage/box/mre/menu2/safe - spawner_chance = 0 - desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." - can_expire = FALSE - -/obj/item/storage/box/mre/menu2/PopulateContents() - new /obj/item/reagent_containers/food/snacks/omelette(src) - new /obj/item/reagent_containers/food/snacks/meat/cutlet/plain(src) - new /obj/item/reagent_containers/food/snacks/fries(src) - new /obj/item/reagent_containers/food/snacks/chocolatebar(src) - new /obj/item/tank/internals/emergency_oxygen(src) - -/obj/item/storage/box/mre/menu3 - name = "\improper Kinaris MRE Ration Kit Menu 3" - desc = "The holy grail of MREs. This item contains the fabled MRE pizza, spicy nachos and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed." - icon_state = "menu3" - can_expire = FALSE //always fresh, never expired. - spawner_chance = 1 - -/obj/item/storage/box/mre/menu3/PopulateContents() - new /obj/item/reagent_containers/food/snacks/pizzaslice/pepperoni(src) - new /obj/item/reagent_containers/food/snacks/breadslice/plain(src) - new /obj/item/reagent_containers/food/snacks/cubannachos(src) - new /obj/item/reagent_containers/food/snacks/grown/chili(src) - new /obj/item/reagent_containers/food/drinks/coffee/type2(src) - new /obj/item/tank/internals/emergency_oxygen(src) - -/obj/item/storage/box/mre/menu4 - name = "\improper Kinaris MRE Ration Kit Menu 4" - -/obj/item/storage/box/mre/menu4/safe - spawner_chance = 0 - desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." - can_expire = FALSE - -/obj/item/storage/box/mre/menu4/PopulateContents() - if(prob(66)) - new /obj/item/reagent_containers/food/snacks/salad/boiledrice(src) - else - new /obj/item/reagent_containers/food/snacks/salad/ricebowl(src) - new /obj/item/reagent_containers/food/snacks/burger/tofu(src) - new /obj/item/reagent_containers/food/snacks/salad/fruit(src) - new /obj/item/reagent_containers/food/snacks/cracker(src) - new /obj/item/tank/internals/emergency_oxygen(src) - -//Where do I put this? -/obj/item/secbat - name = "Secbat box" - desc = "Contained inside is a secbat for use with law enforcement." - icon = 'icons/obj/storage.dmi' - icon_state = "box" - item_state = "syringe_kit" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - -/obj/item/secbat/attack_self(mob/user) - new /mob/living/simple_animal/hostile/retaliate/bat/secbat(user.loc) - to_chat(user, "You open the box, releasing the secbat!") - var/obj/item/stack/sheet/cardboard/I = new(user.drop_location()) - qdel(src) - user.put_in_hands(I) +/* + * Everything derived from the common cardboard box. + * Basically everything except the original is a kit (starts full). + * + * Contains: + * Empty box, starter boxes (survival/engineer), + * Latex glove and sterile mask boxes, + * Syringe, beaker, dna injector boxes, + * Blanks, flashbangs, and EMP grenade boxes, + * Tracking and chemical implant boxes, + * Prescription glasses and drinking glass boxes, + * Condiment bottle and silly cup boxes, + * Donkpocket and monkeycube boxes, + * ID and security PDA cart boxes, + * Handcuff, mousetrap, and pillbottle boxes, + * Snap-pops and matchboxes, + * Replacement light boxes, + * Ammo types, + * Action Figure Boxes, + * Various paper bags, + * Colored boxes + * + * For syndicate call-ins see uplink_kits.dm + */ + +/obj/item/storage/box + name = "box" + desc = "It's just an ordinary box." + icon_state = "box" + item_state = "syringe_kit" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + resistance_flags = FLAMMABLE + var/foldable = /obj/item/stack/sheet/cardboard + var/illustration = "writing" + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE //exploits ahoy + +/obj/item/storage/box/Initialize(mapload) + . = ..() + update_icon() + +/obj/item/storage/box/suicide_act(mob/living/carbon/user) + var/obj/item/bodypart/head/myhead = user.get_bodypart(BODY_ZONE_HEAD) + if(myhead) + user.visible_message("[user] puts [user.p_their()] head into \the [src], and begins closing it! It looks like [user.p_theyre()] trying to commit suicide!") + myhead.dismember() + myhead.forceMove(src)//force your enemies to kill themselves with your head collection box! + playsound(user,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1) + return BRUTELOSS + user.visible_message("[user] beating [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/storage/box/update_icon() + . = ..() + if(illustration) + cut_overlays() + add_overlay(illustration) + +/obj/item/storage/box/attack_self(mob/user) + ..() + + if(!foldable) + return + if(contents.len) + to_chat(user, "You can't fold this box with items still inside!") + return + if(!ispath(foldable)) + return + + to_chat(user, "You fold [src] flat.") + var/obj/item/I = new foldable + qdel(src) + user.put_in_hands(I) + +/obj/item/storage/box/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/stack/packageWrap)) + return 0 + return ..() + +//Disk boxes +/obj/item/storage/box/disks + name = "diskette box" + illustration = "disk_kit" + +/obj/item/storage/box/disks/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/disk/data(src) + +/obj/item/storage/box/disks_plantgene + name = "plant data disks box" + illustration = "disk_kit" + +/obj/item/storage/box/disks_plantgene/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/disk/plantgene(src) + +/obj/item/storage/box/disks_nanite + name = "nanite program disks box" + illustration = "disk_kit" + +/obj/item/storage/box/disks_nanite/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/disk/nanite_program(src) + +// Ordinary survival box +/obj/item/storage/box/survival/PopulateContents() + new /obj/item/clothing/mask/breath(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +/obj/item/storage/box/survival/radio/PopulateContents() + ..() // we want the survival stuff too. + new /obj/item/radio/off(src) + +/obj/item/storage/box/survival_mining/PopulateContents() + new /obj/item/clothing/mask/gas/explorer(src) + new /obj/item/crowbar/red(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +// Engineer survival box +/obj/item/storage/box/engineer/PopulateContents() + new /obj/item/clothing/mask/breath(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen/engi(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +/obj/item/storage/box/engineer/radio/PopulateContents() + ..() // we want the regular items too. + new /obj/item/radio/off(src) + +// Syndie survival box +/obj/item/storage/box/syndie/PopulateContents() + new /obj/item/clothing/mask/gas/syndicate(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen/engi(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +// Security survival box +/obj/item/storage/box/security/PopulateContents() + new /obj/item/clothing/mask/gas/sechailer(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +/obj/item/storage/box/security/radio/PopulateContents() + ..() // we want the regular stuff too + new /obj/item/radio/off(src) + +/obj/item/storage/box/seclooking + icon_state = "secbox" + illustration = null + +/obj/item/storage/box/cells + name = "box of powercells" + desc = "Contains powercells." + illustration = "power_cell" + +/obj/item/storage/box/ammoshells + name = "box of loose ammo" + desc = "Contains loose ammo." + illustration = "loose_ammo" + +/obj/item/storage/box/otwo + name = "box of o2 supplies" + desc = "Contains o2 supplies." + illustration = "02" + +/obj/item/storage/box/otwo/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/tank/internals/emergency_oxygen/engi(src) + +/obj/item/storage/box/gloves + name = "box of latex gloves" + desc = "Contains sterile latex gloves." + illustration = "latex" + +/obj/item/storage/box/gloves/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/clothing/gloves/color/latex(src) + +/obj/item/storage/box/masks + name = "box of sterile masks" + desc = "This box contains sterile medical masks." + illustration = "sterile" + +/obj/item/storage/box/masks/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/clothing/mask/surgical(src) + +/obj/item/storage/box/syringes + name = "box of syringes" + desc = "A box full of syringes." + illustration = "syringe" + +/obj/item/storage/box/syringes/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/syringe(src) + +/obj/item/storage/box/medipens + name = "box of medipens" + desc = "A box full of epinephrine MediPens." + illustration = "syringe" + +/obj/item/storage/box/medipens/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/hypospray/medipen(src) + +/obj/item/storage/box/medipens/utility + name = "stimpack value kit" + desc = "A box with several stimpack medipens for the economical miner." + illustration = "syringe" + +/obj/item/storage/box/medipens/utility/PopulateContents() + ..() // includes regular medipens. + for(var/i in 1 to 5) + new /obj/item/reagent_containers/hypospray/medipen/stimpack(src) + +/obj/item/storage/box/beakers + name = "box of beakers" + illustration = "beaker" + +/obj/item/storage/box/beakers/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/glass/beaker( src ) + +/obj/item/storage/box/beakers/bluespace + name = "box of bluespace beakers" + illustration = "beaker" + +/obj/item/storage/box/beakers/bluespace/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/glass/beaker/bluespace(src) + +/obj/item/storage/box/medsprays + name = "box of medical sprayers" + desc = "A box full of medical sprayers, with unscrewable caps and precision spray heads." + +/obj/item/storage/box/medsprays/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/medspray( src ) + +/obj/item/storage/box/injectors + name = "box of DNA injectors" + desc = "This box contains injectors, it seems." + +/obj/item/storage/box/injectors/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/dnainjector/h2m(src) + for(var/i in 1 to 3) + new /obj/item/dnainjector/m2h(src) + +/obj/item/storage/box/flashbangs + name = "box of flashbangs (WARNING)" + desc = "WARNING: These devices are extremely dangerous and can cause blindness or deafness in repeated use." + icon_state = "secbox" + illustration = "flashbang" + +/obj/item/storage/box/flashbangs/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/grenade/flashbang(src) + +/obj/item/storage/box/flashes + name = "box of flashbulbs" + desc = "WARNING: Flashes can cause serious eye damage, protective eyewear is required." + icon_state = "secbox" + illustration = "flashbang" + +/obj/item/storage/box/flashes/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/assembly/flash/handheld(src) + +/obj/item/storage/box/wall_flash + name = "wall-mounted flash kit" + desc = "This box contains everything necessary to build a wall-mounted flash. WARNING: Flashes can cause serious eye damage, protective eyewear is required." + illustration = "flashbang" + +/obj/item/storage/box/wall_flash/PopulateContents() + var/id = rand(1000, 9999) + // FIXME what if this conflicts with an existing one? + + new /obj/item/wallframe/button(src) + new /obj/item/electronics/airlock(src) + var/obj/item/assembly/control/flasher/remote = new(src) + remote.id = id + var/obj/item/wallframe/flasher/frame = new(src) + frame.id = id + new /obj/item/assembly/flash/handheld(src) + new /obj/item/screwdriver(src) + +/obj/item/storage/box/teargas + name = "box of tear gas grenades (WARNING)" + desc = "WARNING: These devices are extremely dangerous and can cause blindness and skin irritation." + illustration = "flashbang" + +/obj/item/storage/box/teargas/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/grenade/chem_grenade/teargas(src) + +/obj/item/storage/box/emps + name = "box of emp grenades" + desc = "A box with 5 emp grenades." + illustration = "flashbang" + +/obj/item/storage/box/emps/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/grenade/empgrenade(src) + +/obj/item/storage/box/trackimp + name = "boxed tracking implant kit" + desc = "Box full of scum-bag tracking utensils." + illustration = "implant" + +/obj/item/storage/box/trackimp/PopulateContents() + for(var/i in 1 to 4) + new /obj/item/implantcase/tracking(src) + new /obj/item/implanter(src) + new /obj/item/implantpad(src) + new /obj/item/locator(src) + +/obj/item/storage/box/minertracker + name = "boxed tracking implant kit" + desc = "For finding those who have died on the accursed lavaworld." + illustration = "implant" + +/obj/item/storage/box/minertracker/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/implantcase/tracking(src) + new /obj/item/implanter(src) + new /obj/item/implantpad(src) + new /obj/item/locator(src) + +/obj/item/storage/box/chemimp + name = "boxed chemical implant kit" + desc = "Box of stuff used to implant chemicals." + illustration = "implant" + +/obj/item/storage/box/chemimp/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/implantcase/chem(src) + new /obj/item/implanter(src) + new /obj/item/implantpad(src) + +/obj/item/storage/box/exileimp + name = "boxed exile implant kit" + desc = "Box of exile implants. It has a picture of a clown being booted through the Gateway." + illustration = "implant" + +/obj/item/storage/box/exileimp/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/implantcase/exile(src) + new /obj/item/implanter(src) + +/obj/item/storage/box/bodybags + name = "body bags" + desc = "The label indicates that it contains body bags." + illustration = "bodybags" + +/obj/item/storage/box/bodybags/PopulateContents() + ..() + for(var/i in 1 to 7) + new /obj/item/bodybag(src) + +/obj/item/storage/box/rxglasses + name = "box of prescription glasses" + desc = "This box contains nerd glasses." + illustration = "glasses" + +/obj/item/storage/box/rxglasses/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/clothing/glasses/regular(src) + +/obj/item/storage/box/drinkingglasses + name = "box of drinking glasses" + desc = "It has a picture of drinking glasses on it." + +/obj/item/storage/box/drinkingglasses/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/drinks/drinkingglass(src) + +/obj/item/storage/box/condimentbottles + name = "box of condiment bottles" + desc = "It has a large ketchup smear on it." + +/obj/item/storage/box/condimentbottles/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/condiment(src) + +/obj/item/storage/box/cups + name = "box of paper cups" + desc = "It has pictures of paper cups on the front." + +/obj/item/storage/box/cups/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/food/drinks/sillycup( src ) + +/obj/item/storage/box/donkpockets + name = "box of donk-pockets" + desc = "Instructions: Heat in microwave. Product will cool if not eaten within seven minutes." + icon_state = "donkpocketbox" + illustration=null + +/obj/item/storage/box/donkpockets/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket)) + +/obj/item/storage/box/donkpockets/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket(src) + +/obj/item/storage/box/donkpockets/donkpocketspicy + name = "box of spicy-flavoured donk-pockets" + icon_state = "donkpocketboxspicy" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/spicy + +/obj/item/storage/box/donkpockets/donkpocketspicy/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/spicy)) + +/obj/item/storage/box/donkpockets/donkpocketspicy/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/spicy(src) + +/obj/item/storage/box/donkpockets/donkpocketteriyaki + name = "box of teriyaki-flavoured donk-pockets" + icon_state = "donkpocketboxteriyaki" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/teriyaki + +/obj/item/storage/box/donkpockets/donkpocketteriyaki/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/teriyaki)) + +/obj/item/storage/box/donkpockets/donkpocketteriyaki/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/teriyaki(src) + +/obj/item/storage/box/donkpockets/donkpocketpizza + name = "box of pizza-flavoured donk-pockets" + icon_state = "donkpocketboxpizza" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/pizza + +/obj/item/storage/box/donkpockets/donkpocketpizza/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/pizza)) + +/obj/item/storage/box/donkpockets/donkpocketpizza/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/pizza(src) + +/obj/item/storage/box/donkpockets/donkpocketgondola + name = "box of gondola-flavoured donk-pockets" + icon_state = "donkpocketboxgondola" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/gondola + +/obj/item/storage/box/donkpockets/donkpocketgondola/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/gondola)) + +/obj/item/storage/box/donkpockets/donkpocketgondola/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/gondola(src) + +/obj/item/storage/box/donkpockets/donkpocketberry + name = "box of berry-flavoured donk-pockets" + icon_state = "donkpocketboxberry" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/berry + +/obj/item/storage/box/donkpockets/donkpocketberry/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/berry)) + +/obj/item/storage/box/donkpockets/donkpocketberry/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/berry(src) + +/obj/item/storage/box/donkpockets/donkpockethonk + name = "box of banana-flavoured donk-pockets" + icon_state = "donkpocketboxbanana" + var/donktype = /obj/item/reagent_containers/food/snacks/donkpocket/honk + +/obj/item/storage/box/donkpockets/donkpockethonk/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket/honk)) + +/obj/item/storage/box/donkpockets/donkpockethonk/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/reagent_containers/food/snacks/donkpocket/honk(src) + +/obj/item/storage/box/monkeycubes + name = "monkey cube box" + desc = "Drymate brand monkey cubes. Just add water!" + icon_state = "monkeycubebox" + illustration = null + +/obj/item/storage/box/monkeycubes/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_items = 7 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/monkeycube)) + +/obj/item/storage/box/monkeycubes/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/food/snacks/monkeycube(src) + +/obj/item/storage/box/ids + name = "box of spare IDs" + desc = "Has so many empty IDs." + illustration = "id" + +/obj/item/storage/box/ids/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/card/id(src) + +//Some spare PDAs in a box +/obj/item/storage/box/PDAs + name = "spare PDAs" + desc = "A box of spare PDA microcomputers." + illustration = "pda" + +/obj/item/storage/box/PDAs/PopulateContents() + new /obj/item/pda(src) + new /obj/item/pda(src) + new /obj/item/pda(src) + new /obj/item/pda(src) + new /obj/item/cartridge/head(src) + + var/newcart = pick( /obj/item/cartridge/engineering, + /obj/item/cartridge/security, + /obj/item/cartridge/medical, + /obj/item/cartridge/signal/toxins, + /obj/item/cartridge/quartermaster) + new newcart(src) + +/obj/item/storage/box/silver_ids + name = "box of spare silver IDs" + desc = "Shiny IDs for important people." + illustration = "id" + +/obj/item/storage/box/silver_ids/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/card/id/silver(src) + +/obj/item/storage/box/prisoner + name = "box of prisoner IDs" + desc = "Take away their last shred of dignity, their name." + illustration = "id" + +/obj/item/storage/box/prisoner/PopulateContents() + ..() + new /obj/item/card/id/prisoner/one(src) + new /obj/item/card/id/prisoner/two(src) + new /obj/item/card/id/prisoner/three(src) + new /obj/item/card/id/prisoner/four(src) + new /obj/item/card/id/prisoner/five(src) + new /obj/item/card/id/prisoner/six(src) + new /obj/item/card/id/prisoner/seven(src) + +/obj/item/storage/box/seccarts + name = "box of PDA security cartridges" + desc = "A box full of PDA cartridges used by Security." + illustration = "pda" + +/obj/item/storage/box/seccarts/PopulateContents() + new /obj/item/cartridge/detective(src) + for(var/i in 1 to 6) + new /obj/item/cartridge/security(src) + +/obj/item/storage/box/firingpins + name = "box of standard firing pins" + desc = "A box full of standard firing pins, to allow newly-developed firearms to operate." + illustration = "firing_pins" + +/obj/item/storage/box/firingpins/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/firing_pin(src) + +/obj/item/storage/box/lasertagpins + name = "box of laser tag firing pins" + desc = "A box full of laser tag firing pins, to allow newly-developed firearms to require wearing brightly coloured plastic armor before being able to be used." + illustration = "firing_pins" + +/obj/item/storage/box/lasertagpins/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/firing_pin/tag/red(src) + new /obj/item/firing_pin/tag/blue(src) + +/obj/item/storage/box/handcuffs + name = "box of spare handcuffs" + desc = "A box full of handcuffs." + icon_state = "secbox" + illustration = "handcuff" + +/obj/item/storage/box/handcuffs/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/restraints/handcuffs(src) + +/obj/item/storage/box/zipties + name = "box of spare zipties" + desc = "A box full of zipties." + icon_state = "secbox" + illustration = "handcuff" + +/obj/item/storage/box/zipties/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/restraints/handcuffs/cable/zipties(src) + +/obj/item/storage/box/alienhandcuffs + name = "box of spare handcuffs" + desc = "A box full of handcuffs." + icon_state = "alienbox" + illustration = "handcuff" + +/obj/item/storage/box/alienhandcuffs/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/restraints/handcuffs/alien(src) + +/obj/item/storage/box/fakesyndiesuit + name = "boxed space suit and helmet" + desc = "A sleek, sturdy box used to hold replica spacesuits." + icon_state = "syndiebox" + +/obj/item/storage/box/fakesyndiesuit/PopulateContents() + new /obj/item/clothing/head/syndicatefake(src) + new /obj/item/clothing/suit/syndicatefake(src) + +/obj/item/storage/box/mousetraps + name = "box of Pest-B-Gon mousetraps" + desc = "Keep out of reach of children." + illustration = "mousetraps" + +/obj/item/storage/box/mousetraps/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/assembly/mousetrap(src) + +/obj/item/storage/box/pillbottles + name = "box of pill bottles" + desc = "It has pictures of pill bottles on its front." + illustration = "pillbox" + +/obj/item/storage/box/pillbottles/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/storage/pill_bottle(src) + +/obj/item/storage/box/snappops + name = "snap pop box" + desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children." + icon = 'icons/obj/toy.dmi' + icon_state = "spbox" + +/obj/item/storage/box/snappops/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/toy/snappop)) + STR.max_items = 8 + +/obj/item/storage/box/snappops/PopulateContents() + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/toy/snappop) + +/obj/item/storage/box/matches + name = "matchbox" + desc = "A small box of Almost But Not Quite Plasma Premium Matches." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "matchbox" + item_state = "zippo" + w_class = WEIGHT_CLASS_TINY + slot_flags = ITEM_SLOT_BELT + +/obj/item/storage/box/matches/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_items = 10 + STR.can_hold = typecacheof(list(/obj/item/match)) + +/obj/item/storage/box/matches/PopulateContents() + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/match) + +/obj/item/storage/box/matches/attackby(obj/item/match/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/match)) + W.matchignite() + +/obj/item/storage/box/lights + name = "box of replacement bulbs" + icon = 'icons/obj/storage.dmi' + illustration = "light" + desc = "This box is shaped on the inside so that only light tubes and bulbs fit." + item_state = "syringe_kit" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + foldable = /obj/item/stack/sheet/cardboard //BubbleWrap + +/obj/item/storage/box/lights/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_items = 21 + STR.can_hold = typecacheof(list(/obj/item/light/tube, /obj/item/light/bulb)) + STR.max_combined_w_class = 21 + STR.click_gather = TRUE + +/obj/item/storage/box/lights/bulbs/PopulateContents() + for(var/i in 1 to 21) + new /obj/item/light/bulb(src) + +/obj/item/storage/box/lights/tubes + name = "box of replacement tubes" + illustration = "lighttube" + +/obj/item/storage/box/lights/tubes/PopulateContents() + for(var/i in 1 to 21) + new /obj/item/light/tube(src) + +/obj/item/storage/box/lights/mixed + name = "box of replacement lights" + illustration = "lightmixed" + +/obj/item/storage/box/lights/mixed/PopulateContents() + for(var/i in 1 to 14) + new /obj/item/light/tube(src) + for(var/i in 1 to 7) + new /obj/item/light/bulb(src) + +/obj/item/storage/box/deputy + name = "box of deputy armbands" + desc = "To be issued to those authorized to act as deputy of security." + +/obj/item/storage/box/deputy/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/clothing/accessory/armband/deputy(src) + +/obj/item/storage/box/metalfoam + name = "box of metal foam grenades" + desc = "To be used to rapidly seal hull breaches." + illustration = "flashbang" + +/obj/item/storage/box/metalfoam/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/grenade/chem_grenade/metalfoam(src) + +/obj/item/storage/box/smart_metal_foam + name = "box of smart metal foam grenades" + desc = "Used to rapidly seal hull breaches. This variety conforms to the walls of its area." + illustration = "flashbang" + +/obj/item/storage/box/smart_metal_foam/PopulateContents() + for(var/i in 1 to 7) + new/obj/item/grenade/chem_grenade/smart_metal_foam(src) + +/obj/item/storage/box/hug + name = "box of hugs" + desc = "A special box for sensitive people." + icon_state = "hugbox" + illustration = "heart" + foldable = null + +/obj/item/storage/box/hug/suicide_act(mob/user) + user.visible_message("[user] clamps the box of hugs on [user.p_their()] jugular! Guess it wasn't such a hugbox after all..") + return (BRUTELOSS) + +/obj/item/storage/box/hug/attack_self(mob/user) + ..() + user.changeNext_move(CLICK_CD_MELEE) + playsound(loc, "rustle", 50, 1, -5) + user.visible_message("[user] hugs \the [src].","You hug \the [src].") + +/////clown box & honkbot assembly +/obj/item/storage/box/clown + name = "clown box" + desc = "A colorful cardboard box for the clown" + illustration = "clown" + +/obj/item/storage/box/clown/attackby(obj/item/I, mob/user, params) + if((istype(I, /obj/item/bodypart/l_arm/robot)) || (istype(I, /obj/item/bodypart/r_arm/robot))) + if(contents.len) //prevent accidently deleting contents + to_chat(user, "You need to empty [src] out first!") + return + if(!user.temporarilyRemoveItemFromInventory(I)) + return + qdel(I) + to_chat(user, "You add some wheels to the [src]! You've got an honkbot assembly now! Honk!") + var/obj/item/bot_assembly/honkbot/A = new + qdel(src) + user.put_in_hands(A) + else + return ..() + +////// +/obj/item/storage/box/hug/medical/PopulateContents() + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + +// Clown survival box +/obj/item/storage/box/hug/survival/PopulateContents() + new /obj/item/clothing/mask/breath(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + + if(!isplasmaman(loc)) + new /obj/item/tank/internals/emergency_oxygen(src) + else + new /obj/item/tank/internals/plasmaman/belt(src) + +/obj/item/storage/box/rubbershot + name = "box of rubber shots" + desc = "A box full of rubber shots, designed for riot shotguns." + icon_state = "rubbershot_box" + illustration = null + +/obj/item/storage/box/rubbershot/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/rubbershot(src) + +/obj/item/storage/box/lethalshot + name = "box of buckshot (Lethal)" + desc = "A box full of lethal shots, designed for riot shotguns." + icon_state = "lethalshot_box" + illustration = null + +/obj/item/storage/box/lethalshot/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/buckshot(src) + +/obj/item/storage/box/beanbag + name = "box of beanbags" + desc = "A box full of beanbag shells." + icon_state = "rubbershot_box" + illustration = null + +/obj/item/storage/box/beanbag/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/ammo_casing/shotgun/beanbag(src) + +/obj/item/storage/box/lethalslugs + name = "box of 12g shotgun slugs" + desc = "A box full of lethal 12g slug, designed for riot shotguns." + icon_state = "12g_box" + illustration = null + +/obj/item/storage/box/lethalslugs/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun(src) + +/obj/item/storage/box/stunslug + name = "box of stun slugs" + desc = "A box full of stun 12g slugs." + icon_state = "stunslug_box" + illustration = null + +/obj/item/storage/box/stunslug/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/stunslug(src) + +/obj/item/storage/box/techsslug + name = "box of tech shotgun shells" + desc = "A box full of tech shotgun shells." + icon_state = "techslug_box" + illustration = null + +/obj/item/storage/box/techsslug/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/techshell(src) + +/obj/item/storage/box/fireshot + name = "box of incendiary ammo" + desc = "A box full of incendiary ammo." + icon_state = "fireshot_box" + illustration = null + +/obj/item/storage/box/fireshot/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/ammo_casing/shotgun/incendiary(src) + +/obj/item/storage/box/actionfigure + name = "box of action figures" + desc = "The latest set of collectable action figures." + icon_state = "box" + +/obj/item/storage/box/actionfigure/PopulateContents() + for(var/i in 1 to 4) + var/randomFigure = pick(subtypesof(/obj/item/toy/figure)) + new randomFigure(src) + +/obj/item/storage/box/mechfigures + name = "box of mech figures" + desc = "The latest set of collectable mech figures." + icon_state = "box" + +/obj/item/storage/box/mechfigures/PopulateContents() + for(var/i in 1 to 4) + var/randomFigure = pick(subtypesof(/obj/item/toy/prize/)) + new randomFigure(src) + + + + +/obj/item/storage/box/papersack + name = "paper sack" + desc = "A sack neatly crafted out of paper." + icon_state = "paperbag_None" + item_state = "paperbag_None" + resistance_flags = FLAMMABLE + foldable = null + /// A list of all available papersack reskins + var/list/papersack_designs = list() + +/obj/item/storage/box/papersack/Initialize(mapload) + . = ..() + papersack_designs = sortList(list( + "None" = image(icon = src.icon, icon_state = "paperbag_None"), + "NanotrasenStandard" = image(icon = src.icon, icon_state = "paperbag_NanotrasenStandard"), + "SyndiSnacks" = image(icon = src.icon, icon_state = "paperbag_SyndiSnacks"), + "Heart" = image(icon = src.icon, icon_state = "paperbag_Heart"), + "SmileyFace" = image(icon = src.icon, icon_state = "paperbag_SmileyFace") + )) + +/obj/item/storage/box/papersack/update_icon_state() + if(contents.len == 0) + icon_state = "[item_state]" + else + icon_state = "[item_state]_closed" + +/obj/item/storage/box/papersack/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/pen)) + var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, .proc/check_menu, user, W), radius = 36, require_near = TRUE) + if(!choice) + return FALSE + if(icon_state == "paperbag_[choice]") + return FALSE + switch(choice) + if("None") + desc = "A sack neatly crafted out of paper." + if("NanotrasenStandard") + desc = "A standard Kinaris paper lunch sack for loyal employees on the go." + if("SyndiSnacks") + desc = "The design on this paper sack is a remnant of the notorious 'SyndieSnacks' program." + if("Heart") + desc = "A paper sack with a heart etched onto the side." + if("SmileyFace") + desc = "A paper sack with a crude smile etched onto the side." + else + return FALSE + to_chat(user, "You make some modifications to [src] using your pen.") + icon_state = "paperbag_[choice]" + item_state = "paperbag_[choice]" + return FALSE + else if(W.is_sharp()) + if(!contents.len) + if(item_state == "paperbag_None") + user.show_message("You cut eyeholes into [src].", MSG_VISUAL) + new /obj/item/clothing/head/papersack(user.loc) + qdel(src) + return FALSE + else if(item_state == "paperbag_SmileyFace") + user.show_message("You cut eyeholes into [src] and modify the design.", MSG_VISUAL) + new /obj/item/clothing/head/papersack/smiley(user.loc) + qdel(src) + return FALSE + return ..() + +/** + * check_menu: Checks if we are allowed to interact with a radial menu + * + * Arguments: + * * user The mob interacting with a menu + * * P The pen used to interact with a menu + */ +/obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P) + if(!istype(user)) + return FALSE + if(user.incapacitated()) + return FALSE + if(contents.len) + to_chat(user, "You can't modify [src] with items still inside!") + return FALSE + if(!P || !user.is_holding(P)) + to_chat(user, "You need a pen to modify [src]!") + return FALSE + return TRUE + +/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist. + name = "ingredients box" + illustration = "fruit" + var/theme_name + +/obj/item/storage/box/ingredients/Initialize() + . = ..() + if(theme_name) + name = "[name] ([theme_name])" + desc = "A box containing supplementary ingredients for the aspiring chef. The box's theme is '[theme_name]'." + item_state = "syringe_kit" + +/obj/item/storage/box/ingredients/wildcard + theme_name = "wildcard" + +/obj/item/storage/box/ingredients/wildcard/PopulateContents() + for(var/i in 1 to 7) + var/randomFood = pick(/obj/item/reagent_containers/food/snacks/grown/chili, + /obj/item/reagent_containers/food/snacks/grown/tomato, + /obj/item/reagent_containers/food/snacks/grown/carrot, + /obj/item/reagent_containers/food/snacks/grown/potato, + /obj/item/reagent_containers/food/snacks/grown/potato/sweet, + /obj/item/reagent_containers/food/snacks/grown/apple, + /obj/item/reagent_containers/food/snacks/chocolatebar, + /obj/item/reagent_containers/food/snacks/grown/cherries, + /obj/item/reagent_containers/food/snacks/grown/banana, + /obj/item/reagent_containers/food/snacks/grown/cabbage, + /obj/item/reagent_containers/food/snacks/grown/soybeans, + /obj/item/reagent_containers/food/snacks/grown/corn, + /obj/item/reagent_containers/food/snacks/grown/mushroom/plumphelmet, + /obj/item/reagent_containers/food/snacks/grown/mushroom/chanterelle) + new randomFood(src) + +/obj/item/storage/box/ingredients/fiesta + theme_name = "fiesta" + +/obj/item/storage/box/ingredients/fiesta/PopulateContents() + new /obj/item/reagent_containers/food/snacks/tortilla(src) + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/corn(src) + new /obj/item/reagent_containers/food/snacks/grown/soybeans(src) + new /obj/item/reagent_containers/food/snacks/grown/chili(src) + +/obj/item/storage/box/ingredients/italian + theme_name = "italian" + +/obj/item/storage/box/ingredients/italian/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/reagent_containers/food/snacks/grown/tomato(src) + new /obj/item/reagent_containers/food/snacks/meatball(src) + new /obj/item/reagent_containers/food/drinks/bottle/wine(src) + +/obj/item/storage/box/ingredients/vegetarian + theme_name = "vegetarian" + +/obj/item/storage/box/ingredients/vegetarian/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/carrot(src) + new /obj/item/reagent_containers/food/snacks/grown/eggplant(src) + new /obj/item/reagent_containers/food/snacks/grown/potato(src) + new /obj/item/reagent_containers/food/snacks/grown/apple(src) + new /obj/item/reagent_containers/food/snacks/grown/corn(src) + new /obj/item/reagent_containers/food/snacks/grown/tomato(src) + +/obj/item/storage/box/ingredients/american + theme_name = "american" + +/obj/item/storage/box/ingredients/american/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/potato(src) + new /obj/item/reagent_containers/food/snacks/grown/tomato(src) + new /obj/item/reagent_containers/food/snacks/grown/corn(src) + new /obj/item/reagent_containers/food/snacks/meatball(src) + +/obj/item/storage/box/ingredients/fruity + theme_name = "fruity" + +/obj/item/storage/box/ingredients/fruity/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/apple(src) + new /obj/item/reagent_containers/food/snacks/grown/citrus/orange(src) + new /obj/item/reagent_containers/food/snacks/grown/citrus/lemon(src) + new /obj/item/reagent_containers/food/snacks/grown/citrus/lime(src) + new /obj/item/reagent_containers/food/snacks/grown/watermelon(src) + +/obj/item/storage/box/ingredients/sweets + theme_name = "sweets" + +/obj/item/storage/box/ingredients/sweets/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/cherries(src) + new /obj/item/reagent_containers/food/snacks/grown/banana(src) + new /obj/item/reagent_containers/food/snacks/chocolatebar(src) + new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) + new /obj/item/reagent_containers/food/snacks/grown/apple(src) + +/obj/item/storage/box/ingredients/delights + theme_name = "delights" + +/obj/item/storage/box/ingredients/delights/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/grown/potato/sweet(src) + new /obj/item/reagent_containers/food/snacks/grown/bluecherries(src) + new /obj/item/reagent_containers/food/snacks/grown/vanillapod(src) + new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) + new /obj/item/reagent_containers/food/snacks/grown/berries(src) + +/obj/item/storage/box/ingredients/grains + theme_name = "grains" + +/obj/item/storage/box/ingredients/grains/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/reagent_containers/food/snacks/grown/oat(src) + new /obj/item/reagent_containers/food/snacks/grown/wheat(src) + new /obj/item/reagent_containers/food/snacks/grown/cocoapod(src) + new /obj/item/reagent_containers/honeycomb(src) + new /obj/item/seeds/poppy(src) + +/obj/item/storage/box/ingredients/carnivore + theme_name = "carnivore" + +/obj/item/storage/box/ingredients/carnivore/PopulateContents() + new /obj/item/reagent_containers/food/snacks/meat/slab/bear(src) + new /obj/item/reagent_containers/food/snacks/meat/slab/spider(src) + new /obj/item/reagent_containers/food/snacks/spidereggs(src) + new /obj/item/reagent_containers/food/snacks/carpmeat(src) + new /obj/item/reagent_containers/food/snacks/meat/slab/xeno(src) + new /obj/item/reagent_containers/food/snacks/meat/slab/corgi(src) + new /obj/item/reagent_containers/food/snacks/meatball(src) + +/obj/item/storage/box/ingredients/exotic + theme_name = "exotic" + +/obj/item/storage/box/ingredients/exotic/PopulateContents() + for(var/i in 1 to 2) + new /obj/item/reagent_containers/food/snacks/carpmeat(src) + new /obj/item/reagent_containers/food/snacks/grown/soybeans(src) + new /obj/item/reagent_containers/food/snacks/grown/cabbage(src) + new /obj/item/reagent_containers/food/snacks/grown/chili(src) + +/obj/item/storage/box/emptysandbags + name = "box of empty sandbags" + +/obj/item/storage/box/emptysandbags/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/emptysandbag(src) + +/obj/item/storage/box/rndboards + name = "\proper the liberator's legacy" + desc = "A box containing a gift for worthy golems." + +/obj/item/storage/box/rndboards/PopulateContents() + new /obj/item/circuitboard/machine/protolathe(src) + new /obj/item/circuitboard/machine/destructive_analyzer(src) + new /obj/item/circuitboard/machine/circuit_imprinter(src) + new /obj/item/circuitboard/computer/rdconsole(src) + +/obj/item/storage/box/silver_sulf + name = "box of silver sulfadiazine patches" + desc = "Contains patches used to treat burns." + +/obj/item/storage/box/silver_sulf/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + +/obj/item/storage/box/fountainpens + name = "box of fountain pens" + +/obj/item/storage/box/fountainpens/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/pen/fountain(src) + +/obj/item/storage/box/holy_grenades + name = "box of holy hand grenades" + desc = "Contains several grenades used to rapidly purge heresy." + illustration = "flashbang" + +/obj/item/storage/box/holy_grenades/PopulateContents() + for(var/i in 1 to 7) + new/obj/item/grenade/chem_grenade/holy(src) + +/obj/item/storage/box/stockparts/basic //for ruins where it's a bad idea to give access to an autolathe/protolathe, but still want to make stock parts accessible + name = "box of stock parts" + desc = "Contains a variety of basic stock parts." + +/obj/item/storage/box/stockparts/basic/PopulateContents() + new /obj/item/stock_parts/capacitor(src) + new /obj/item/stock_parts/capacitor(src) + new /obj/item/stock_parts/capacitor(src) + new /obj/item/stock_parts/scanning_module(src) + new /obj/item/stock_parts/scanning_module(src) + new /obj/item/stock_parts/scanning_module(src) + new /obj/item/stock_parts/manipulator(src) + new /obj/item/stock_parts/manipulator(src) + new /obj/item/stock_parts/manipulator(src) + new /obj/item/stock_parts/micro_laser(src) + new /obj/item/stock_parts/micro_laser(src) + new /obj/item/stock_parts/micro_laser(src) + new /obj/item/stock_parts/matter_bin(src) + new /obj/item/stock_parts/matter_bin(src) + new /obj/item/stock_parts/matter_bin(src) + +/obj/item/storage/box/stockparts/deluxe + name = "box of deluxe stock parts" + desc = "Contains a variety of deluxe stock parts." + icon_state = "syndiebox" + +/obj/item/storage/box/stockparts/deluxe/PopulateContents() + new /obj/item/stock_parts/capacitor/quadratic(src) + new /obj/item/stock_parts/capacitor/quadratic(src) + new /obj/item/stock_parts/capacitor/quadratic(src) + new /obj/item/stock_parts/scanning_module/triphasic(src) + new /obj/item/stock_parts/scanning_module/triphasic(src) + new /obj/item/stock_parts/scanning_module/triphasic(src) + new /obj/item/stock_parts/manipulator/femto(src) + new /obj/item/stock_parts/manipulator/femto(src) + new /obj/item/stock_parts/manipulator/femto(src) + new /obj/item/stock_parts/micro_laser/quadultra(src) + new /obj/item/stock_parts/micro_laser/quadultra(src) + new /obj/item/stock_parts/micro_laser/quadultra(src) + new /obj/item/stock_parts/matter_bin/bluespace(src) + new /obj/item/stock_parts/matter_bin/bluespace(src) + new /obj/item/stock_parts/matter_bin/bluespace(src) + +//Colored boxes. +/obj/item/storage/box/green + icon_state = "box_green" + illustration = null + +/obj/item/storage/box/blue + icon_state = "box_blue" + illustration = null + +/obj/item/storage/box/purple + icon_state = "box_purple" + illustration = null + +/obj/item/storage/box/red + icon_state = "box_red" + illustration = null + +/obj/item/storage/box/yellow + icon_state = "box_yellow" + illustration = null + +/obj/item/storage/box/brown + icon_state = "box_brown" + illustration = null + +/obj/item/storage/box/pink + icon_state = "box_pink" + illustration = null + +/obj/item/storage/box/mre //base MRE type. + name = "Kinaris MRE Ration Kit Menu 0" + desc = "A package containing food suspended in an outdated bluespace pocket which lasts for centuries. If you're lucky you may even be able to enjoy the meal without getting food poisoning." + icon_state = "mre" + illustration = null + var/can_expire = TRUE + var/spawner_chance = 2 + var/expiration_date + var/expiration_date_min = 2300 + var/expiration_date_max = 2700 + +/obj/item/storage/box/mre/Initialize() + . = ..() + if(can_expire) + expiration_date = rand(expiration_date_min, expiration_date_max) + desc += "\nAn expiry date is listed on it. It reads: [expiration_date]" + var/spess_current_year = GLOB.year_integer + 540 + if(expiration_date < spess_current_year) + var/gross_risk = min(round(spess_current_year - expiration_date * 0.1), 1) + var/toxic_risk = min(round(spess_current_year - expiration_date * 0.01), 1) + for(var/obj/item/reagent_containers/food/snacks/S in contents) + if(prob(gross_risk)) + ENABLE_BITFIELD(S.foodtype, GROSS) + if(prob(toxic_risk)) + ENABLE_BITFIELD(S.foodtype, TOXIC) + +/obj/item/storage/box/mre/menu1 + name = "\improper Kinaris MRE Ration Kit Menu 1" + +/obj/item/storage/box/mre/menu1/safe + desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." + spawner_chance = 0 + can_expire = FALSE + +/obj/item/storage/box/mre/menu1/PopulateContents() + new /obj/item/reagent_containers/food/snacks/breadslice/plain(src) + new /obj/item/reagent_containers/food/snacks/breadslice/creamcheese(src) + new /obj/item/reagent_containers/food/condiment/pack/ketchup(src) + new /obj/item/reagent_containers/food/snacks/chocolatebar(src) + new /obj/item/tank/internals/emergency_oxygen(src) + +/obj/item/storage/box/mre/menu2 + name = "\improper Kinaris MRE Ration Kit Menu 2" + +/obj/item/storage/box/mre/menu2/safe + spawner_chance = 0 + desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." + can_expire = FALSE + +/obj/item/storage/box/mre/menu2/PopulateContents() + new /obj/item/reagent_containers/food/snacks/omelette(src) + new /obj/item/reagent_containers/food/snacks/meat/cutlet/plain(src) + new /obj/item/reagent_containers/food/snacks/fries(src) + new /obj/item/reagent_containers/food/snacks/chocolatebar(src) + new /obj/item/tank/internals/emergency_oxygen(src) + +/obj/item/storage/box/mre/menu3 + name = "\improper Kinaris MRE Ration Kit Menu 3" + desc = "The holy grail of MREs. This item contains the fabled MRE pizza, spicy nachos and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed." + icon_state = "menu3" + can_expire = FALSE //always fresh, never expired. + spawner_chance = 1 + +/obj/item/storage/box/mre/menu3/PopulateContents() + new /obj/item/reagent_containers/food/snacks/pizzaslice/pepperoni(src) + new /obj/item/reagent_containers/food/snacks/breadslice/plain(src) + new /obj/item/reagent_containers/food/snacks/cubannachos(src) + new /obj/item/reagent_containers/food/snacks/grown/chili(src) + new /obj/item/reagent_containers/food/drinks/coffee/type2(src) + new /obj/item/tank/internals/emergency_oxygen(src) + +/obj/item/storage/box/mre/menu4 + name = "\improper Kinaris MRE Ration Kit Menu 4" + +/obj/item/storage/box/mre/menu4/safe + spawner_chance = 0 + desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time." + can_expire = FALSE + +/obj/item/storage/box/mre/menu4/PopulateContents() + if(prob(66)) + new /obj/item/reagent_containers/food/snacks/salad/boiledrice(src) + else + new /obj/item/reagent_containers/food/snacks/salad/ricebowl(src) + new /obj/item/reagent_containers/food/snacks/burger/tofu(src) + new /obj/item/reagent_containers/food/snacks/salad/fruit(src) + new /obj/item/reagent_containers/food/snacks/cracker(src) + new /obj/item/tank/internals/emergency_oxygen(src) + +//Where do I put this? +/obj/item/secbat + name = "Secbat box" + desc = "Contained inside is a secbat for use with law enforcement." + icon = 'icons/obj/storage.dmi' + icon_state = "box" + item_state = "syringe_kit" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + +/obj/item/secbat/attack_self(mob/user) + new /mob/living/simple_animal/hostile/retaliate/bat/secbat(user.loc) + to_chat(user, "You open the box, releasing the secbat!") + var/obj/item/stack/sheet/cardboard/I = new(user.drop_location()) + qdel(src) + user.put_in_hands(I) diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 0129eeb3..92b0036e 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -1,240 +1,240 @@ - -#define SOURCE_PORTAL 1 -#define DESTINATION_PORTAL 2 - -/* Teleportation devices. - * Contains: - * Locator - * Hand-tele - */ - -/* - * Locator - */ -/obj/item/locator - name = "bluespace locator" - desc = "Used to track portable teleportation beacons and targets with embedded tracking implants." - icon = 'icons/obj/device.dmi' - icon_state = "locator" - var/temp = null - flags_1 = CONDUCT_1 - w_class = WEIGHT_CLASS_SMALL - item_state = "electronic" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - throw_speed = 3 - throw_range = 7 - materials = list(MAT_METAL=400) - -/obj/item/locator/attack_self(mob/user) - user.set_machine(src) - var/dat - if (temp) - dat = "[temp]

Clear" - else - dat = {" -Persistent Signal Locator
-Refresh"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return - -/obj/item/locator/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained()) - return - var/turf/current_location = get_turf(usr)//What turf is the user on? - if(!current_location || is_centcom_level(current_location.z))//If turf was not found or they're on CentCom - to_chat(usr, "[src] is malfunctioning.") - return - if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc))) - usr.set_machine(src) - if (href_list["refresh"]) - temp = "Persistent Signal Locator
" - var/turf/sr = get_turf(src) - - if (sr) - temp += "Beacon Signals:
" - for(var/obj/item/beacon/W in GLOB.teleportbeacons) - if (!W.renamed) - continue - var/turf/tr = get_turf(W) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - if (direct < 20) - direct = "weak" - else - direct = "very weak" - temp += "[W.name]-[dir2text(get_dir(sr, tr))]-[direct]
" - - temp += "Implant Signals:
" - for (var/obj/item/implant/tracking/W in GLOB.tracked_implants) - if (!isliving(W.imp_in)) - continue - var/mob/living/M = W.imp_in - if (M.stat == DEAD) - if (M.timeofdeath + W.lifespan_postmortem < world.time) - continue - - var/turf/tr = get_turf(M) - if (tr.z == sr.z && tr) - var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) - if (direct < 20) - if (direct < 5) - direct = "very strong" - else - if (direct < 10) - direct = "strong" - else - direct = "weak" - temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct]
" - - temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

Refresh
" - else - temp += "Processing Error: Unable to locate orbital position.
" - else - if (href_list["temp"]) - temp = null - if (ismob(src.loc)) - attack_self(src.loc) - else - for(var/mob/M in viewers(1, src)) - if (M.client) - src.attack_self(M) - return - - -/* - * Hand-tele - */ -/obj/item/hand_tele - name = "hand tele" - desc = "A portable item using blue-space technology." - icon = 'icons/obj/device.dmi' - icon_state = "hand_tele" - item_state = "electronic" - lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' - throwforce = 0 - w_class = WEIGHT_CLASS_SMALL - throw_speed = 3 - throw_range = 5 - materials = list(MAT_METAL=10000) - armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF - var/list/active_portal_pairs - var/max_portal_pairs = 3 - var/atmos_link_override - -/obj/item/hand_tele/Initialize() - . = ..() - active_portal_pairs = list() - -/obj/item/hand_tele/pre_attack(atom/target, mob/user, params) - if(try_dispel_portal(target, user)) - return FALSE - return ..() - -/obj/item/hand_tele/proc/try_dispel_portal(atom/target, mob/user) - if(is_parent_of_portal(target)) - qdel(target) - to_chat(user, "You dispel [target] with \the [src]!") - return TRUE - return FALSE - -/obj/item/hand_tele/afterattack(atom/target, mob/user) - try_dispel_portal(target, user) - . = ..() - -/obj/item/hand_tele/attack_self(mob/user) - var/turf/current_location = get_turf(user)//What turf is the user on? - var/area/current_area = current_location.loc - if(!current_location || current_area.noteleport || is_away_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf - to_chat(user, "\The [src] is malfunctioning.") - return - var/list/L = list( ) - for(var/obj/machinery/computer/teleporter/com in GLOB.machines) - if(com.target) - var/area/A = get_area(com.target) - if(!A || A.noteleport) - continue - if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged) - L["[get_area(com.target)] (Active)"] = com.target - else - L["[get_area(com.target)] (Inactive)"] = com.target - var/list/turfs = list( ) - for(var/turf/T in urange(10, orange=1)) - if(T.x>world.maxx-8 || T.x<8) - continue //putting them at the edge is dumb - if(T.y>world.maxy-8 || T.y<8) - continue - var/area/A = T.loc - if(A.noteleport) - continue - turfs += T - if(turfs.len) - L["None (Dangerous)"] = pick(turfs) - var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in L - if (!t1 || user.get_active_held_item() != src || user.incapacitated()) - return - if(active_portal_pairs.len >= max_portal_pairs) - user.show_message("\The [src] is recharging!") - return - var/atom/T = L[t1] - var/implantcheckmate = FALSE - if(isliving(T)) - var/mob/living/M = T - if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed. - implantcheckmate = TRUE - var/area/A = get_area(T) - if(A.noteleport || implantcheckmate) - to_chat(user, "\The [src] is malfunctioning.") - return - current_location = get_turf(user) //Recheck. - current_area = current_location.loc - if(!current_location || current_area.noteleport || is_away_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf - to_chat(user, "\The [src] is malfunctioning.") - return - user.show_message("Locked In.", 2) - var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1, null, atmos_link_override) - if(!(LAZYLEN(created) == 2)) - return - try_move_adjacent(created[1]) - active_portal_pairs[created[1]] = created[2] - var/obj/effect/portal/c1 = created[1] - var/obj/effect/portal/c2 = created[2] - investigate_log("was used by [key_name(user)] at [AREACOORD(user)] to create a portal pair with destinations [AREACOORD(c1)] and [AREACOORD(c2)].", INVESTIGATE_PORTAL) - add_fingerprint(user) - -/obj/item/hand_tele/proc/on_portal_destroy(obj/effect/portal/P) - active_portal_pairs -= P //If this portal pair is made by us it'll be erased along with the other portal by the portal. - -/obj/item/hand_tele/proc/is_parent_of_portal(obj/effect/portal/P) - if(!istype(P)) - return FALSE - if(active_portal_pairs[P]) - return SOURCE_PORTAL - for(var/i in active_portal_pairs) - if(active_portal_pairs[i] == P) - return DESTINATION_PORTAL - return FALSE - -/obj/item/hand_tele/suicide_act(mob/user) - if(iscarbon(user)) - user.visible_message("[user] is creating a weak portal and sticking [user.p_their()] head through! It looks like [user.p_theyre()] trying to commit suicide!") - var/mob/living/carbon/itemUser = user - var/obj/item/bodypart/head/head = itemUser.get_bodypart(BODY_ZONE_HEAD) - if(head) - head.drop_limb() - var/list/safeLevels = SSmapping.levels_by_any_trait(list(ZTRAIT_SPACE_RUINS, ZTRAIT_LAVA_RUINS, ZTRAIT_STATION, ZTRAIT_MINING)) - head.forceMove(locate(rand(1, world.maxx), rand(1, world.maxy), pick(safeLevels))) - itemUser.visible_message("The portal snaps closed taking [user]'s head with it!") - else - itemUser.visible_message("[user] looks even further depressed as they realize they do not have a head...and suddenly dies of shame!") - return (BRUTELOSS) + +#define SOURCE_PORTAL 1 +#define DESTINATION_PORTAL 2 + +/* Teleportation devices. + * Contains: + * Locator + * Hand-tele + */ + +/* + * Locator + */ +/obj/item/locator + name = "bluespace locator" + desc = "Used to track portable teleportation beacons and targets with embedded tracking implants." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + var/temp = null + flags_1 = CONDUCT_1 + w_class = WEIGHT_CLASS_SMALL + item_state = "electronic" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + throw_speed = 3 + throw_range = 7 + materials = list(MAT_METAL=400) + +/obj/item/locator/attack_self(mob/user) + user.set_machine(src) + var/dat + if (temp) + dat = "[temp]

Clear" + else + dat = {" +Persistent Signal Locator
+Refresh"} + user << browse(dat, "window=radio") + onclose(user, "radio") + return + +/obj/item/locator/Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + var/turf/current_location = get_turf(usr)//What turf is the user on? + if(!current_location || is_centcom_level(current_location.z))//If turf was not found or they're on CentCom + to_chat(usr, "[src] is malfunctioning.") + return + if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc))) + usr.set_machine(src) + if (href_list["refresh"]) + temp = "Persistent Signal Locator
" + var/turf/sr = get_turf(src) + + if (sr) + temp += "Beacon Signals:
" + for(var/obj/item/beacon/W in GLOB.teleportbeacons) + if (!W.renamed) + continue + var/turf/tr = get_turf(W) + if (tr.z == sr.z && tr) + var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + if (direct < 5) + direct = "very strong" + else + if (direct < 10) + direct = "strong" + else + if (direct < 20) + direct = "weak" + else + direct = "very weak" + temp += "[W.name]-[dir2text(get_dir(sr, tr))]-[direct]
" + + temp += "Implant Signals:
" + for (var/obj/item/implant/tracking/W in GLOB.tracked_implants) + if (!isliving(W.imp_in)) + continue + var/mob/living/M = W.imp_in + if (M.stat == DEAD) + if (M.timeofdeath + W.lifespan_postmortem < world.time) + continue + + var/turf/tr = get_turf(M) + if (tr.z == sr.z && tr) + var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y)) + if (direct < 20) + if (direct < 5) + direct = "very strong" + else + if (direct < 10) + direct = "strong" + else + direct = "weak" + temp += "[W.imp_in.name]-[dir2text(get_dir(sr, tr))]-[direct]
" + + temp += "You are at \[[sr.x],[sr.y],[sr.z]\] in orbital coordinates.

Refresh
" + else + temp += "Processing Error: Unable to locate orbital position.
" + else + if (href_list["temp"]) + temp = null + if (ismob(src.loc)) + attack_self(src.loc) + else + for(var/mob/M in viewers(1, src)) + if (M.client) + src.attack_self(M) + return + + +/* + * Hand-tele + */ +/obj/item/hand_tele + name = "hand tele" + desc = "A portable item using blue-space technology." + icon = 'icons/obj/device.dmi' + icon_state = "hand_tele" + item_state = "electronic" + lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' + throwforce = 0 + w_class = WEIGHT_CLASS_SMALL + throw_speed = 3 + throw_range = 5 + materials = list(MAT_METAL=10000) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/list/active_portal_pairs + var/max_portal_pairs = 3 + var/atmos_link_override + +/obj/item/hand_tele/Initialize() + . = ..() + active_portal_pairs = list() + +/obj/item/hand_tele/pre_attack(atom/target, mob/user, params) + if(try_dispel_portal(target, user)) + return FALSE + return ..() + +/obj/item/hand_tele/proc/try_dispel_portal(atom/target, mob/user) + if(is_parent_of_portal(target)) + qdel(target) + to_chat(user, "You dispel [target] with \the [src]!") + return TRUE + return FALSE + +/obj/item/hand_tele/afterattack(atom/target, mob/user) + try_dispel_portal(target, user) + . = ..() + +/obj/item/hand_tele/attack_self(mob/user) + var/turf/current_location = get_turf(user)//What turf is the user on? + var/area/current_area = current_location.loc + if(!current_location || current_area.noteleport || is_away_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf + to_chat(user, "\The [src] is malfunctioning.") + return + var/list/L = list( ) + for(var/obj/machinery/computer/teleporter/com in GLOB.machines) + if(com.target) + var/area/A = get_area(com.target) + if(!A || A.noteleport) + continue + if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged) + L["[get_area(com.target)] (Active)"] = com.target + else + L["[get_area(com.target)] (Inactive)"] = com.target + var/list/turfs = list( ) + for(var/turf/T in urange(10, orange=1)) + if(T.x>world.maxx-8 || T.x<8) + continue //putting them at the edge is dumb + if(T.y>world.maxy-8 || T.y<8) + continue + var/area/A = T.loc + if(A.noteleport) + continue + turfs += T + if(turfs.len) + L["None (Dangerous)"] = pick(turfs) + var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") as null|anything in L + if (!t1 || user.get_active_held_item() != src || user.incapacitated()) + return + if(active_portal_pairs.len >= max_portal_pairs) + user.show_message("\The [src] is recharging!") + return + var/atom/T = L[t1] + var/implantcheckmate = FALSE + if(isliving(T)) + var/mob/living/M = T + if(!locate(/obj/item/implant/tracking) in M.implants) //The user was too slow and let the target mob's tracking implant expire or get removed. + implantcheckmate = TRUE + var/area/A = get_area(T) + if(A.noteleport || implantcheckmate) + to_chat(user, "\The [src] is malfunctioning.") + return + current_location = get_turf(user) //Recheck. + current_area = current_location.loc + if(!current_location || current_area.noteleport || is_away_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf + to_chat(user, "\The [src] is malfunctioning.") + return + user.show_message("Locked In.", MSG_AUDIBLE) + var/list/obj/effect/portal/created = create_portal_pair(current_location, get_teleport_turf(get_turf(T)), src, 300, 1, null, atmos_link_override) + if(!(LAZYLEN(created) == 2)) + return + try_move_adjacent(created[1]) + active_portal_pairs[created[1]] = created[2] + var/obj/effect/portal/c1 = created[1] + var/obj/effect/portal/c2 = created[2] + investigate_log("was used by [key_name(user)] at [AREACOORD(user)] to create a portal pair with destinations [AREACOORD(c1)] and [AREACOORD(c2)].", INVESTIGATE_PORTAL) + add_fingerprint(user) + +/obj/item/hand_tele/proc/on_portal_destroy(obj/effect/portal/P) + active_portal_pairs -= P //If this portal pair is made by us it'll be erased along with the other portal by the portal. + +/obj/item/hand_tele/proc/is_parent_of_portal(obj/effect/portal/P) + if(!istype(P)) + return FALSE + if(active_portal_pairs[P]) + return SOURCE_PORTAL + for(var/i in active_portal_pairs) + if(active_portal_pairs[i] == P) + return DESTINATION_PORTAL + return FALSE + +/obj/item/hand_tele/suicide_act(mob/user) + if(iscarbon(user)) + user.visible_message("[user] is creating a weak portal and sticking [user.p_their()] head through! It looks like [user.p_theyre()] trying to commit suicide!") + var/mob/living/carbon/itemUser = user + var/obj/item/bodypart/head/head = itemUser.get_bodypart(BODY_ZONE_HEAD) + if(head) + head.drop_limb() + var/list/safeLevels = SSmapping.levels_by_any_trait(list(ZTRAIT_SPACE_RUINS, ZTRAIT_LAVA_RUINS, ZTRAIT_STATION, ZTRAIT_MINING)) + head.forceMove(locate(rand(1, world.maxx), rand(1, world.maxy), pick(safeLevels))) + itemUser.visible_message("The portal snaps closed taking [user]'s head with it!") + else + itemUser.visible_message("[user] looks even further depressed as they realize they do not have a head...and suddenly dies of shame!") + return (BRUTELOSS) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 5b58d186..65835457 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -182,7 +182,7 @@ return src.add_fingerprint(user) if (src.bullets < 1) - user.show_message("*click*", 2) + user.show_message("*click*", MSG_AUDIBLE) playsound(src, "gun_dry_fire", 30, 1) return playsound(user, 'sound/weapons/gunshot.ogg', 100, 1) diff --git a/code/game/objects/structures/loom.dm b/code/game/objects/structures/loom.dm index 553712a0..7d1ee27e 100644 --- a/code/game/objects/structures/loom.dm +++ b/code/game/objects/structures/loom.dm @@ -1,56 +1,81 @@ -//Loom, turns raw cotton and durathread into their respective fabrics. - -/obj/structure/loom - name = "loom" - desc = "A simple device used to weave cloth and other thread-based fabrics together into usable material." - icon = 'icons/obj/hydroponics/equipment.dmi' - icon_state = "loom" - density = TRUE - anchored = TRUE - -/obj/structure/loom/attackby(obj/item/I, mob/user) - if (user.a_intent != INTENT_HELP) - return ..() - if (istype(I, /obj/item/stack/sheet)) - if (!anchored) - return to_chat(user, "You have to anchor [src] first!") - - var/obj/item/stack/sheet/W = I - if(W.is_fabric && W.amount > 1) - user.visible_message("", - "You start weaving the [W.name] through the loom.") - - if(W.use_tool(src, user, W.pull_effort)) - new W.loom_result(drop_location()) - to_chat(user, "You weave the [W.name] into a workable fabric.") - W.amount = (W.amount - 2) - if(W.amount < 1) - qdel(W) - else if(W.is_fabric) - to_chat("You need at least 2 [W.name] to loom into fabric!") - return - else - switch (I.tool_behaviour) - if (TOOL_SCREWDRIVER) - user.visible_message("[user] starts disassembling [src]...", - "You start disassembling [src]...") - I.play_tool_sound(src) - if(I.use_tool(src, user, 60)) - playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) - deconstruct(TRUE) - return - if (TOOL_WRENCH) - if (anchored) - to_chat(user, "You unsecure the [src].") - I.play_tool_sound(src) - anchored = FALSE - else - to_chat(user, "You secure the [src].") - I.play_tool_sound(src) - anchored = TRUE - return - return ..() - -/obj/structure/loom/deconstruct(disassembled = TRUE) - new /obj/item/stack/sheet/mineral/wood (get_turf(src), 10) - qdel(src) +//Loom, turns raw cotton and durathread into their respective fabrics. + +/obj/structure/loom + name = "loom" + desc = "A simple device used to weave cloth and other thread-based fabrics together into usable material." + icon = 'icons/obj/hydroponics/equipment.dmi' + icon_state = "loom" + density = TRUE + anchored = TRUE + +/obj/structure/loom/attackby(obj/item/I, mob/user) + if (user.a_intent != INTENT_HELP) + return ..() + if (istype(I, /obj/item/stack/sheet)) + if (!anchored) + return to_chat(user, "You have to anchor [src] first!") + + var/obj/item/stack/sheet/W = I + if(W.is_fabric && W.amount > 1) + user.visible_message("", + "You start weaving the [W.name] through the loom.") + + if(W.use_tool(src, user, W.pull_effort)) + new W.loom_result(drop_location()) + to_chat(user, "You weave the [W.name] into a workable fabric.") + W.amount = (W.amount - 2) + if(W.amount < 1) + qdel(W) + else if(W.is_fabric) + to_chat("You need at least 2 [W.name] to loom into fabric!") + return + else + switch (I.tool_behaviour) + if (TOOL_SCREWDRIVER) + user.visible_message("[user] starts disassembling [src]...", + "You start disassembling [src]...") + I.play_tool_sound(src) + if(I.use_tool(src, user, 60)) + playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE) + deconstruct(TRUE) + return + if (TOOL_WRENCH) + if (anchored) + to_chat(user, "You unsecure the [src].") + I.play_tool_sound(src) + anchored = FALSE + else + to_chat(user, "You secure the [src].") + I.play_tool_sound(src) + anchored = TRUE + return + return ..() + +/obj/structure/loom/deconstruct(disassembled = TRUE) + new /obj/item/stack/sheet/mineral/wood (get_turf(src), 10) + qdel(src) + + + +/*///Handles the weaving. +/obj/structure/loom/proc/weave(obj/item/stack/sheet/S, mob/user) + if(!istype(S) || !S.is_fabric) + return FALSE + if(!anchored) + user.show_message("The loom needs to be wrenched down.", MSG_VISUAL) + return FALSE + if(S.amount < FABRIC_PER_SHEET) + user.show_message("You need at least [FABRIC_PER_SHEET] units of fabric before using this.", 1) + return FALSE + user.show_message("You start weaving \the [S.name] through the loom..", MSG_VISUAL) + if(S.use_tool(src, user, S.pull_effort)) + if(S.amount >= FABRIC_PER_SHEET) + new S.loom_result(drop_location()) + S.use(FABRIC_PER_SHEET) + user.show_message("You weave \the [S.name] into a workable fabric.", MSG_VISUAL) + return TRUE + +/obj/structure/loom/unanchored + anchored = FALSE + +#undef FABRIC_PER_SHEET */ diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm index a524e0c0..436adc47 100644 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ b/code/modules/clothing/spacesuits/hardsuit.dm @@ -65,7 +65,7 @@ /obj/item/clothing/head/helmet/space/hardsuit/proc/display_visor_message(var/msg) var/mob/wearer = loc if(msg && ishuman(wearer)) - wearer.show_message("[icon2html(src, wearer)][msg]", 1) + wearer.show_message("[icon2html(src, wearer)][msg]", MSG_VISUAL) /obj/item/clothing/head/helmet/space/hardsuit/rad_act(severity) . = ..() diff --git a/code/modules/hydroponics/grown/cotton.dm b/code/modules/hydroponics/grown/cotton.dm index 3fa4247f..a3ac7d33 100644 --- a/code/modules/hydroponics/grown/cotton.dm +++ b/code/modules/hydroponics/grown/cotton.dm @@ -32,7 +32,7 @@ var/cotton_name = "raw cotton" /obj/item/grown/cotton/attack_self(mob/user) - user.show_message("You pull some [cotton_name] out of the [name]!", 1) + user.show_message("You pull some [cotton_name] out of the [name]!", MSG_VISUAL) var/seed_modifier = 0 if(seed) seed_modifier = round(seed.potency / 25) diff --git a/code/modules/hydroponics/grown/pumpkin.dm b/code/modules/hydroponics/grown/pumpkin.dm index e26d1c1d..6254fb5b 100644 --- a/code/modules/hydroponics/grown/pumpkin.dm +++ b/code/modules/hydroponics/grown/pumpkin.dm @@ -28,8 +28,8 @@ wine_power = 20 /obj/item/reagent_containers/food/snacks/grown/pumpkin/attackby(obj/item/W as obj, mob/user as mob, params) - if(W.is_sharp()) - user.show_message("You carve a face into [src]!", 1) + if(W.get_sharpness()) + user.show_message("You carve a face into [src]!", MSG_VISUAL) new /obj/item/clothing/head/hardhat/pumpkinhead(user.loc) qdel(src) return diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 6df0f0cd..b120e592 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -51,7 +51,7 @@ /obj/item/grown/log/attackby(obj/item/W, mob/user, params) if(W.sharpness) - user.show_message("You make [plank_name] out of \the [src]!", 1) + user.show_message("You make [plank_name] out of \the [src]!", MSG_VISUAL) var/seed_modifier = 0 if(seed) seed_modifier = round(seed.potency / 25) diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index 896b9ad2..d08eb5ae 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -861,27 +861,27 @@ if(M.stat == DEAD) //F return if(M == H) - H.show_message("You cringe with pain as your body rings around you!", 2) + H.show_message("You cringe with pain as your body rings around you!", MSG_AUDIBLE) H.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE) H.soundbang_act(2, 0, 100, 1) H.jitteriness += 7 var/distance = max(0,get_dist(get_turf(H),get_turf(M))) switch(distance) if(0 to 1) - M.show_message("GONG!", 2) + M.show_message("GONG!", MSG_AUDIBLE) M.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE) M.soundbang_act(1, 0, 30, 3) M.confused += 10 M.jitteriness += 4 SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong) if(2 to 3) - M.show_message("GONG!", 2) + M.show_message("GONG!", MSG_AUDIBLE) M.playsound_local(H, 'sound/effects/gong.ogg', 75, TRUE) M.soundbang_act(1, 0, 15, 2) M.jitteriness += 3 SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong) else - M.show_message("GONG!", 2) + M.show_message("GONG!", MSG_AUDIBLE) M.playsound_local(H, 'sound/effects/gong.ogg', 50, TRUE) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index f3336344..8d2c75d7 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -1,431 +1,431 @@ -GLOBAL_LIST_INIT(department_radio_prefixes, list(":", ".")) - -GLOBAL_LIST_INIT(department_radio_keys, list( - // Location - MODE_KEY_R_HAND = MODE_R_HAND, - MODE_KEY_L_HAND = MODE_L_HAND, - MODE_KEY_INTERCOM = MODE_INTERCOM, - - // Department - MODE_KEY_DEPARTMENT = MODE_DEPARTMENT, - RADIO_KEY_COMMAND = RADIO_CHANNEL_COMMAND, - RADIO_KEY_SCIENCE = RADIO_CHANNEL_SCIENCE, - RADIO_KEY_MEDICAL = RADIO_CHANNEL_MEDICAL, - RADIO_KEY_ENGINEERING = RADIO_CHANNEL_ENGINEERING, - RADIO_KEY_SECURITY = RADIO_CHANNEL_SECURITY, - RADIO_KEY_SUPPLY = RADIO_CHANNEL_SUPPLY, - RADIO_KEY_SERVICE = RADIO_CHANNEL_SERVICE, - - // Faction - RADIO_KEY_SYNDICATE = RADIO_CHANNEL_SYNDICATE, - RADIO_KEY_CENTCOM = RADIO_CHANNEL_CENTCOM, - - // Admin - MODE_KEY_ADMIN = MODE_ADMIN, - MODE_KEY_DEADMIN = MODE_DEADMIN, - - // Misc - RADIO_KEY_AI_PRIVATE = RADIO_CHANNEL_AI_PRIVATE, // AI Upload channel - MODE_KEY_VOCALCORDS = MODE_VOCALCORDS, // vocal cords, used by Voice of God - - - //kinda localization -- rastaf0 - //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. - // Location - "ê" = MODE_R_HAND, - "ä" = MODE_L_HAND, - "ø" = MODE_INTERCOM, - - // Department - "ð" = MODE_DEPARTMENT, - "ñ" = RADIO_CHANNEL_COMMAND, - "ò" = RADIO_CHANNEL_SCIENCE, - "ü" = RADIO_CHANNEL_MEDICAL, - "ó" = RADIO_CHANNEL_ENGINEERING, - "û" = RADIO_CHANNEL_SECURITY, - "ã" = RADIO_CHANNEL_SUPPLY, - "ì" = RADIO_CHANNEL_SERVICE, - - // Faction - "å" = RADIO_CHANNEL_SYNDICATE, - "í" = RADIO_CHANNEL_CENTCOM, - - // Admin - "ç" = MODE_ADMIN, - "â" = MODE_ADMIN, - - // Misc - "ù" = RADIO_CHANNEL_AI_PRIVATE, - "÷" = MODE_VOCALCORDS -)) - -/mob/living/proc/Ellipsis(original_msg, chance = 50, keep_words) - if(chance <= 0) - return "..." - if(chance >= 100) - return original_msg - - var/list/words = splittext(original_msg," ") - var/list/new_words = list() - - var/new_msg = "" - - for(var/w in words) - if(prob(chance)) - new_words += "..." - if(!keep_words) - continue - new_words += w - - new_msg = jointext(new_words," ") - - return new_msg - -/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) - var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) - var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) - var/talk_key = get_key(message) - - var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE, MODE_SING = TRUE) - - if(sanitize) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - if(!message || message == "") - return - - var/datum/saymode/saymode = SSradio.saymodes[talk_key] - var/message_mode = get_message_mode(message) - var/original_message = message - var/in_critical = InCritical() - - if(one_character_prefix[message_mode]) - message = copytext(message, 2) - else if(message_mode || saymode) - message = copytext(message, 3) - if(findtext(message, " ", 1, 2)) - message = copytext(message, 2) - - if(message_mode == MODE_ADMIN) - if(client) - client.cmd_admin_say(message) - return - - if(message_mode == MODE_DEADMIN) - if(client) - client.dsay(message) - return - - if(stat == DEAD) - say_dead(original_message) - return - - if(check_emote(original_message) || !can_speak_basic(original_message, ignore_spam)) - return - - if(in_critical) - if(!(crit_allowed_modes[message_mode])) - return - else if(stat == UNCONSCIOUS) - if(!(unconscious_allowed_modes[message_mode])) - return - - // language comma detection. - var/datum/language/message_language = get_message_language(message) - if(message_language) - // No, you cannot speak in xenocommon just because you know the key - if(can_speak_in_language(message_language)) - language = message_language - message = copytext(message, 3) - - // Trim the space if they said ",0 I LOVE LANGUAGES" - if(findtext(message, " ", 1, 2)) - message = copytext(message, 2) - - if(!language) - language = get_default_language() - - // Detection of language needs to be before inherent channels, because - // AIs use inherent channels for the holopad. Most inherent channels - // ignore the language argument however. - - if(saymode && !saymode.handle_message(src, message, language)) - return - - if(!can_speak_vocal(message)) - to_chat(src, "You find yourself unable to speak!") - return - - var/message_range = 7 - - var/succumbed = FALSE - - var/fullcrit = InFullCritical() - if((InCritical() && !fullcrit) || message_mode == MODE_WHISPER) - message_range = 1 - message_mode = MODE_WHISPER - src.log_talk(message, LOG_WHISPER) - if(fullcrit) - var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health) - // If we cut our message short, abruptly end it with a-.. - var/message_len = length(message) - message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]" - message = Ellipsis(message, 10, 1) - message_mode = MODE_WHISPER_CRIT - succumbed = TRUE - else - src.log_talk(message, LOG_SAY, forced_by=forced) - - message = treat_message(message) // unfortunately we still need this - var/sigreturn = SEND_SIGNAL(src, COMSIG_MOB_SAY, args) - if (sigreturn & COMPONENT_UPPERCASE_SPEECH) - message = uppertext(message) - if(!message) - return - - last_words = message - - spans |= speech_span - - if(language) - var/datum/language/L = GLOB.language_datum_instances[language] - spans |= L.spans - - if(message_mode == MODE_SING) - #if DM_VERSION < 513 - var/randomnote = "~" - #else - var/randomnote = pick("\u2669", "\u266A", "\u266B") - #endif - spans |= SPAN_SINGING - message = "[randomnote] [message] [randomnote]" - - var/radio_return = radio(message, message_mode, spans, language) - if(radio_return & ITALICS) - spans |= SPAN_ITALICS - if(radio_return & REDUCE_RANGE) - message_range = 1 - if(radio_return & NOPASS) - return 1 - - //No screams in space, unless you're next to someone. - var/turf/T = get_turf(src) - var/datum/gas_mixture/environment = T.return_air() - var/pressure = (environment)? environment.return_pressure() : 0 - if(pressure < SOUND_MINIMUM_PRESSURE) - message_range = 1 - - if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message - spans |= SPAN_ITALICS - - send_speech(message, message_range, src, bubble_type, spans, language, message_mode) - - if(succumbed) - succumb() - to_chat(src, compose_message(src, language, message, , spans, message_mode)) - - return 1 - -/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - . = ..() - if(!client) - return - var/deaf_message - var/deaf_type - if(speaker != src) - if(!radio_freq) //These checks have to be seperate, else people talking on the radio will make "You can't hear yourself!" appear when hearing people over the radio while deaf. - deaf_message = "[speaker] [speaker.verb_say] something but you cannot hear [speaker.p_them()]." - deaf_type = 1 - else - deaf_message = "You can't hear yourself!" - deaf_type = 2 // Since you should be able to hear yourself without looking - // Create map text prior to modifying message for goonchat - if (client?.prefs.chat_on_map && stat != UNCONSCIOUS && (client.prefs.see_chat_non_mob || ismob(speaker)) && can_hear()) - create_chat_message(speaker, message_language, raw_message, spans, message_mode) - if (client?.prefs.radiosounds && stat != UNCONSCIOUS && can_hear() && radio_freq) - playsound_local(src,'sound/voice/radio.ogg', 30, 1) - - // Recompose message for AI hrefs, language incomprehension. - message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) - message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) - - show_message(message, 2, deaf_message, deaf_type) - return message - -/mob/living/proc/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - return message - -/mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode) - var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE) - var/eavesdrop_range = 0 - if(eavesdropping_modes[message_mode]) - eavesdrop_range = EAVESDROP_EXTRA_RANGE - var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source) - var/list/the_dead = list() - var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas - if(say_test(message) == "2") //CIT CHANGE - ditto - yellareas = get_areas_in_range(message_range*0.5,src) //CIT CHANGE - ditto - for(var/_M in GLOB.player_list) - var/mob/M = _M - if(M.stat != DEAD) //not dead, not important - if(yellareas) //CIT CHANGE - see above. makes yelling penetrate walls - var/area/A = get_area(M) //CIT CHANGE - ditto - if(istype(A) && A.ambientsounds != SPACE && A in yellareas) //CIT CHANGE - ditto - listening |= M //CIT CHANGE - ditto - continue - if(!M.client || !client) //client is so that ghosts don't have to listen to mice - continue - if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing - if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off - continue - if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off - continue - listening |= M - the_dead[M] = TRUE - - var/eavesdropping - var/eavesrendered - if(eavesdrop_range) - eavesdropping = stars(message) - eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode) - - var/rendered = compose_message(src, message_language, message, , spans, message_mode) - for(var/_AM in listening) - var/atom/movable/AM = _AM - if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM])) - AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode) - else - AM.Hear(rendered, src, message_language, message, , spans, message_mode) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message) - - //speech bubble - var/list/speech_bubble_recipients = list() - for(var/mob/M in listening) - if(M.client && !M.client.prefs.chat_on_map) - speech_bubble_recipients.Add(M.client) - var/image/I = image('icons/mob/talk.dmi', src, "[bubble_type][say_test(message)]", FLY_LAYER) - I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA - INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30) - -/mob/proc/binarycheck() - return FALSE - -/mob/living/can_speak(message) //For use outside of Say() - if(can_speak_basic(message) && can_speak_vocal(message)) - return 1 - -/mob/living/proc/can_speak_basic(message, ignore_spam = FALSE) //Check BEFORE handling of xeno and ling channels - if(client) - if(client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot speak in IC (muted).") - return 0 - if(!ignore_spam && client.handle_spam_prevention(message,MUTE_IC)) - return 0 - - return 1 - -/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels - if(HAS_TRAIT(src, TRAIT_MUTE)) - return 0 - - if(is_muzzled()) - return 0 - - if(!IsVocal()) - return 0 - - return 1 - -/mob/living/proc/get_key(message) - var/key = copytext(message, 1, 2) - if(key in GLOB.department_radio_prefixes) - return lowertext(copytext(message, 2, 3)) - -/mob/living/proc/get_message_language(message) - if(copytext(message, 1, 2) == ",") - var/key = copytext(message, 2, 3) - for(var/ld in GLOB.all_languages) - var/datum/language/LD = ld - if(initial(LD.key) == key) - return LD - return null - -/mob/living/proc/treat_message(message) - - if(HAS_TRAIT(src, TRAIT_UNINTELLIGIBLE_SPEECH)) - message = unintelligize(message) - - if(derpspeech) - message = derpspeech(message, stuttering) - - if(stuttering) - message = stutter(message) - - if(slurring) - message = slur(message,slurring) - - if(cultslurring) - message = cultslur(message) - - message = capitalize(message) - - return message - -/mob/living/proc/radio(message, message_mode, list/spans, language) - var/obj/item/implant/radio/imp = locate() in implants - if(imp?.radio.on) - if(message_mode == MODE_HEADSET) - imp.radio.talk_into(src, message, , spans, language) - return ITALICS | REDUCE_RANGE - if(message_mode == MODE_DEPARTMENT || message_mode in GLOB.radiochannels) - imp.radio.talk_into(src, message, message_mode, spans, language) - return ITALICS | REDUCE_RANGE - - switch(message_mode) - if(MODE_WHISPER) - return ITALICS - if(MODE_R_HAND) - for(var/obj/item/r_hand in get_held_items_for_side("r", all = TRUE)) - if (r_hand) - return r_hand.talk_into(src, message, , spans, language) - return ITALICS | REDUCE_RANGE - if(MODE_L_HAND) - for(var/obj/item/l_hand in get_held_items_for_side("l", all = TRUE)) - if (l_hand) - return l_hand.talk_into(src, message, , spans, language) - return ITALICS | REDUCE_RANGE - - if(MODE_INTERCOM) - for (var/obj/item/radio/intercom/I in view(1, null)) - I.talk_into(src, message, , spans, language) - return ITALICS | REDUCE_RANGE - - if(MODE_BINARY) - return ITALICS | REDUCE_RANGE //Does not return 0 since this is only reached by humans, not borgs or AIs. - - return 0 - -/mob/living/say_mod(input, message_mode) - if(message_mode == MODE_WHISPER) - . = verb_whisper - else if(message_mode == MODE_WHISPER_CRIT) - . = "[verb_whisper] in [p_their()] last breath" - else if(stuttering) - . = "stammers" - else if(derpspeech) - . = "gibbers" - else if(message_mode == MODE_SING) - . = verb_sing - else - . = ..() - -/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) - say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced) - -/mob/living/get_language_holder(shadow=TRUE) - if(mind && shadow) - // Mind language holders shadow mob holders. - . = mind.get_language_holder() - if(.) - return . - - . = ..() +GLOBAL_LIST_INIT(department_radio_prefixes, list(":", ".")) + +GLOBAL_LIST_INIT(department_radio_keys, list( + // Location + MODE_KEY_R_HAND = MODE_R_HAND, + MODE_KEY_L_HAND = MODE_L_HAND, + MODE_KEY_INTERCOM = MODE_INTERCOM, + + // Department + MODE_KEY_DEPARTMENT = MODE_DEPARTMENT, + RADIO_KEY_COMMAND = RADIO_CHANNEL_COMMAND, + RADIO_KEY_SCIENCE = RADIO_CHANNEL_SCIENCE, + RADIO_KEY_MEDICAL = RADIO_CHANNEL_MEDICAL, + RADIO_KEY_ENGINEERING = RADIO_CHANNEL_ENGINEERING, + RADIO_KEY_SECURITY = RADIO_CHANNEL_SECURITY, + RADIO_KEY_SUPPLY = RADIO_CHANNEL_SUPPLY, + RADIO_KEY_SERVICE = RADIO_CHANNEL_SERVICE, + + // Faction + RADIO_KEY_SYNDICATE = RADIO_CHANNEL_SYNDICATE, + RADIO_KEY_CENTCOM = RADIO_CHANNEL_CENTCOM, + + // Admin + MODE_KEY_ADMIN = MODE_ADMIN, + MODE_KEY_DEADMIN = MODE_DEADMIN, + + // Misc + RADIO_KEY_AI_PRIVATE = RADIO_CHANNEL_AI_PRIVATE, // AI Upload channel + MODE_KEY_VOCALCORDS = MODE_VOCALCORDS, // vocal cords, used by Voice of God + + + //kinda localization -- rastaf0 + //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. + // Location + "ê" = MODE_R_HAND, + "ä" = MODE_L_HAND, + "ø" = MODE_INTERCOM, + + // Department + "ð" = MODE_DEPARTMENT, + "ñ" = RADIO_CHANNEL_COMMAND, + "ò" = RADIO_CHANNEL_SCIENCE, + "ü" = RADIO_CHANNEL_MEDICAL, + "ó" = RADIO_CHANNEL_ENGINEERING, + "û" = RADIO_CHANNEL_SECURITY, + "ã" = RADIO_CHANNEL_SUPPLY, + "ì" = RADIO_CHANNEL_SERVICE, + + // Faction + "å" = RADIO_CHANNEL_SYNDICATE, + "í" = RADIO_CHANNEL_CENTCOM, + + // Admin + "ç" = MODE_ADMIN, + "â" = MODE_ADMIN, + + // Misc + "ù" = RADIO_CHANNEL_AI_PRIVATE, + "÷" = MODE_VOCALCORDS +)) + +/mob/living/proc/Ellipsis(original_msg, chance = 50, keep_words) + if(chance <= 0) + return "..." + if(chance >= 100) + return original_msg + + var/list/words = splittext(original_msg," ") + var/list/new_words = list() + + var/new_msg = "" + + for(var/w in words) + if(prob(chance)) + new_words += "..." + if(!keep_words) + continue + new_words += w + + new_msg = jointext(new_words," ") + + return new_msg + +/mob/living/say(message, bubble_type,var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + var/static/list/crit_allowed_modes = list(MODE_WHISPER = TRUE, MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) + var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE) + var/talk_key = get_key(message) + + var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE, MODE_SING = TRUE) + + if(sanitize) + message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + if(!message || message == "") + return + + var/datum/saymode/saymode = SSradio.saymodes[talk_key] + var/message_mode = get_message_mode(message) + var/original_message = message + var/in_critical = InCritical() + + if(one_character_prefix[message_mode]) + message = copytext(message, 2) + else if(message_mode || saymode) + message = copytext(message, 3) + if(findtext(message, " ", 1, 2)) + message = copytext(message, 2) + + if(message_mode == MODE_ADMIN) + if(client) + client.cmd_admin_say(message) + return + + if(message_mode == MODE_DEADMIN) + if(client) + client.dsay(message) + return + + if(stat == DEAD) + say_dead(original_message) + return + + if(check_emote(original_message) || !can_speak_basic(original_message, ignore_spam)) + return + + if(in_critical) + if(!(crit_allowed_modes[message_mode])) + return + else if(stat == UNCONSCIOUS) + if(!(unconscious_allowed_modes[message_mode])) + return + + // language comma detection. + var/datum/language/message_language = get_message_language(message) + if(message_language) + // No, you cannot speak in xenocommon just because you know the key + if(can_speak_in_language(message_language)) + language = message_language + message = copytext(message, 3) + + // Trim the space if they said ",0 I LOVE LANGUAGES" + if(findtext(message, " ", 1, 2)) + message = copytext(message, 2) + + if(!language) + language = get_default_language() + + // Detection of language needs to be before inherent channels, because + // AIs use inherent channels for the holopad. Most inherent channels + // ignore the language argument however. + + if(saymode && !saymode.handle_message(src, message, language)) + return + + if(!can_speak_vocal(message)) + to_chat(src, "You find yourself unable to speak!") + return + + var/message_range = 7 + + var/succumbed = FALSE + + var/fullcrit = InFullCritical() + if((InCritical() && !fullcrit) || message_mode == MODE_WHISPER) + message_range = 1 + message_mode = MODE_WHISPER + src.log_talk(message, LOG_WHISPER) + if(fullcrit) + var/health_diff = round(-HEALTH_THRESHOLD_DEAD + health) + // If we cut our message short, abruptly end it with a-.. + var/message_len = length(message) + message = copytext(message, 1, health_diff) + "[message_len > health_diff ? "-.." : "..."]" + message = Ellipsis(message, 10, 1) + message_mode = MODE_WHISPER_CRIT + succumbed = TRUE + else + src.log_talk(message, LOG_SAY, forced_by=forced) + + message = treat_message(message) // unfortunately we still need this + var/sigreturn = SEND_SIGNAL(src, COMSIG_MOB_SAY, args) + if (sigreturn & COMPONENT_UPPERCASE_SPEECH) + message = uppertext(message) + if(!message) + return + + last_words = message + + spans |= speech_span + + if(language) + var/datum/language/L = GLOB.language_datum_instances[language] + spans |= L.spans + + if(message_mode == MODE_SING) + #if DM_VERSION < 513 + var/randomnote = "~" + #else + var/randomnote = pick("\u2669", "\u266A", "\u266B") + #endif + spans |= SPAN_SINGING + message = "[randomnote] [message] [randomnote]" + + var/radio_return = radio(message, message_mode, spans, language) + if(radio_return & ITALICS) + spans |= SPAN_ITALICS + if(radio_return & REDUCE_RANGE) + message_range = 1 + if(radio_return & NOPASS) + return 1 + + //No screams in space, unless you're next to someone. + var/turf/T = get_turf(src) + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 + + if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message + spans |= SPAN_ITALICS + + send_speech(message, message_range, src, bubble_type, spans, language, message_mode) + + if(succumbed) + succumb() + to_chat(src, compose_message(src, language, message, , spans, message_mode)) + + return 1 + +/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) + . = ..() + if(!client) + return + var/deaf_message + var/deaf_type + if(speaker != src) + if(!radio_freq) //These checks have to be seperate, else people talking on the radio will make "You can't hear yourself!" appear when hearing people over the radio while deaf. + deaf_message = "[speaker] [speaker.verb_say] something but you cannot hear [speaker.p_them()]." + deaf_type = 1 + else + deaf_message = "You can't hear yourself!" + deaf_type = 2 // Since you should be able to hear yourself without looking + // Create map text prior to modifying message for goonchat + if (client?.prefs.chat_on_map && stat != UNCONSCIOUS && (client.prefs.see_chat_non_mob || ismob(speaker)) && can_hear()) + create_chat_message(speaker, message_language, raw_message, spans, message_mode) + if (client?.prefs.radiosounds && stat != UNCONSCIOUS && can_hear() && radio_freq) + playsound_local(src,'sound/voice/radio.ogg', 30, 1) + + // Recompose message for AI hrefs, language incomprehension. + message = compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode) + message = hear_intercept(message, speaker, message_language, raw_message, radio_freq, spans, message_mode) + + show_message(message, MSG_AUDIBLE, deaf_message, deaf_type) + return message + +/mob/living/proc/hear_intercept(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) + return message + +/mob/living/send_speech(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode) + var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE) + var/eavesdrop_range = 0 + if(eavesdropping_modes[message_mode]) + eavesdrop_range = EAVESDROP_EXTRA_RANGE + var/list/listening = get_hearers_in_view(message_range+eavesdrop_range, source) + var/list/the_dead = list() + var/list/yellareas //CIT CHANGE - adds the ability for yelling to penetrate walls and echo throughout areas + if(say_test(message) == "2") //CIT CHANGE - ditto + yellareas = get_areas_in_range(message_range*0.5,src) //CIT CHANGE - ditto + for(var/_M in GLOB.player_list) + var/mob/M = _M + if(M.stat != DEAD) //not dead, not important + if(yellareas) //CIT CHANGE - see above. makes yelling penetrate walls + var/area/A = get_area(M) //CIT CHANGE - ditto + if(istype(A) && A.ambientsounds != SPACE && A in yellareas) //CIT CHANGE - ditto + listening |= M //CIT CHANGE - ditto + continue + if(!M.client || !client) //client is so that ghosts don't have to listen to mice + continue + if(get_dist(M, src) > 7 || M.z != z) //they're out of range of normal hearing + if(eavesdropping_modes[message_mode] && !(M.client.prefs.chat_toggles & CHAT_GHOSTWHISPER)) //they're whispering and we have hearing whispers at any range off + continue + if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off + continue + listening |= M + the_dead[M] = TRUE + + var/eavesdropping + var/eavesrendered + if(eavesdrop_range) + eavesdropping = stars(message) + eavesrendered = compose_message(src, message_language, eavesdropping, , spans, message_mode) + + var/rendered = compose_message(src, message_language, message, , spans, message_mode) + for(var/_AM in listening) + var/atom/movable/AM = _AM + if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM])) + AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode) + else + AM.Hear(rendered, src, message_language, message, , spans, message_mode) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message) + + //speech bubble + var/list/speech_bubble_recipients = list() + for(var/mob/M in listening) + if(M.client && !M.client.prefs.chat_on_map) + speech_bubble_recipients.Add(M.client) + var/image/I = image('icons/mob/talk.dmi', src, "[bubble_type][say_test(message)]", FLY_LAYER) + I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA + INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_recipients, 30) + +/mob/proc/binarycheck() + return FALSE + +/mob/living/can_speak(message) //For use outside of Say() + if(can_speak_basic(message) && can_speak_vocal(message)) + return 1 + +/mob/living/proc/can_speak_basic(message, ignore_spam = FALSE) //Check BEFORE handling of xeno and ling channels + if(client) + if(client.prefs.muted & MUTE_IC) + to_chat(src, "You cannot speak in IC (muted).") + return 0 + if(!ignore_spam && client.handle_spam_prevention(message,MUTE_IC)) + return 0 + + return 1 + +/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels + if(HAS_TRAIT(src, TRAIT_MUTE)) + return 0 + + if(is_muzzled()) + return 0 + + if(!IsVocal()) + return 0 + + return 1 + +/mob/living/proc/get_key(message) + var/key = copytext(message, 1, 2) + if(key in GLOB.department_radio_prefixes) + return lowertext(copytext(message, 2, 3)) + +/mob/living/proc/get_message_language(message) + if(copytext(message, 1, 2) == ",") + var/key = copytext(message, 2, 3) + for(var/ld in GLOB.all_languages) + var/datum/language/LD = ld + if(initial(LD.key) == key) + return LD + return null + +/mob/living/proc/treat_message(message) + + if(HAS_TRAIT(src, TRAIT_UNINTELLIGIBLE_SPEECH)) + message = unintelligize(message) + + if(derpspeech) + message = derpspeech(message, stuttering) + + if(stuttering) + message = stutter(message) + + if(slurring) + message = slur(message,slurring) + + if(cultslurring) + message = cultslur(message) + + message = capitalize(message) + + return message + +/mob/living/proc/radio(message, message_mode, list/spans, language) + var/obj/item/implant/radio/imp = locate() in implants + if(imp?.radio.on) + if(message_mode == MODE_HEADSET) + imp.radio.talk_into(src, message, , spans, language) + return ITALICS | REDUCE_RANGE + if(message_mode == MODE_DEPARTMENT || message_mode in GLOB.radiochannels) + imp.radio.talk_into(src, message, message_mode, spans, language) + return ITALICS | REDUCE_RANGE + + switch(message_mode) + if(MODE_WHISPER) + return ITALICS + if(MODE_R_HAND) + for(var/obj/item/r_hand in get_held_items_for_side("r", all = TRUE)) + if (r_hand) + return r_hand.talk_into(src, message, , spans, language) + return ITALICS | REDUCE_RANGE + if(MODE_L_HAND) + for(var/obj/item/l_hand in get_held_items_for_side("l", all = TRUE)) + if (l_hand) + return l_hand.talk_into(src, message, , spans, language) + return ITALICS | REDUCE_RANGE + + if(MODE_INTERCOM) + for (var/obj/item/radio/intercom/I in view(1, null)) + I.talk_into(src, message, , spans, language) + return ITALICS | REDUCE_RANGE + + if(MODE_BINARY) + return ITALICS | REDUCE_RANGE //Does not return 0 since this is only reached by humans, not borgs or AIs. + + return 0 + +/mob/living/say_mod(input, message_mode) + if(message_mode == MODE_WHISPER) + . = verb_whisper + else if(message_mode == MODE_WHISPER_CRIT) + . = "[verb_whisper] in [p_their()] last breath" + else if(stuttering) + . = "stammers" + else if(derpspeech) + . = "gibbers" + else if(message_mode == MODE_SING) + . = verb_sing + else + . = ..() + +/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced) + +/mob/living/get_language_holder(shadow=TRUE) + if(mind && shadow) + // Mind language holders shadow mob holders. + . = mind.get_language_holder() + if(.) + return . + + . = ..() diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 529c8a68..efc714f2 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1,1001 +1,1001 @@ -#define CALL_BOT_COOLDOWN 900 - -//Not sure why this is necessary... -/proc/AutoUpdateAI(obj/subject) - var/is_in_use = 0 - if (subject!=null) - for(var/A in GLOB.ai_list) - var/mob/living/silicon/ai/M = A - if ((M.client && M.machine == subject)) - is_in_use = 1 - subject.attack_ai(M) - return is_in_use - - -/mob/living/silicon/ai - name = "AI" - icon = 'icons/mob/ai.dmi' - icon_state = "ai" - move_resist = MOVE_FORCE_OVERPOWERING - density = TRUE - canmove = FALSE - status_flags = CANSTUN|CANPUSH - a_intent = INTENT_HARM //so we always get pushed instead of trying to swap - sight = SEE_TURFS | SEE_MOBS | SEE_OBJS - see_in_dark = 8 - hud_type = /datum/hud/ai - med_hud = DATA_HUD_MEDICAL_BASIC - sec_hud = DATA_HUD_SECURITY_BASIC - d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED - mob_size = MOB_SIZE_LARGE - var/list/network = list("ss13") - var/obj/machinery/camera/current - var/list/connected_robots = list() - var/aiRestorePowerRoutine = 0 - var/requires_power = POWER_REQ_ALL - var/can_be_carded = TRUE - var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list()) - var/viewalerts = 0 - var/icon/holo_icon//Default is assigned when AI is created. - var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. - var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not. - radiomod = ";" //AIs will, by default, state their laws on the internal radio. - var/obj/item/pda/ai/aiPDA - var/obj/item/multitool/aiMulti - var/mob/living/simple_animal/bot/Bot - var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed. - var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N - - //MALFUNCTION - var/datum/module_picker/malf_picker - var/list/datum/AI_Module/current_modules = list() - var/can_dominate_mechs = FALSE - var/shunted = FALSE //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead - - var/control_disabled = FALSE // Set to 1 to stop AI from interacting via Click() - var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite - var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown - - var/obj/machinery/power/apc/malfhack - var/explosive = FALSE //does the AI explode when it dies? - - var/mob/living/silicon/ai/parent - var/camera_light_on = FALSE - var/list/obj/machinery/camera/lit_cameras = list() - - var/datum/trackable/track = new - - var/last_paper_seen = null - var/can_shunt = TRUE - var/last_announcement = "" // For AI VOX, if enabled - var/turf/waypoint //Holds the turf of the currently selected waypoint. - var/waypoint_mode = FALSE //Waypoint mode is for selecting a turf via clicking. - var/call_bot_cooldown = 0 //time of next call bot command - var/apc_override = FALSE //hack for letting the AI use its APC even when visionless - var/nuking = FALSE - var/obj/machinery/doomsday_device/doomsday_device - - var/mob/camera/aiEye/eyeobj - var/sprint = 10 - var/cooldown = 0 - var/acceleration = 1 - - var/obj/structure/AIcore/deactivated/linked_core //For exosuit control - var/mob/living/silicon/robot/deployed_shell = null //For shell control - var/datum/action/innate/deploy_shell/deploy_action = new - var/datum/action/innate/deploy_last_shell/redeploy_action = new - var/chnotify = 0 - - - var/multicam_on = FALSE - var/obj/screen/movable/pic_in_pic/ai/master_multicam - var/list/multicam_screens = list() - var/list/all_eyes = list() - var/max_multicams = 6 - var/display_icon_override - -/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai) - . = ..() - if(!target_ai) //If there is no player/brain inside. - new/obj/structure/AIcore/deactivated(loc) //New empty terminal. - return INITIALIZE_HINT_QDEL //Delete AI. - - ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) - if(L && istype(L, /datum/ai_laws)) - laws = L - laws.associate(src) - else - make_laws() - - if(target_ai.mind) - target_ai.mind.transfer_to(src) - if(mind.special_role) - mind.store_memory("As an AI, you must obey your silicon laws above all else. Your objectives will consider you to be dead.") - to_chat(src, "You have been installed as an AI! ") - to_chat(src, "You must obey your silicon laws above all else. Your objectives will consider you to be dead.") - - to_chat(src, "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).") - to_chat(src, "To look at other parts of the station, click on yourself to get a camera menu.") - to_chat(src, "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.") - to_chat(src, "To use something, simply click on it.") - to_chat(src, "Use say :b to speak to your cyborgs through binary.") - to_chat(src, "For department channels, use the following say commands:") - to_chat(src, ":o - AI Private, :c - Command, :s - Security, :e - Engineering, :u - Supply, :v - Service, :m - Medical, :n - Science.") - show_laws() - to_chat(src, "These laws may be changed by other players, or by you being the traitor.") - - job = "AI" - - create_eye() - apply_pref_name("ai") - - set_core_display_icon() - - holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"default")) - - spark_system = new /datum/effect_system/spark_spread() - spark_system.set_up(5, 0, src) - spark_system.attach(src) - - verbs += /mob/living/silicon/ai/proc/show_laws_verb - - aiPDA = new/obj/item/pda/ai(src) - aiPDA.owner = name - aiPDA.ownjob = "AI" - aiPDA.name = name + " (" + aiPDA.ownjob + ")" - - aiMulti = new(src) - radio = new /obj/item/radio/headset/ai(src) - aicamera = new/obj/item/camera/siliconcam/ai_camera(src) - - deploy_action.Grant(src) - - if(isturf(loc)) - verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \ - /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ - /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, \ - /mob/living/silicon/ai/proc/set_automatic_say_channel) - - GLOB.ai_list += src - GLOB.shuttle_caller_list += src - - builtInCamera = new (src) - builtInCamera.network = list("ss13") - - -/mob/living/silicon/ai/Destroy() - GLOB.ai_list -= src - GLOB.shuttle_caller_list -= src - SSshuttle.autoEvac() - qdel(eyeobj) // No AI, no Eye - malfhack = null - - . = ..() - -/mob/living/silicon/ai/IgniteMob() - fire_stacks = 0 - . = ..() - -/mob/living/silicon/ai/proc/set_core_display_icon(input, client/C) - if(client && !C) - C = client - if(!input && !C?.prefs?.preferred_ai_core_display) - icon_state = initial(icon_state) - else - var/preferred_icon = input ? input : C.prefs.preferred_ai_core_display - icon_state = resolve_ai_icon(preferred_icon) - -/mob/living/silicon/ai/verb/pick_icon() - set category = "AI Commands" - set name = "Set AI Core Display" - if(incapacitated()) - return - var/list/iconstates = GLOB.ai_core_display_screens - for(var/option in iconstates) - if(option == "Random") - iconstates[option] = image(icon = src.icon, icon_state = "ai-random") - continue - iconstates[option] = image(icon = src.icon, icon_state = resolve_ai_icon(option)) - - view_core() - var/ai_core_icon = show_radial_menu(src, src , iconstates, radius = 42) - - if(!ai_core_icon || incapacitated()) - return - display_icon_override = ai_core_icon - set_core_display_icon(ai_core_icon) - -/mob/living/silicon/ai/Stat() - ..() - if(statpanel("Status")) - if(!stat) - stat(null, text("System integrity: [(health+100)/2]%")) - stat(null, text("Connected cyborgs: [connected_robots.len]")) - for(var/mob/living/silicon/robot/R in connected_robots) - var/robot_status = "Nominal" - if(R.shell) - robot_status = "AI SHELL" - else if(R.stat || !R.client) - robot_status = "OFFLINE" - else if(!R.cell || R.cell.charge <= 0) - robot_status = "DEPOWERED" - //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! - stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \ - Module: [R.designation] | Loc: [get_area_name(R, TRUE)] | Status: [robot_status]")) - stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells - else - stat(null, text("Systems nonfunctional")) - -/mob/living/silicon/ai/proc/ai_alerts() - var/dat = "Current Station Alerts\n" - dat += "Close

" - for (var/cat in alarms) - dat += text("[]
\n", cat) - var/list/L = alarms[cat] - if (L.len) - for (var/alarm in L) - var/list/alm = L[alarm] - var/area/A = alm[1] - var/C = alm[2] - var/list/sources = alm[3] - dat += "" - if (C && istype(C, /list)) - var/dat2 = "" - for (var/obj/machinery/camera/I in C) - dat2 += text("[][]", (dat2=="") ? "" : " | ", I.c_tag) - dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera") - else if (C && istype(C, /obj/machinery/camera)) - var/obj/machinery/camera/Ctmp = C - dat += text("-- [] ([])", A.name, Ctmp.c_tag) - else - dat += text("-- [] (No Camera)", A.name) - if (sources.len > 1) - dat += text("- [] sources", sources.len) - dat += "
\n" - else - dat += "-- All Systems Nominal
\n" - dat += "
\n" - - viewalerts = 1 - src << browse(dat, "window=aialerts&can_close=0") - -/mob/living/silicon/ai/proc/ai_roster() - var/dat = "Crew RosterCrew Roster:

" - - dat += GLOB.data_core.get_manifest() - dat += "" - - src << browse(dat, "window=airoster") - onclose(src, "airoster") - -/mob/living/silicon/ai/proc/ai_call_shuttle() - if(control_disabled) - to_chat(usr, "Wireless control is disabled!") - return - - var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text - - if(incapacitated()) - return - - if(trim(reason)) - SSshuttle.requestEvac(src, reason) - - // hack to display shuttle timer - if(!EMERGENCY_IDLE_OR_RECALLED) - var/obj/machinery/computer/communications/C = locate() in GLOB.machines - if(C) - C.post_status("shuttle") - -/mob/living/silicon/ai/can_interact_with(atom/A) - . = ..() - var/turf/ai = get_turf(src) - var/turf/target = get_turf(A) - if (.) - return - - if(!target) - return - - if ((ai.z != target.z) && !is_station_level(ai.z)) - return FALSE - - if (istype(loc, /obj/item/aicard)) - var/turf/T0 = get_turf(src) - var/turf/T1 = get_turf(A) - if (!T0 || ! T1) - return FALSE - return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range) - else - return GLOB.cameranet.checkTurfVis(get_turf(A)) - -/mob/living/silicon/ai/cancel_camera() - view_core() - -/mob/living/silicon/ai/verb/toggle_anchor() - set category = "AI Commands" - set name = "Toggle Floor Bolts" - if(!isturf(loc)) // if their location isn't a turf - return // stop - if(incapacitated()) - return - var/is_anchored = FALSE - if(move_resist == MOVE_FORCE_OVERPOWERING) - move_resist = MOVE_FORCE_NORMAL - else - is_anchored = TRUE - move_resist = MOVE_FORCE_OVERPOWERING - REMOVE_TRAIT(src, TRAIT_NO_TELEPORT, src) - ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) - - to_chat(src, "You are now [is_anchored ? "" : "un"]anchored.") - // the message in the [] will change depending whether or not the AI is anchored - -/mob/living/silicon/ai/update_canmove() //If the AI dies, mobs won't go through it anymore - return 0 - -/mob/living/silicon/ai/proc/ai_cancel_call() - set category = "Malfunction" - if(control_disabled) - to_chat(src, "Wireless control is disabled!") - return - SSshuttle.cancelEvac(src) - -/mob/living/silicon/ai/restrained(ignore_grab) - . = 0 - -/mob/living/silicon/ai/Topic(href, href_list) - if(usr != src || incapacitated()) - return - ..() - if (href_list["mach_close"]) - if (href_list["mach_close"] == "aialerts") - viewalerts = 0 - var/t1 = text("window=[]", href_list["mach_close"]) - unset_machine() - src << browse(null, t1) - if (href_list["switchcamera"]) - switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras - if (href_list["showalerts"]) - ai_alerts() -#ifdef AI_VOX - if(href_list["say_word"]) - play_vox_word(href_list["say_word"], null, src) - return -#endif - if(href_list["show_paper"]) - if(last_paper_seen) - src << browse(last_paper_seen, "window=show_paper") - //Carn: holopad requests - if(href_list["jumptoholopad"]) - var/obj/machinery/holopad/H = locate(href_list["jumptoholopad"]) - if(H) - H.attack_ai(src) //may as well recycle - else - to_chat(src, "Unable to locate the holopad.") - if(href_list["track"]) - var/string = href_list["track"] - trackable_mobs() - var/list/trackeable = list() - trackeable += track.humans + track.others - var/list/target = list() - for(var/I in trackeable) - var/mob/M = trackeable[I] - if(M.name == string) - target += M - if(name == string) - target += src - if(target.len) - ai_actual_track(pick(target)) - else - to_chat(src, "Target is not on or near any active cameras on the station.") - return - if(href_list["callbot"]) //Command a bot to move to a selected location. - if(call_bot_cooldown > world.time) - to_chat(src, "Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.") - return - Bot = locate(href_list["callbot"]) in GLOB.alive_mob_list - if(!Bot || Bot.remote_disabled || src.control_disabled) - return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off. - waypoint_mode = 1 - to_chat(src, "Set your waypoint by clicking on a valid location free of obstructions.") - return - if(href_list["interface"]) //Remotely connect to a bot! - Bot = locate(href_list["interface"]) in GLOB.alive_mob_list - if(!Bot || Bot.remote_disabled || src.control_disabled) - return - Bot.attack_ai(src) - if(href_list["botrefresh"]) //Refreshes the bot control panel. - botcall() - return - - if (href_list["ai_take_control"]) //Mech domination - var/obj/mecha/M = locate(href_list["ai_take_control"]) - if(controlled_mech) - to_chat(src, "You are already loaded into an onboard computer!") - return - if(!GLOB.cameranet.checkCameraVis(M)) - to_chat(src, "Exosuit is no longer near active cameras.") - return - if(!isturf(loc)) - to_chat(src, "You aren't in your core!") - return - if(M) - M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself. - - -/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C) - if(QDELETED(C)) - return FALSE - - if(!tracking) - cameraFollow = null - - if(QDELETED(eyeobj)) - view_core() - return - // ok, we're alive, camera is good and in our network... - eyeobj.setLoc(get_turf(C)) - return TRUE - -/mob/living/silicon/ai/proc/botcall() - set category = "AI Commands" - set name = "Access Robot Control" - set desc = "Wirelessly control various automatic robots." - if(incapacitated()) - return - - if(control_disabled) - to_chat(src, "Wireless control is disabled.") - return - var/turf/ai_current_turf = get_turf(src) - var/ai_Zlevel = ai_current_turf.z - var/d - d += "Query network status
" - d += "" - - for (Bot in GLOB.alive_mob_list) - if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! - var/bot_mode = Bot.get_mode() - d += "" - //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all. - d += "" - d += "" - d += "" - d += "" - d += "" - d = format_text(d) - - var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400) - popup.set_content(d) - popup.open() - -/mob/living/silicon/ai/proc/set_waypoint(atom/A) - var/turf/turf_check = get_turf(A) - //The target must be in view of a camera or near the core. - if(turf_check in range(get_turf(src))) - call_bot(turf_check) - else if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check)) - call_bot(turf_check) - else - to_chat(src, "Selected location is not visible.") - -/mob/living/silicon/ai/proc/call_bot(turf/waypoint) - - if(!Bot) - return - - if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. - to_chat(src, "Interface error. Unit is already in use.") - return - to_chat(src, "Sending command to bot...") - call_bot_cooldown = world.time + CALL_BOT_COOLDOWN - Bot.call_bot(src, waypoint) - call_bot_cooldown = 0 - - -/mob/living/silicon/ai/triggerAlarm(class, area/A, O, obj/alarmsource) - if(alarmsource.z != z) - return - var/list/L = alarms[class] - for (var/I in L) - if (I == A.name) - var/list/alarm = L[I] - var/list/sources = alarm[3] - if (!(alarmsource in sources)) - sources += alarmsource - return 1 - var/obj/machinery/camera/C = null - var/list/CL = null - if (O && istype(O, /list)) - CL = O - if (CL.len == 1) - C = CL[1] - else if (O && istype(O, /obj/machinery/camera)) - C = O - L[A.name] = list(A, (C) ? C : O, list(alarmsource)) - if (O) - if (C && C.can_use()) - queueAlarm("--- [class] alarm detected in [A.name]! ([C.c_tag])", class) - else if (CL && CL.len) - var/foo = 0 - var/dat2 = "" - for (var/obj/machinery/camera/I in CL) - dat2 += text("[][]", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit... - foo = 1 - queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class) - else - queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class) - else - queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class) - if (viewalerts) ai_alerts() - return 1 - -/mob/living/silicon/ai/cancelAlarm(class, area/A, obj/origin) - var/list/L = alarms[class] - var/cleared = 0 - for (var/I in L) - if (I == A.name) - var/list/alarm = L[I] - var/list/srcs = alarm[3] - if (origin in srcs) - srcs -= origin - if (srcs.len == 0) - cleared = 1 - L -= I - if (cleared) - queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0) - if (viewalerts) ai_alerts() - return !cleared - -//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm -//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead -//Addition by Mord_Sith to define AI's network change ability -/mob/living/silicon/ai/proc/ai_network_change() - set category = "AI Commands" - set name = "Jump To Network" - unset_machine() - cameraFollow = null - var/cameralist[0] - - if(incapacitated()) - return - - var/mob/living/silicon/ai/U = usr - - for (var/obj/machinery/camera/C in GLOB.cameranet.cameras) - var/list/tempnetwork = C.network - if(!(is_station_level(C.z) || is_mining_level(C.z) || ("ss13" in tempnetwork))) - continue - if(!C.can_use()) - continue - - tempnetwork.Remove("rd", "toxins", "prison") - if(tempnetwork.len) - for(var/i in C.network) - cameralist[i] = i - var/old_network = network - network = input(U, "Which network would you like to view?") as null|anything in cameralist - - if(!U.eyeobj) - U.view_core() - return - - if(isnull(network)) - network = old_network // If nothing is selected - else - for(var/obj/machinery/camera/C in GLOB.cameranet.cameras) - if(!C.can_use()) - continue - if(network in C.network) - U.eyeobj.setLoc(get_turf(C)) - break - to_chat(src, "Switched to the \"[uppertext(network)]\" camera network.") -//End of code by Mord_Sith - - -/mob/living/silicon/ai/proc/choose_modules() - set category = "Malfunction" - set name = "Choose Module" - - malf_picker.use(src) - -/mob/living/silicon/ai/proc/ai_statuschange() - set category = "AI Commands" - set name = "AI Status" - - if(incapacitated()) - return - var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Thinking", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow") - var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions - for (var/each in GLOB.ai_status_displays) //change status of displays - var/obj/machinery/status_display/ai/M = each - M.emotion = emote - M.update() - if (emote == "Friend Computer") - var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS) - - if(!frequency) - return - - var/datum/signal/status_signal = new(list("command" = "friendcomputer")) - frequency.post_signal(src, status_signal) - return - -//I am the icon meister. Bow fefore me. //>fefore -/mob/living/silicon/ai/proc/ai_hologram_change() - set name = "Change Hologram" - set desc = "Change the default hologram available to AI to something else." - set category = "AI Commands" - - if(incapacitated()) - return - var/input - switch(alert("Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?",,"Crew Member","Unique","Animal")) - if("Crew Member") - var/list/personnel_list = list() - - for(var/datum/data/record/t in GLOB.data_core.locked)//Look in data core locked. - personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image. - - if(personnel_list.len) - input = input("Select a crew member:") as null|anything in personnel_list - var/icon/character_icon = personnel_list[input] - if(character_icon) - qdel(holo_icon)//Clear old icon so we're not storing it in memory. - holo_icon = getHologramIcon(icon(character_icon)) - else - alert("No suitable records found. Aborting.") - - if("Animal") - var/list/icon_list = list( - "bear" = 'icons/mob/animal.dmi', - "carp" = 'icons/mob/animal.dmi', - "chicken" = 'icons/mob/animal.dmi', - "corgi" = 'icons/mob/pets.dmi', - "cow" = 'icons/mob/animal.dmi', - "crab" = 'icons/mob/animal.dmi', - "fox" = 'icons/mob/pets.dmi', - "goat" = 'icons/mob/animal.dmi', - "cat" = 'icons/mob/pets.dmi', - "cat2" = 'icons/mob/pets.dmi', - "poly" = 'icons/mob/animal.dmi', - "pug" = 'icons/mob/pets.dmi', - "spider" = 'icons/mob/animal.dmi' - ) - - input = input("Please select a hologram:") as null|anything in icon_list - if(input) - qdel(holo_icon) - switch(input) - if("poly") - holo_icon = getHologramIcon(icon(icon_list[input],"parrot_fly")) - if("chicken") - holo_icon = getHologramIcon(icon(icon_list[input],"chicken_brown")) - if("spider") - holo_icon = getHologramIcon(icon(icon_list[input],"guard")) - else - holo_icon = getHologramIcon(icon(icon_list[input], input)) - else - var/list/icon_list = list( - "default" = 'icons/mob/ai.dmi', - "floating face" = 'icons/mob/ai.dmi', - "xeno queen" = 'icons/mob/alien.dmi', - "horror" = 'icons/mob/ai.dmi' - ) - - input = input("Please select a hologram:") as null|anything in icon_list - if(input) - qdel(holo_icon) - switch(input) - if("xeno queen") - holo_icon = getHologramIcon(icon(icon_list[input],"alienq")) - else - holo_icon = getHologramIcon(icon(icon_list[input], input)) - return - -/mob/living/silicon/ai/proc/corereturn() - set category = "Malfunction" - set name = "Return to Main Core" - - var/obj/machinery/power/apc/apc = src.loc - if(!istype(apc)) - to_chat(src, "You are already in your Main Core.") - return - apc.malfvacate() - -/mob/living/silicon/ai/proc/toggle_camera_light() - camera_light_on = !camera_light_on - - if (!camera_light_on) - to_chat(src, "Camera lights deactivated.") - - for (var/obj/machinery/camera/C in lit_cameras) - C.set_light(0) - lit_cameras = list() - - return - - light_cameras() - - to_chat(src, "Camera lights activated.") - -//AI_CAMERA_LUMINOSITY - -/mob/living/silicon/ai/proc/light_cameras() - var/list/obj/machinery/camera/add = list() - var/list/obj/machinery/camera/remove = list() - var/list/obj/machinery/camera/visible = list() - for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks) - for (var/obj/machinery/camera/C in CC.cameras) - if (!C.can_use() || get_dist(C, eyeobj) > 7 || !C.internal_light) - continue - visible |= C - - add = visible - lit_cameras - remove = lit_cameras - visible - - for (var/obj/machinery/camera/C in remove) - lit_cameras -= C //Removed from list before turning off the light so that it doesn't check the AI looking away. - C.Togglelight(0) - for (var/obj/machinery/camera/C in add) - C.Togglelight(1) - lit_cameras |= C - -/mob/living/silicon/ai/proc/control_integrated_radio() - set name = "Transceiver Settings" - set desc = "Allows you to change settings of your radio." - set category = "AI Commands" - - if(incapacitated()) - return - - to_chat(src, "Accessing Subspace Transceiver control...") - if (radio) - radio.interact(src) - -/mob/living/silicon/ai/proc/set_syndie_radio() - if(radio) - radio.make_syndie() - -/mob/living/silicon/ai/proc/set_automatic_say_channel() - set name = "Set Auto Announce Mode" - set desc = "Modify the default radio setting for your automatic announcements." - set category = "AI Commands" - - if(incapacitated()) - return - set_autosay() - -/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) - if(!..()) - return - if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. - if(!can_be_carded) - to_chat(user, "Transfer failed.") - return - disconnect_shell() //If the AI is controlling a borg, force the player back to core! - if(!mind) - to_chat(user, "No intelligence patterns detected." ) - return - ShutOffDoomsdayDevice() - new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location. - ai_restore_power()//So the AI initially has power. - control_disabled = 1//Can't control things remotely if you're stuck in a card! - radio_enabled = 0 //No talking on the built-in radio for you either! - forceMove(card) - card.AI = src - to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") - to_chat(user, "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") - -/mob/living/silicon/ai/can_buckle() - return 0 - -/mob/living/silicon/ai/incapacitated() - if(aiRestorePowerRoutine) - return TRUE - return ..() - -/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) - if(control_disabled || incapacitated()) - to_chat(src, "You can't do that right now!") - return FALSE - if(be_close && !in_range(M, src)) - to_chat(src, "You are too far away!") - return FALSE - return can_see(M) //stop AIs from leaving windows open and using then after they lose vision - -/mob/living/silicon/ai/proc/can_see(atom/A) - if(isturf(loc)) //AI in core, check if on cameras - //get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera - //apc_override is needed here because AIs use their own APC when depowered - return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A))) || apc_override - //AI is carded/shunted - //view(src) returns nothing for carded/shunted AIs and they have X-ray vision so just use get_dist - var/list/viewscale = getviewsize(client.view) - return get_dist(src, A) <= max(viewscale[1]*0.5,viewscale[2]*0.5) - -/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) - var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mode) - var/start = "Relayed Speech: " - var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]" - var/hrefpart = "" - var/jobpart - - if (iscarbon(speaker)) - var/mob/living/carbon/S = speaker - if(S.job) - jobpart = "[S.job]" - else - jobpart = "Unknown" - - var/rendered = "[start][hrefpart][namepart] ([jobpart])[treated_message]" - if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker))) - create_chat_message(speaker, message_language, raw_message, spans, message_mode) - - show_message(rendered, 2) - -/mob/living/silicon/ai/fully_replace_character_name(oldname,newname) - ..() - if(oldname != real_name) - if(eyeobj) - eyeobj.name = "[newname] (AI Eye)" - - // Notify Cyborgs - for(var/mob/living/silicon/robot/Slave in connected_robots) - Slave.show_laws() - -/mob/living/silicon/ai/replace_identification_name(oldname,newname) - if(aiPDA) - aiPDA.owner = newname - aiPDA.name = newname + " (" + aiPDA.ownjob + ")" - - -/mob/living/silicon/ai/proc/add_malf_picker() - to_chat(src, "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.") - to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.") - view_core() //A BYOND bug requires you to be viewing your core before your verbs update - verbs += /mob/living/silicon/ai/proc/choose_modules - malf_picker = new /datum/module_picker - - -/mob/living/silicon/ai/reset_perspective(atom/A) - if(camera_light_on) - light_cameras() - if(istype(A, /obj/machinery/camera)) - current = A - if(client) - if(ismovableatom(A)) - if(A != GLOB.ai_camera_room_landmark) - end_multicam() - client.perspective = EYE_PERSPECTIVE - client.eye = A - else - end_multicam() - if(isturf(loc)) - if(eyeobj) - client.eye = eyeobj - client.perspective = EYE_PERSPECTIVE - else - client.eye = client.mob - client.perspective = MOB_PERSPECTIVE - else - client.perspective = EYE_PERSPECTIVE - client.eye = loc - update_sight() - if(client.eye != src) - var/atom/AT = client.eye - AT.get_remote_view_fullscreens(src) - else - clear_fullscreen("remote_view", 0) - -/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0) - . = ..() - if(.) //successfully ressuscitated from death - set_core_display_icon(display_icon_override) - -/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc) - malfhack = null - malfhacking = 0 - clear_alert("hackingapc") - - if(!istype(apc) || QDELETED(apc) || apc.stat & BROKEN) - to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") - playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) - else if(apc.aidisabled) - to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.") - playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) - else - malf_picker.processing_time += 10 - - apc.malfai = parent || src - apc.malfhack = TRUE - apc.locked = TRUE - apc.coverlocked = TRUE - - playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) - to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.") - apc.update_icon() - -/mob/living/silicon/ai/verb/deploy_to_shell(var/mob/living/silicon/robot/target) - set category = "AI Commands" - set name = "Deploy to Shell" - - if(incapacitated()) - return - if(control_disabled) - to_chat(src, "Wireless networking module is offline.") - return - - var/list/possible = list() - - for(var/borgie in GLOB.available_ai_shells) - var/mob/living/silicon/robot/R = borgie - if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai ||(R.connected_ai == src))) - possible += R - - if(!LAZYLEN(possible)) - to_chat(src, "No usable AI shell beacons detected.") - - if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid - target = input(src, "Which body to control?") as null|anything in possible - - if (!target || target.stat == DEAD || target.deployed || !(!target.connected_ai ||(target.connected_ai == src))) - return - - else if(mind) - soullink(/datum/soullink/sharedbody, src, target) - deployed_shell = target - target.deploy_init(src) - mind.transfer_to(target) - diag_hud_set_deployed() - -/datum/action/innate/deploy_shell - name = "Deploy to AI Shell" - desc = "Wirelessly control a specialized cyborg shell." - icon_icon = 'icons/mob/actions/actions_AI.dmi' - button_icon_state = "ai_shell" - -/datum/action/innate/deploy_shell/Trigger() - var/mob/living/silicon/ai/AI = owner - if(!AI) - return - AI.deploy_to_shell() - -/datum/action/innate/deploy_last_shell - name = "Reconnect to shell" - desc = "Reconnect to the most recently used AI shell." - icon_icon = 'icons/mob/actions/actions_AI.dmi' - button_icon_state = "ai_last_shell" - var/mob/living/silicon/robot/last_used_shell - -/datum/action/innate/deploy_last_shell/Trigger() - if(!owner) - return - if(last_used_shell) - var/mob/living/silicon/ai/AI = owner - AI.deploy_to_shell(last_used_shell) - else - Remove(owner) //If the last shell is blown, destroy it. - -/mob/living/silicon/ai/proc/disconnect_shell() - if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss. - to_chat(src, "Your remote connection has been reset!") - deployed_shell.undeploy() - diag_hud_set_deployed() - -/mob/living/silicon/ai/resist() - return - -/mob/living/silicon/ai/spawned/Initialize(mapload, datum/ai_laws/L, mob/target_ai) - . = ..() - if(!target_ai) - target_ai = src //cheat! just give... ourselves as the spawned AI, because that's technically correct - -/mob/living/silicon/ai/proc/camera_visibility(mob/camera/aiEye/moved_eye) - GLOB.cameranet.visibility(moved_eye, client, all_eyes, USE_STATIC_OPAQUE) - -/mob/living/silicon/ai/forceMove(atom/destination) - . = ..() - if(.) - end_multicam() +#define CALL_BOT_COOLDOWN 900 + +//Not sure why this is necessary... +/proc/AutoUpdateAI(obj/subject) + var/is_in_use = 0 + if (subject!=null) + for(var/A in GLOB.ai_list) + var/mob/living/silicon/ai/M = A + if ((M.client && M.machine == subject)) + is_in_use = 1 + subject.attack_ai(M) + return is_in_use + + +/mob/living/silicon/ai + name = "AI" + icon = 'icons/mob/ai.dmi' + icon_state = "ai" + move_resist = MOVE_FORCE_OVERPOWERING + density = TRUE + canmove = FALSE + status_flags = CANSTUN|CANPUSH + a_intent = INTENT_HARM //so we always get pushed instead of trying to swap + sight = SEE_TURFS | SEE_MOBS | SEE_OBJS + see_in_dark = 8 + hud_type = /datum/hud/ai + med_hud = DATA_HUD_MEDICAL_BASIC + sec_hud = DATA_HUD_SECURITY_BASIC + d_hud = DATA_HUD_DIAGNOSTIC_ADVANCED + mob_size = MOB_SIZE_LARGE + var/list/network = list("ss13") + var/obj/machinery/camera/current + var/list/connected_robots = list() + var/aiRestorePowerRoutine = 0 + var/requires_power = POWER_REQ_ALL + var/can_be_carded = TRUE + var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list()) + var/viewalerts = 0 + var/icon/holo_icon//Default is assigned when AI is created. + var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. + var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not. + radiomod = ";" //AIs will, by default, state their laws on the internal radio. + var/obj/item/pda/ai/aiPDA + var/obj/item/multitool/aiMulti + var/mob/living/simple_animal/bot/Bot + var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed. + var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N + + //MALFUNCTION + var/datum/module_picker/malf_picker + var/list/datum/AI_Module/current_modules = list() + var/can_dominate_mechs = FALSE + var/shunted = FALSE //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead + + var/control_disabled = FALSE // Set to 1 to stop AI from interacting via Click() + var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite + var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown + + var/obj/machinery/power/apc/malfhack + var/explosive = FALSE //does the AI explode when it dies? + + var/mob/living/silicon/ai/parent + var/camera_light_on = FALSE + var/list/obj/machinery/camera/lit_cameras = list() + + var/datum/trackable/track = new + + var/last_paper_seen = null + var/can_shunt = TRUE + var/last_announcement = "" // For AI VOX, if enabled + var/turf/waypoint //Holds the turf of the currently selected waypoint. + var/waypoint_mode = FALSE //Waypoint mode is for selecting a turf via clicking. + var/call_bot_cooldown = 0 //time of next call bot command + var/apc_override = FALSE //hack for letting the AI use its APC even when visionless + var/nuking = FALSE + var/obj/machinery/doomsday_device/doomsday_device + + var/mob/camera/aiEye/eyeobj + var/sprint = 10 + var/cooldown = 0 + var/acceleration = 1 + + var/obj/structure/AIcore/deactivated/linked_core //For exosuit control + var/mob/living/silicon/robot/deployed_shell = null //For shell control + var/datum/action/innate/deploy_shell/deploy_action = new + var/datum/action/innate/deploy_last_shell/redeploy_action = new + var/chnotify = 0 + + + var/multicam_on = FALSE + var/obj/screen/movable/pic_in_pic/ai/master_multicam + var/list/multicam_screens = list() + var/list/all_eyes = list() + var/max_multicams = 6 + var/display_icon_override + +/mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai) + . = ..() + if(!target_ai) //If there is no player/brain inside. + new/obj/structure/AIcore/deactivated(loc) //New empty terminal. + return INITIALIZE_HINT_QDEL //Delete AI. + + ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) + if(L && istype(L, /datum/ai_laws)) + laws = L + laws.associate(src) + else + make_laws() + + if(target_ai.mind) + target_ai.mind.transfer_to(src) + if(mind.special_role) + mind.store_memory("As an AI, you must obey your silicon laws above all else. Your objectives will consider you to be dead.") + to_chat(src, "You have been installed as an AI! ") + to_chat(src, "You must obey your silicon laws above all else. Your objectives will consider you to be dead.") + + to_chat(src, "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).") + to_chat(src, "To look at other parts of the station, click on yourself to get a camera menu.") + to_chat(src, "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.") + to_chat(src, "To use something, simply click on it.") + to_chat(src, "Use say :b to speak to your cyborgs through binary.") + to_chat(src, "For department channels, use the following say commands:") + to_chat(src, ":o - AI Private, :c - Command, :s - Security, :e - Engineering, :u - Supply, :v - Service, :m - Medical, :n - Science.") + show_laws() + to_chat(src, "These laws may be changed by other players, or by you being the traitor.") + + job = "AI" + + create_eye() + apply_pref_name("ai") + + set_core_display_icon() + + holo_icon = getHologramIcon(icon('icons/mob/ai.dmi',"default")) + + spark_system = new /datum/effect_system/spark_spread() + spark_system.set_up(5, 0, src) + spark_system.attach(src) + + verbs += /mob/living/silicon/ai/proc/show_laws_verb + + aiPDA = new/obj/item/pda/ai(src) + aiPDA.owner = name + aiPDA.ownjob = "AI" + aiPDA.name = name + " (" + aiPDA.ownjob + ")" + + aiMulti = new(src) + radio = new /obj/item/radio/headset/ai(src) + aicamera = new/obj/item/camera/siliconcam/ai_camera(src) + + deploy_action.Grant(src) + + if(isturf(loc)) + verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \ + /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ + /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, \ + /mob/living/silicon/ai/proc/set_automatic_say_channel) + + GLOB.ai_list += src + GLOB.shuttle_caller_list += src + + builtInCamera = new (src) + builtInCamera.network = list("ss13") + + +/mob/living/silicon/ai/Destroy() + GLOB.ai_list -= src + GLOB.shuttle_caller_list -= src + SSshuttle.autoEvac() + qdel(eyeobj) // No AI, no Eye + malfhack = null + + . = ..() + +/mob/living/silicon/ai/IgniteMob() + fire_stacks = 0 + . = ..() + +/mob/living/silicon/ai/proc/set_core_display_icon(input, client/C) + if(client && !C) + C = client + if(!input && !C?.prefs?.preferred_ai_core_display) + icon_state = initial(icon_state) + else + var/preferred_icon = input ? input : C.prefs.preferred_ai_core_display + icon_state = resolve_ai_icon(preferred_icon) + +/mob/living/silicon/ai/verb/pick_icon() + set category = "AI Commands" + set name = "Set AI Core Display" + if(incapacitated()) + return + var/list/iconstates = GLOB.ai_core_display_screens + for(var/option in iconstates) + if(option == "Random") + iconstates[option] = image(icon = src.icon, icon_state = "ai-random") + continue + iconstates[option] = image(icon = src.icon, icon_state = resolve_ai_icon(option)) + + view_core() + var/ai_core_icon = show_radial_menu(src, src , iconstates, radius = 42) + + if(!ai_core_icon || incapacitated()) + return + display_icon_override = ai_core_icon + set_core_display_icon(ai_core_icon) + +/mob/living/silicon/ai/Stat() + ..() + if(statpanel("Status")) + if(!stat) + stat(null, text("System integrity: [(health+100)/2]%")) + stat(null, text("Connected cyborgs: [connected_robots.len]")) + for(var/mob/living/silicon/robot/R in connected_robots) + var/robot_status = "Nominal" + if(R.shell) + robot_status = "AI SHELL" + else if(R.stat || !R.client) + robot_status = "OFFLINE" + else if(!R.cell || R.cell.charge <= 0) + robot_status = "DEPOWERED" + //Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies! + stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \ + Module: [R.designation] | Loc: [get_area_name(R, TRUE)] | Status: [robot_status]")) + stat(null, text("AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]")) //Count of total AI shells + else + stat(null, text("Systems nonfunctional")) + +/mob/living/silicon/ai/proc/ai_alerts() + var/dat = "Current Station Alerts\n" + dat += "Close

" + for (var/cat in alarms) + dat += text("[]
\n", cat) + var/list/L = alarms[cat] + if (L.len) + for (var/alarm in L) + var/list/alm = L[alarm] + var/area/A = alm[1] + var/C = alm[2] + var/list/sources = alm[3] + dat += "" + if (C && istype(C, /list)) + var/dat2 = "" + for (var/obj/machinery/camera/I in C) + dat2 += text("[][]", (dat2=="") ? "" : " | ", I.c_tag) + dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera") + else if (C && istype(C, /obj/machinery/camera)) + var/obj/machinery/camera/Ctmp = C + dat += text("-- [] ([])", A.name, Ctmp.c_tag) + else + dat += text("-- [] (No Camera)", A.name) + if (sources.len > 1) + dat += text("- [] sources", sources.len) + dat += "
\n" + else + dat += "-- All Systems Nominal
\n" + dat += "
\n" + + viewalerts = 1 + src << browse(dat, "window=aialerts&can_close=0") + +/mob/living/silicon/ai/proc/ai_roster() + var/dat = "Crew RosterCrew Roster:

" + + dat += GLOB.data_core.get_manifest() + dat += "" + + src << browse(dat, "window=airoster") + onclose(src, "airoster") + +/mob/living/silicon/ai/proc/ai_call_shuttle() + if(control_disabled) + to_chat(usr, "Wireless control is disabled!") + return + + var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text + + if(incapacitated()) + return + + if(trim(reason)) + SSshuttle.requestEvac(src, reason) + + // hack to display shuttle timer + if(!EMERGENCY_IDLE_OR_RECALLED) + var/obj/machinery/computer/communications/C = locate() in GLOB.machines + if(C) + C.post_status("shuttle") + +/mob/living/silicon/ai/can_interact_with(atom/A) + . = ..() + var/turf/ai = get_turf(src) + var/turf/target = get_turf(A) + if (.) + return + + if(!target) + return + + if ((ai.z != target.z) && !is_station_level(ai.z)) + return FALSE + + if (istype(loc, /obj/item/aicard)) + var/turf/T0 = get_turf(src) + var/turf/T1 = get_turf(A) + if (!T0 || ! T1) + return FALSE + return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range) + else + return GLOB.cameranet.checkTurfVis(get_turf(A)) + +/mob/living/silicon/ai/cancel_camera() + view_core() + +/mob/living/silicon/ai/verb/toggle_anchor() + set category = "AI Commands" + set name = "Toggle Floor Bolts" + if(!isturf(loc)) // if their location isn't a turf + return // stop + if(incapacitated()) + return + var/is_anchored = FALSE + if(move_resist == MOVE_FORCE_OVERPOWERING) + move_resist = MOVE_FORCE_NORMAL + else + is_anchored = TRUE + move_resist = MOVE_FORCE_OVERPOWERING + REMOVE_TRAIT(src, TRAIT_NO_TELEPORT, src) + ADD_TRAIT(src, TRAIT_NO_TELEPORT, src) + + to_chat(src, "You are now [is_anchored ? "" : "un"]anchored.") + // the message in the [] will change depending whether or not the AI is anchored + +/mob/living/silicon/ai/update_canmove() //If the AI dies, mobs won't go through it anymore + return 0 + +/mob/living/silicon/ai/proc/ai_cancel_call() + set category = "Malfunction" + if(control_disabled) + to_chat(src, "Wireless control is disabled!") + return + SSshuttle.cancelEvac(src) + +/mob/living/silicon/ai/restrained(ignore_grab) + . = 0 + +/mob/living/silicon/ai/Topic(href, href_list) + if(usr != src || incapacitated()) + return + ..() + if (href_list["mach_close"]) + if (href_list["mach_close"] == "aialerts") + viewalerts = 0 + var/t1 = text("window=[]", href_list["mach_close"]) + unset_machine() + src << browse(null, t1) + if (href_list["switchcamera"]) + switchCamera(locate(href_list["switchcamera"])) in GLOB.cameranet.cameras + if (href_list["showalerts"]) + ai_alerts() +#ifdef AI_VOX + if(href_list["say_word"]) + play_vox_word(href_list["say_word"], null, src) + return +#endif + if(href_list["show_paper"]) + if(last_paper_seen) + src << browse(last_paper_seen, "window=show_paper") + //Carn: holopad requests + if(href_list["jumptoholopad"]) + var/obj/machinery/holopad/H = locate(href_list["jumptoholopad"]) + if(H) + H.attack_ai(src) //may as well recycle + else + to_chat(src, "Unable to locate the holopad.") + if(href_list["track"]) + var/string = href_list["track"] + trackable_mobs() + var/list/trackeable = list() + trackeable += track.humans + track.others + var/list/target = list() + for(var/I in trackeable) + var/mob/M = trackeable[I] + if(M.name == string) + target += M + if(name == string) + target += src + if(target.len) + ai_actual_track(pick(target)) + else + to_chat(src, "Target is not on or near any active cameras on the station.") + return + if(href_list["callbot"]) //Command a bot to move to a selected location. + if(call_bot_cooldown > world.time) + to_chat(src, "Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.") + return + Bot = locate(href_list["callbot"]) in GLOB.alive_mob_list + if(!Bot || Bot.remote_disabled || src.control_disabled) + return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off. + waypoint_mode = 1 + to_chat(src, "Set your waypoint by clicking on a valid location free of obstructions.") + return + if(href_list["interface"]) //Remotely connect to a bot! + Bot = locate(href_list["interface"]) in GLOB.alive_mob_list + if(!Bot || Bot.remote_disabled || src.control_disabled) + return + Bot.attack_ai(src) + if(href_list["botrefresh"]) //Refreshes the bot control panel. + botcall() + return + + if (href_list["ai_take_control"]) //Mech domination + var/obj/mecha/M = locate(href_list["ai_take_control"]) + if(controlled_mech) + to_chat(src, "You are already loaded into an onboard computer!") + return + if(!GLOB.cameranet.checkCameraVis(M)) + to_chat(src, "Exosuit is no longer near active cameras.") + return + if(!isturf(loc)) + to_chat(src, "You aren't in your core!") + return + if(M) + M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself. + + +/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C) + if(QDELETED(C)) + return FALSE + + if(!tracking) + cameraFollow = null + + if(QDELETED(eyeobj)) + view_core() + return + // ok, we're alive, camera is good and in our network... + eyeobj.setLoc(get_turf(C)) + return TRUE + +/mob/living/silicon/ai/proc/botcall() + set category = "AI Commands" + set name = "Access Robot Control" + set desc = "Wirelessly control various automatic robots." + if(incapacitated()) + return + + if(control_disabled) + to_chat(src, "Wireless control is disabled.") + return + var/turf/ai_current_turf = get_turf(src) + var/ai_Zlevel = ai_current_turf.z + var/d + d += "Query network status
" + d += "

Name

Status

Location

Control

[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])[bot_mode][get_area_name(Bot, TRUE)]InterfaceCall
" + + for (Bot in GLOB.alive_mob_list) + if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected! + var/bot_mode = Bot.get_mode() + d += "" + //If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all. + d += "" + d += "" + d += "" + d += "" + d += "" + d = format_text(d) + + var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400) + popup.set_content(d) + popup.open() + +/mob/living/silicon/ai/proc/set_waypoint(atom/A) + var/turf/turf_check = get_turf(A) + //The target must be in view of a camera or near the core. + if(turf_check in range(get_turf(src))) + call_bot(turf_check) + else if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check)) + call_bot(turf_check) + else + to_chat(src, "Selected location is not visible.") + +/mob/living/silicon/ai/proc/call_bot(turf/waypoint) + + if(!Bot) + return + + if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot. + to_chat(src, "Interface error. Unit is already in use.") + return + to_chat(src, "Sending command to bot...") + call_bot_cooldown = world.time + CALL_BOT_COOLDOWN + Bot.call_bot(src, waypoint) + call_bot_cooldown = 0 + + +/mob/living/silicon/ai/triggerAlarm(class, area/A, O, obj/alarmsource) + if(alarmsource.z != z) + return + var/list/L = alarms[class] + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/sources = alarm[3] + if (!(alarmsource in sources)) + sources += alarmsource + return 1 + var/obj/machinery/camera/C = null + var/list/CL = null + if (O && istype(O, /list)) + CL = O + if (CL.len == 1) + C = CL[1] + else if (O && istype(O, /obj/machinery/camera)) + C = O + L[A.name] = list(A, (C) ? C : O, list(alarmsource)) + if (O) + if (C && C.can_use()) + queueAlarm("--- [class] alarm detected in [A.name]! ([C.c_tag])", class) + else if (CL && CL.len) + var/foo = 0 + var/dat2 = "" + for (var/obj/machinery/camera/I in CL) + dat2 += text("[][]", (!foo) ? "" : " | ", I.c_tag) //I'm not fixing this shit... + foo = 1 + queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class) + else + queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class) + else + queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class) + if (viewalerts) ai_alerts() + return 1 + +/mob/living/silicon/ai/cancelAlarm(class, area/A, obj/origin) + var/list/L = alarms[class] + var/cleared = 0 + for (var/I in L) + if (I == A.name) + var/list/alarm = L[I] + var/list/srcs = alarm[3] + if (origin in srcs) + srcs -= origin + if (srcs.len == 0) + cleared = 1 + L -= I + if (cleared) + queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0) + if (viewalerts) ai_alerts() + return !cleared + +//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm +//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead +//Addition by Mord_Sith to define AI's network change ability +/mob/living/silicon/ai/proc/ai_network_change() + set category = "AI Commands" + set name = "Jump To Network" + unset_machine() + cameraFollow = null + var/cameralist[0] + + if(incapacitated()) + return + + var/mob/living/silicon/ai/U = usr + + for (var/obj/machinery/camera/C in GLOB.cameranet.cameras) + var/list/tempnetwork = C.network + if(!(is_station_level(C.z) || is_mining_level(C.z) || ("ss13" in tempnetwork))) + continue + if(!C.can_use()) + continue + + tempnetwork.Remove("rd", "toxins", "prison") + if(tempnetwork.len) + for(var/i in C.network) + cameralist[i] = i + var/old_network = network + network = input(U, "Which network would you like to view?") as null|anything in cameralist + + if(!U.eyeobj) + U.view_core() + return + + if(isnull(network)) + network = old_network // If nothing is selected + else + for(var/obj/machinery/camera/C in GLOB.cameranet.cameras) + if(!C.can_use()) + continue + if(network in C.network) + U.eyeobj.setLoc(get_turf(C)) + break + to_chat(src, "Switched to the \"[uppertext(network)]\" camera network.") +//End of code by Mord_Sith + + +/mob/living/silicon/ai/proc/choose_modules() + set category = "Malfunction" + set name = "Choose Module" + + malf_picker.use(src) + +/mob/living/silicon/ai/proc/ai_statuschange() + set category = "AI Commands" + set name = "AI Status" + + if(incapacitated()) + return + var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Thinking", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow") + var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions + for (var/each in GLOB.ai_status_displays) //change status of displays + var/obj/machinery/status_display/ai/M = each + M.emotion = emote + M.update() + if (emote == "Friend Computer") + var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS) + + if(!frequency) + return + + var/datum/signal/status_signal = new(list("command" = "friendcomputer")) + frequency.post_signal(src, status_signal) + return + +//I am the icon meister. Bow fefore me. //>fefore +/mob/living/silicon/ai/proc/ai_hologram_change() + set name = "Change Hologram" + set desc = "Change the default hologram available to AI to something else." + set category = "AI Commands" + + if(incapacitated()) + return + var/input + switch(alert("Would you like to select a hologram based on a crew member, an animal, or switch to a unique avatar?",,"Crew Member","Unique","Animal")) + if("Crew Member") + var/list/personnel_list = list() + + for(var/datum/data/record/t in GLOB.data_core.locked)//Look in data core locked. + personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image. + + if(personnel_list.len) + input = input("Select a crew member:") as null|anything in personnel_list + var/icon/character_icon = personnel_list[input] + if(character_icon) + qdel(holo_icon)//Clear old icon so we're not storing it in memory. + holo_icon = getHologramIcon(icon(character_icon)) + else + alert("No suitable records found. Aborting.") + + if("Animal") + var/list/icon_list = list( + "bear" = 'icons/mob/animal.dmi', + "carp" = 'icons/mob/animal.dmi', + "chicken" = 'icons/mob/animal.dmi', + "corgi" = 'icons/mob/pets.dmi', + "cow" = 'icons/mob/animal.dmi', + "crab" = 'icons/mob/animal.dmi', + "fox" = 'icons/mob/pets.dmi', + "goat" = 'icons/mob/animal.dmi', + "cat" = 'icons/mob/pets.dmi', + "cat2" = 'icons/mob/pets.dmi', + "poly" = 'icons/mob/animal.dmi', + "pug" = 'icons/mob/pets.dmi', + "spider" = 'icons/mob/animal.dmi' + ) + + input = input("Please select a hologram:") as null|anything in icon_list + if(input) + qdel(holo_icon) + switch(input) + if("poly") + holo_icon = getHologramIcon(icon(icon_list[input],"parrot_fly")) + if("chicken") + holo_icon = getHologramIcon(icon(icon_list[input],"chicken_brown")) + if("spider") + holo_icon = getHologramIcon(icon(icon_list[input],"guard")) + else + holo_icon = getHologramIcon(icon(icon_list[input], input)) + else + var/list/icon_list = list( + "default" = 'icons/mob/ai.dmi', + "floating face" = 'icons/mob/ai.dmi', + "xeno queen" = 'icons/mob/alien.dmi', + "horror" = 'icons/mob/ai.dmi' + ) + + input = input("Please select a hologram:") as null|anything in icon_list + if(input) + qdel(holo_icon) + switch(input) + if("xeno queen") + holo_icon = getHologramIcon(icon(icon_list[input],"alienq")) + else + holo_icon = getHologramIcon(icon(icon_list[input], input)) + return + +/mob/living/silicon/ai/proc/corereturn() + set category = "Malfunction" + set name = "Return to Main Core" + + var/obj/machinery/power/apc/apc = src.loc + if(!istype(apc)) + to_chat(src, "You are already in your Main Core.") + return + apc.malfvacate() + +/mob/living/silicon/ai/proc/toggle_camera_light() + camera_light_on = !camera_light_on + + if (!camera_light_on) + to_chat(src, "Camera lights deactivated.") + + for (var/obj/machinery/camera/C in lit_cameras) + C.set_light(0) + lit_cameras = list() + + return + + light_cameras() + + to_chat(src, "Camera lights activated.") + +//AI_CAMERA_LUMINOSITY + +/mob/living/silicon/ai/proc/light_cameras() + var/list/obj/machinery/camera/add = list() + var/list/obj/machinery/camera/remove = list() + var/list/obj/machinery/camera/visible = list() + for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks) + for (var/obj/machinery/camera/C in CC.cameras) + if (!C.can_use() || get_dist(C, eyeobj) > 7 || !C.internal_light) + continue + visible |= C + + add = visible - lit_cameras + remove = lit_cameras - visible + + for (var/obj/machinery/camera/C in remove) + lit_cameras -= C //Removed from list before turning off the light so that it doesn't check the AI looking away. + C.Togglelight(0) + for (var/obj/machinery/camera/C in add) + C.Togglelight(1) + lit_cameras |= C + +/mob/living/silicon/ai/proc/control_integrated_radio() + set name = "Transceiver Settings" + set desc = "Allows you to change settings of your radio." + set category = "AI Commands" + + if(incapacitated()) + return + + to_chat(src, "Accessing Subspace Transceiver control...") + if (radio) + radio.interact(src) + +/mob/living/silicon/ai/proc/set_syndie_radio() + if(radio) + radio.make_syndie() + +/mob/living/silicon/ai/proc/set_automatic_say_channel() + set name = "Set Auto Announce Mode" + set desc = "Modify the default radio setting for your automatic announcements." + set category = "AI Commands" + + if(incapacitated()) + return + set_autosay() + +/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) + if(!..()) + return + if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card. + if(!can_be_carded) + to_chat(user, "Transfer failed.") + return + disconnect_shell() //If the AI is controlling a borg, force the player back to core! + if(!mind) + to_chat(user, "No intelligence patterns detected." ) + return + ShutOffDoomsdayDevice() + new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location. + ai_restore_power()//So the AI initially has power. + control_disabled = 1//Can't control things remotely if you're stuck in a card! + radio_enabled = 0 //No talking on the built-in radio for you either! + forceMove(card) + card.AI = src + to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.") + to_chat(user, "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.") + +/mob/living/silicon/ai/can_buckle() + return 0 + +/mob/living/silicon/ai/incapacitated() + if(aiRestorePowerRoutine) + return TRUE + return ..() + +/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) + if(control_disabled || incapacitated()) + to_chat(src, "You can't do that right now!") + return FALSE + if(be_close && !in_range(M, src)) + to_chat(src, "You are too far away!") + return FALSE + return can_see(M) //stop AIs from leaving windows open and using then after they lose vision + +/mob/living/silicon/ai/proc/can_see(atom/A) + if(isturf(loc)) //AI in core, check if on cameras + //get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera + //apc_override is needed here because AIs use their own APC when depowered + return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A))) || apc_override + //AI is carded/shunted + //view(src) returns nothing for carded/shunted AIs and they have X-ray vision so just use get_dist + var/list/viewscale = getviewsize(client.view) + return get_dist(src, A) <= max(viewscale[1]*0.5,viewscale[2]*0.5) + +/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode) + var/treated_message = lang_treat(speaker, message_language, raw_message, spans, message_mode) + var/start = "Relayed Speech: " + var/namepart = "[speaker.GetVoice()][speaker.get_alt_name()]" + var/hrefpart = "" + var/jobpart + + if (iscarbon(speaker)) + var/mob/living/carbon/S = speaker + if(S.job) + jobpart = "[S.job]" + else + jobpart = "Unknown" + + var/rendered = "[start][hrefpart][namepart] ([jobpart])[treated_message]" + if (client?.prefs.chat_on_map && (client.prefs.see_chat_non_mob || ismob(speaker))) + create_chat_message(speaker, message_language, raw_message, spans, message_mode) + + show_message(rendered, MSG_AUDIBLE) + +/mob/living/silicon/ai/fully_replace_character_name(oldname,newname) + ..() + if(oldname != real_name) + if(eyeobj) + eyeobj.name = "[newname] (AI Eye)" + + // Notify Cyborgs + for(var/mob/living/silicon/robot/Slave in connected_robots) + Slave.show_laws() + +/mob/living/silicon/ai/replace_identification_name(oldname,newname) + if(aiPDA) + aiPDA.owner = newname + aiPDA.name = newname + " (" + aiPDA.ownjob + ")" + + +/mob/living/silicon/ai/proc/add_malf_picker() + to_chat(src, "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.") + to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.") + view_core() //A BYOND bug requires you to be viewing your core before your verbs update + verbs += /mob/living/silicon/ai/proc/choose_modules + malf_picker = new /datum/module_picker + + +/mob/living/silicon/ai/reset_perspective(atom/A) + if(camera_light_on) + light_cameras() + if(istype(A, /obj/machinery/camera)) + current = A + if(client) + if(ismovableatom(A)) + if(A != GLOB.ai_camera_room_landmark) + end_multicam() + client.perspective = EYE_PERSPECTIVE + client.eye = A + else + end_multicam() + if(isturf(loc)) + if(eyeobj) + client.eye = eyeobj + client.perspective = EYE_PERSPECTIVE + else + client.eye = client.mob + client.perspective = MOB_PERSPECTIVE + else + client.perspective = EYE_PERSPECTIVE + client.eye = loc + update_sight() + if(client.eye != src) + var/atom/AT = client.eye + AT.get_remote_view_fullscreens(src) + else + clear_fullscreen("remote_view", 0) + +/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0) + . = ..() + if(.) //successfully ressuscitated from death + set_core_display_icon(display_icon_override) + +/mob/living/silicon/ai/proc/malfhacked(obj/machinery/power/apc/apc) + malfhack = null + malfhacking = 0 + clear_alert("hackingapc") + + if(!istype(apc) || QDELETED(apc) || apc.stat & BROKEN) + to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + else if(apc.aidisabled) + to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.") + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) + else + malf_picker.processing_time += 10 + + apc.malfai = parent || src + apc.malfhack = TRUE + apc.locked = TRUE + apc.coverlocked = TRUE + + playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) + to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.") + apc.update_icon() + +/mob/living/silicon/ai/verb/deploy_to_shell(var/mob/living/silicon/robot/target) + set category = "AI Commands" + set name = "Deploy to Shell" + + if(incapacitated()) + return + if(control_disabled) + to_chat(src, "Wireless networking module is offline.") + return + + var/list/possible = list() + + for(var/borgie in GLOB.available_ai_shells) + var/mob/living/silicon/robot/R = borgie + if(R.shell && !R.deployed && (R.stat != DEAD) && (!R.connected_ai ||(R.connected_ai == src))) + possible += R + + if(!LAZYLEN(possible)) + to_chat(src, "No usable AI shell beacons detected.") + + if(!target || !(target in possible)) //If the AI is looking for a new shell, or its pre-selected shell is no longer valid + target = input(src, "Which body to control?") as null|anything in possible + + if (!target || target.stat == DEAD || target.deployed || !(!target.connected_ai ||(target.connected_ai == src))) + return + + else if(mind) + soullink(/datum/soullink/sharedbody, src, target) + deployed_shell = target + target.deploy_init(src) + mind.transfer_to(target) + diag_hud_set_deployed() + +/datum/action/innate/deploy_shell + name = "Deploy to AI Shell" + desc = "Wirelessly control a specialized cyborg shell." + icon_icon = 'icons/mob/actions/actions_AI.dmi' + button_icon_state = "ai_shell" + +/datum/action/innate/deploy_shell/Trigger() + var/mob/living/silicon/ai/AI = owner + if(!AI) + return + AI.deploy_to_shell() + +/datum/action/innate/deploy_last_shell + name = "Reconnect to shell" + desc = "Reconnect to the most recently used AI shell." + icon_icon = 'icons/mob/actions/actions_AI.dmi' + button_icon_state = "ai_last_shell" + var/mob/living/silicon/robot/last_used_shell + +/datum/action/innate/deploy_last_shell/Trigger() + if(!owner) + return + if(last_used_shell) + var/mob/living/silicon/ai/AI = owner + AI.deploy_to_shell(last_used_shell) + else + Remove(owner) //If the last shell is blown, destroy it. + +/mob/living/silicon/ai/proc/disconnect_shell() + if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss. + to_chat(src, "Your remote connection has been reset!") + deployed_shell.undeploy() + diag_hud_set_deployed() + +/mob/living/silicon/ai/resist() + return + +/mob/living/silicon/ai/spawned/Initialize(mapload, datum/ai_laws/L, mob/target_ai) + . = ..() + if(!target_ai) + target_ai = src //cheat! just give... ourselves as the spawned AI, because that's technically correct + +/mob/living/silicon/ai/proc/camera_visibility(mob/camera/aiEye/moved_eye) + GLOB.cameranet.visibility(moved_eye, client, all_eyes, USE_STATIC_OPAQUE) + +/mob/living/silicon/ai/forceMove(atom/destination) + . = ..() + if(.) + end_multicam() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index d2b23d5e..0e3cde56 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -80,7 +80,7 @@ Difficulty: Medium return FALSE return ..() -/mob/living/simple_animal/hostile/megafauna/dragon/visible_message() +/mob/living/simple_animal/hostile/megafauna/dragon/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs) if(swooping & SWOOP_INVULNERABLE) //to suppress attack messages without overriding every single proc that could send a message saying we got hit return return ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 3d60ea43..87681881 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -87,106 +87,120 @@ msg = copytext(msg, 1, MAX_MESSAGE_LEN) if(type) - if(type & 1 && eye_blind )//Vision related + if(type & MSG_VISUAL && eye_blind )//Vision related if(!alt_msg) return else msg = alt_msg type = alt_type - if(type & 2 && !can_hear())//Hearing related + if(type & MSG_AUDIBLE && !can_hear())//Hearing related if(!alt_msg) return else msg = alt_msg type = alt_type - if(type & 1 && eye_blind) + if(type & MSG_VISUAL && eye_blind) return // voice muffling if(stat == UNCONSCIOUS) - if(type & 2) //audio + if(type & MSG_AUDIBLE) //audio to_chat(src, "... You can almost hear something ...") - else - to_chat(src, msg) + return + to_chat(src, msg) -// Show a message to all player mobs who sees this atom -// Show a message to the src mob (if the src is a mob) -// Use for atoms performing visible actions -// message is output to anyone who can see, e.g. "The [src] does something!" -// self_message (optional) is what the src mob sees e.g. "You do something!" -// blind_message (optional) is what blind people will hear e.g. "You hear something!" -// vision_distance (optional) define how many tiles away the message can be seen. -// ignored_mob (optional) doesn't show any message to a given mob if TRUE. - -/atom/proc/visible_message(message, self_message, blind_message, vision_distance, list/ignored_mobs, no_ghosts = FALSE) +/** + * Generate a visible message from this atom + * + * Show a message to all player mobs who sees this atom + * + * Show a message to the src mob (if the src is a mob) + * + * Use for atoms performing visible actions + * + * message is output to anyone who can see, e.g. "The [src] does something!" + * + * Vars: + * * self_message (optional) is what the src mob sees e.g. "You do something!" + * * blind_message (optional) is what blind people will hear e.g. "You hear something!" + * * vision_distance (optional) define how many tiles away the message can be seen. + * * ignored_mobs (optional) doesn't show any message to any given mob in the list. + */ +/atom/proc/visible_message(message, self_message, blind_message, vision_distance = DEFAULT_MESSAGE_RANGE, list/ignored_mobs) var/turf/T = get_turf(src) if(!T) return + var/list/hearers = get_hearers_in_view(vision_distance, src) //caches the hearers and then removes ignored mobs. + if(!length(hearers)) + return if(!islist(ignored_mobs)) ignored_mobs = list(ignored_mobs) - var/range = 7 - if(vision_distance) - range = vision_distance - for(var/mob/M in get_hearers_in_view(range, src)) + hearers -= ignored_mobs + if(self_message) + hearers -= src + for(var/mob/M in hearers) if(!M.client) continue - if(M in ignored_mobs) - continue + //This entire if/else chain could be in two lines but isn't for readibilties sake. var/msg = message - if(isobserver(M) && no_ghosts) + //CITADEL EDIT, required for vore code to remove (T != loc && T != src)) as a check + if(M.see_invisible[user.say_emphasis(message)]" if(emote_type == EMOTE_AUDIBLE) - user.audible_message(message=message,hearing_distance=1, no_ghosts = TRUE) + user.audible_message(message=message,hearing_distance=1, ignored_mobs = GLOB.dead_mob_list) else - user.visible_message(message=message,self_message=message,vision_distance=1, no_ghosts = TRUE) + user.visible_message(message=message,self_message=message,vision_distance=1, ignored_mobs = GLOB.dead_mob_list) log_emote("[key_name(user)] : (SUBTLER) [message]") message = null diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 10214f12..8f416cc0 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -719,10 +719,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) for(var/mob/living/L in range(10)) investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER) if(L in view()) - L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\ - "The unearthly ringing subsides and you notice you have new radiation burns.", 2) + L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", MSG_VISUAL,\ + "The unearthly ringing subsides and you notice you have new radiation burns.", MSG_AUDIBLE) else - L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", 2) + L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", MSG_AUDIBLE) //Do not blow up our internal radio /obj/machinery/power/supermatter_crystal/contents_explosion(severity, target) diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm index 05d63673..99102a2d 100644 --- a/code/modules/projectiles/pins.dm +++ b/code/modules/projectiles/pins.dm @@ -58,10 +58,10 @@ /obj/item/firing_pin/proc/auth_fail(mob/living/user) if(user) - user.show_message(fail_message, 1) + user.show_message(fail_message, MSG_VISUAL) if(selfdestruct) if(user) - user.show_message("SELF-DESTRUCTING...
", 1) + user.show_message("SELF-DESTRUCTING...
", MSG_VISUAL) to_chat(user, "[gun] explodes!") explosion(get_turf(gun), -1, 0, 2, 3) if(gun) diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm index 919d1d4f..852f0b67 100644 --- a/code/modules/recycling/disposal/holder.dm +++ b/code/modules/recycling/disposal/holder.dm @@ -115,7 +115,7 @@ if(user.incapacitated()) return for(var/mob/M in range(5, get_turf(src))) - M.show_message("CLONG, clong!", 2) + M.show_message("CLONG, clong!", MSG_AUDIBLE) playsound(src.loc, 'sound/effects/clang.ogg', 50, 0, 0) // called to vent all gas in holder to a location diff --git a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm index 1ad29c1a..dbd831f2 100644 --- a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm +++ b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm @@ -542,7 +542,7 @@ var/list/watching = hearers(3, owner) for(var/mob/living/M in watching) if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) //Might as well censor the normies here too. - M.show_message(struggle_outer_message, 1) // visible + M.show_message(struggle_outer_message, MSG_VISUAL) // visible to_chat(R,struggle_user_message)

Name

Status

Location

Control

[Bot.hacked ? "(!)" : ""] [Bot.name] ([Bot.model])[bot_mode][get_area_name(Bot, TRUE)]InterfaceCall