Merge remote-tracking branch 'citadel/master' into shield_refactor

This commit is contained in:
kevinz000
2020-03-20 22:59:17 -07:00
151 changed files with 156081 additions and 3945 deletions
@@ -27,7 +27,7 @@
INVOKE_ASYNC(B, /obj/effect/mine/pickup/bloodbath/.proc/mineEffect, H) //could use moving out from the mine
for(var/mob/living/carbon/human/P in GLOB.player_list)
if(P == H)
if(P == H || HAS_TRAIT(P, TRAIT_NO_MIDROUND_ANTAG))
continue
to_chat(P, "<span class='userdanger'>You have an overwhelming desire to kill [H]. [H.p_theyve(TRUE)] been marked red! Whoever [H.p_they()] [H.p_were()], friend or foe, go kill [H.p_them()]!</span>")
P.put_in_hands(new /obj/item/kitchen/knife/butcher(P), TRUE)
@@ -185,10 +185,10 @@
BuyPower(new /datum/action/bloodsucker/veil)
// Traits
for(var/T in defaultTraits)
ADD_TRAIT(owner.current, T, "bloodsucker")
ADD_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
if(HAS_TRAIT(owner.current, TRAIT_TOXINLOVER)) //No slime bonuses here, no thank you
had_toxlover = TRUE
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
REMOVE_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
// Traits: Species
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
@@ -235,9 +235,9 @@
// owner.RemoveSpell(power)
// Traits
for(var/T in defaultTraits)
REMOVE_TRAIT(owner.current, T, "bloodsucker")
REMOVE_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
if(had_toxlover == TRUE)
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, "species")
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
// Traits: Species
if(ishuman(owner.current))
@@ -387,7 +387,7 @@
add_objective(heartthief_objective)
/*
else
// Solars Objective, doesnt work due to TG updates.
var/datum/objective/bloodsucker/solars/solars_objective = new
solars_objective.owner = owner
@@ -6,7 +6,7 @@
/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T)
var/datum/objective/escape/O = new
O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!"
O.explanation_text = "You have no explicit goals! While we don't approve of mindless slaughter, you may antagonize nanotrasen any way you wish! Make sure to escape alive and not in custody, though!"
O.owner = T.owner
T.add_objective(O)
return
+1 -1
View File
@@ -211,7 +211,7 @@
/datum/export/weapon/arrows
cost = 150
unit_name = "arrow"
export_types = list(/obj/item/ammo_casing/caseless/arrow, /obj/item/ammo_casing/caseless/arrow/bone, /obj/item/ammo_casing/caseless/arrow/ashen)
export_types = list(/obj/item/ammo_casing/caseless/arrow, /obj/item/ammo_casing/caseless/arrow/bone, /obj/item/ammo_casing/caseless/arrow/ash)
/datum/export/weapon/bow_teaching
cost = 500
-8
View File
@@ -223,7 +223,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
new /datum/admins(localhost_rank, ckey, 1, 1)
//preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum)
prefs = GLOB.preferences_datums[ckey]
prefs_vr = GLOB.vore_preferences_datums[ckey] //CITADEL EDIT bypassing a failing hook
if(prefs)
prefs.parent = src
@@ -231,13 +230,6 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
prefs = new /datum/preferences(src)
GLOB.preferences_datums[ckey] = prefs
if(prefs_vr) //CITADEL EDIT bypassing a failing hook START
prefs_vr.client = src
else
prefs_vr = new/datum/vore_preferences(src)
GLOB.vore_preferences_datums[ckey] = prefs_vr
//CITADEL EDIT bypassing a failing hook END
prefs.last_ip = address //these are gonna be used for banning
prefs.last_id = computer_id //these are gonna be used for banning
fps = prefs.clientfps
+10 -41
View File
@@ -125,28 +125,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"cock_length" = 6,
"cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF,
"cock_color" = "fff",
"has_sheath" = FALSE,
"sheath_color" = "fff",
"has_balls" = FALSE,
"balls_internal" = FALSE,
"balls_color" = "fff",
"balls_amount" = 2,
"balls_sack_size" = BALLS_SACK_SIZE_DEF,
"balls_shape" = "Single",
"balls_size" = BALLS_SIZE_DEF,
"balls_cum_rate" = CUM_RATE,
"balls_cum_mult" = CUM_RATE_MULT,
"balls_efficiency" = CUM_EFFICIENCY,
"has_ovi" = FALSE,
"ovi_shape" = "knotted",
"ovi_length" = 6,
"ovi_color" = "fff",
"has_eggsack" = FALSE,
"eggsack_internal" = TRUE,
"eggsack_color" = "fff",
"eggsack_size" = BALLS_SACK_SIZE_DEF,
"eggsack_egg_color" = "fff",
"eggsack_egg_size" = EGG_GIRTH_DEF,
"has_breasts" = FALSE,
"breasts_color" = "fff",
"breasts_size" = "C",
@@ -205,6 +191,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/action_buttons_screen_locs = list()
//bad stuff
var/digestable = FALSE
var/devourable = FALSE
var/feeding = FALSE
var/lickable = FALSE
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
//backgrounds
var/mutable_appearance/character_background
var/icon/bgstate = "steel"
@@ -1483,7 +1477,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
if("flavor_text")
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", features["flavor_text"], MAX_FAVOR_LEN, TRUE)
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", features["flavor_text"], MAX_FLAVOR_LEN, TRUE)
if(!isnull(msg))
features["flavor_text"] = html_decode(msg)
@@ -1916,6 +1910,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list
if(new_dors)
features["xenodorsal"] = new_dors
//Genital code
if("cock_color")
var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
@@ -1956,22 +1951,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_shape)
features["balls_shape"] = new_shape
if("egg_size")
var/new_size
var/list/egg_sizes = list(1,2,3)
new_size = input(user, "Egg Diameter(inches):", "Egg Size") as null|anything in egg_sizes
if(new_size)
features["eggsack_egg_size"] = new_size
if("egg_color")
var/new_egg_color = input(user, "Egg Color:", "Character Preference") as color|null
if(new_egg_color)
var/temp_hsv = RGBtoHSV(new_egg_color)
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
features["eggsack_egg_color"] = sanitize_hexcolor(new_egg_color)
else
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
if("breasts_size")
var/new_size
new_size = input(user, "Breast Size", "Character Preference") as null|anything in GLOB.breasts_size_list
@@ -2105,14 +2084,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["has_balls"] = FALSE
if("has_balls")
features["has_balls"] = !features["has_balls"]
if("has_ovi")
features["has_ovi"] = !features["has_ovi"]
if("has_eggsack")
features["has_eggsack"] = !features["has_eggsack"]
if("balls_internal")
features["balls_internal"] = !features["balls_internal"]
if("eggsack_internal")
features["eggsack_internal"] = !features["eggsack_internal"]
if("has_breasts")
features["has_breasts"] = !features["has_breasts"]
if(features["has_breasts"] == FALSE)
@@ -2301,16 +2274,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("load")
load_preferences()
load_character()
if(parent && parent.prefs_vr)
attempt_vr(parent.prefs_vr,"load_vore","")
if("changeslot")
if(!load_character(text2num(href_list["num"])))
random_character()
real_name = random_unique_name(gender)
save_character()
if(parent && parent.prefs_vr)
attempt_vr(parent.prefs_vr,"load_vore","")
if("tab")
if (href_list["tab"])
+51 -18
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 25
#define SAVEFILE_VERSION_MAX 26
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -115,6 +115,36 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(digi == "Digitigrade Legs")
WRITE_FILE(S["feature_lizard_legs"], "Digitigrade")
if(current_version < 26)
var/vr_path = "data/player_saves/[parent.ckey[1]]/[parent.ckey]/vore/character[default_slot].json"
if(fexists(vr_path))
var/list/json_from_file = json_decode(file2text(vr_path))
if(json_from_file)
digestable = json_from_file["digestable"]
devourable = json_from_file["devourable"]
feeding = json_from_file["feeding"]
lickable = json_from_file["lickable"]
belly_prefs = json_from_file["belly_prefs"]
vore_taste = json_from_file["vore_taste"]
for(var/V in all_quirks) // quirk migration
switch(V)
if("Acute hepatic pharmacokinesis")
DISABLE_BITFIELD(cit_toggles, PENIS_ENLARGEMENT)
DISABLE_BITFIELD(cit_toggles, BREAST_ENLARGEMENT)
ENABLE_BITFIELD(cit_toggles,FORCED_FEM)
ENABLE_BITFIELD(cit_toggles,FORCED_MASC)
all_quirks -= V
if("Crocin Immunity")
ENABLE_BITFIELD(cit_toggles,NO_APHRO)
all_quirks -= V
if("Buns of Steel")
ENABLE_BITFIELD(cit_toggles,NO_ASS_SLAP)
all_quirks -= V
if(features["meat_type"] == "Inesct")
features["meat_type"] = "Insect"
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -422,7 +452,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_balls_color"] >> features["balls_color"]
S["feature_balls_size"] >> features["balls_size"]
S["feature_balls_shape"] >> features["balls_shape"]
S["feature_balls_sack_size"] >> features["balls_sack_size"]
//breasts features
S["feature_has_breasts"] >> features["has_breasts"]
S["feature_breasts_size"] >> features["breasts_size"]
@@ -446,6 +475,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
else //We have no old flavortext, default to new
S["feature_flavor_text"] >> features["flavor_text"]
S["digestable"] >> digestable
S["devourable"] >> devourable
S["feeding"] >> feeding
S["vore_taste"] >> vore_taste
S["lickable"] >> lickable
S["belly_prefs"] >> belly_prefs
//try to fix any outdated data if necessary
if(needs_update >= 0)
@@ -509,6 +544,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None")
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
//Validate job prefs
@@ -518,23 +554,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
all_quirks = SANITIZE_LIST(all_quirks)
for(var/V in all_quirks) // quirk migration
switch(V)
if("Acute hepatic pharmacokinesis")
DISABLE_BITFIELD(cit_toggles, PENIS_ENLARGEMENT)
DISABLE_BITFIELD(cit_toggles, BREAST_ENLARGEMENT)
ENABLE_BITFIELD(cit_toggles,FORCED_FEM)
ENABLE_BITFIELD(cit_toggles,FORCED_MASC)
all_quirks -= V
if("Crocin Immunity")
ENABLE_BITFIELD(cit_toggles,NO_APHRO)
all_quirks -= V
if("Buns of Steel")
ENABLE_BITFIELD(cit_toggles,NO_ASS_SLAP)
all_quirks -= V
lickable = sanitize_integer(lickable, FALSE, TRUE, initial(lickable))
devourable = sanitize_integer(devourable, FALSE, TRUE, initial(devourable))
digestable = sanitize_integer(digestable, FALSE, TRUE, initial(digestable))
feeding = sanitize_integer(feeding, FALSE, TRUE, initial(feeding))
vore_taste = copytext(vore_taste, 1, MAX_TASTE_LEN)
belly_prefs = SANITIZE_LIST(belly_prefs)
if(features["meat_type"] == "Inesct")
features["meat_type"] = "Insect"
cit_character_pref_load(S)
return 1
@@ -613,6 +639,13 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
WRITE_FILE(S["digestable"] , digestable)
WRITE_FILE(S["devourable"] , devourable)
WRITE_FILE(S["feeding"] , feeding)
WRITE_FILE(S["vore_taste"] , vore_taste)
WRITE_FILE(S["lickable"] , lickable)
WRITE_FILE(S["belly_prefs"] , belly_prefs)
cit_character_pref_save(S)
return 1
@@ -97,6 +97,11 @@
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
/obj/item/clothing/glasses/meson/eyepatch
name = "eyepatch mesons"
desc = "A meson system that connects directly to the optical nerve of the user, replacing the need for that useless eyeball."
icon_state = "mesonpatch"
/obj/item/clothing/glasses/science
name = "science goggles"
desc = "A pair of snazzy goggles used to protect against chemical spills. Fitted with an analyzer for scanning items and reagents."
+17 -6
View File
@@ -83,6 +83,11 @@
name = "prescription medical HUDSunglasses"
vision_correction = 1
/obj/item/clothing/glasses/hud/health/eyepatch
name = "eyepatch medHUD"
desc = "A heads-up display that connects directly to the optical nerve of the user, replacing the need for that useless eyeball."
icon_state = "medpatch"
///////////////////
//Diagnostic Huds//
///////////////////
@@ -97,7 +102,8 @@
/obj/item/clothing/glasses/hud/diagnostic/sunglasses
name = "diagnostic HUDSunglasses"
desc = "Sunglasses with a diagnostic HUD."
icon_state = "sunhuddiagnostic"
icon_state = "sunhuddiag"
item_state = "glasses"
darkness_view = 1
flash_protect = 1
tint = 1
@@ -123,6 +129,11 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/hud/diagnostic/eyepatch
name = "eyepatch diagnostic HUD"
desc = "A heads-up display that connects directly to the optical nerve of the user, replacing the need for that useless eyeball."
icon_state = "diagpatch"
////////////
//Sec Huds//
////////////
@@ -165,11 +176,6 @@
return
chameleon_action.emp_randomise()
/obj/item/clothing/glasses/hud/security/sunglasses/eyepatch
name = "eyepatch HUD"
desc = "A heads-up display that connects directly to the optical nerve of the user, replacing the need for that useless eyeball."
icon_state = "hudpatch"
/obj/item/clothing/glasses/hud/security/sunglasses
name = "security HUDSunglasses"
desc = "Sunglasses with a security HUD."
@@ -179,6 +185,11 @@
tint = 1
glass_colour_type = /datum/client_colour/glass_colour/darkred
/obj/item/clothing/glasses/hud/security/sunglasses/eyepatch // why was this defined *before* the sunglasses it is a subtype of.
name = "eyepatch HUD"
desc = "A heads-up display that connects directly to the optical nerve of the user, replacing the need for that useless eyeball."
icon_state = "hudpatch"
/obj/item/clothing/glasses/hud/security/sunglasses/prescription
name = "prescription security HUDSunglasses"
vision_correction = 1
+5 -4
View File
@@ -16,13 +16,14 @@
..()
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
H.put_in_hands(new /obj/item/valentine)
var/obj/item/storage/backpack/b = locate() in H.contents
new /obj/item/reagent_containers/food/snacks/candyheart(b)
new /obj/item/storage/fancy/heart_box(b)
var/obj/item/storage/backpack/B = locate() in H.contents
if(B)
new /obj/item/reagent_containers/food/snacks/candyheart(B)
new /obj/item/storage/fancy/heart_box(B)
var/list/valentines = list()
for(var/mob/living/M in GLOB.player_list)
if(!M.stat && M.client && M.mind)
if(!M.stat && M.client && M.mind && !HAS_TRAIT(M, TRAIT_NO_MIDROUND_ANTAG))
valentines |= M
+16 -1
View File
@@ -4,11 +4,26 @@
weight = 10
max_occurrences = 2
min_players = 1
var/forced_hallucination
/datum/round_event_control/mass_hallucination/admin_setup()
if(!check_rights(R_FUN))
return
forced_hallucination = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in subtypesof(/datum/hallucination)
/datum/round_event/mass_hallucination
fakeable = FALSE
/datum/round_event/mass_hallucination/start()
var/datum/round_event_control/mass_hallucination/M = control
if(M.forced_hallucination)
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
if (HAS_TRAIT(C,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
new M.forced_hallucination(C, TRUE)
return
switch(rand(1,4))
if(1) //same sound for everyone
var/sound = pick("airlock","airlock_pry","console","explosion","far_explosion","mech","glass","alarm","beepsky","mech","wall_decon","door_hack","tesla")
@@ -37,4 +52,4 @@
for(var/mob/living/carbon/C in GLOB.alive_mob_list)
if (HAS_TRAIT(C,TRAIT_EXEMPT_HEALTH_EVENTS))
continue
new picked_hallucination(C, TRUE)
new picked_hallucination(C, TRUE)
@@ -49,6 +49,10 @@
to_chat(user, "<span class='notice'>You place [I] into [src] to start the fermentation process.</span>")
addtimer(CALLBACK(src, .proc/makeWine, fruit), rand(80, 120) * speed_multiplier)
return TRUE
var/obj/item/W = I
if(W)
if(W.is_refillable())
return FALSE //so we can refill them via their afterattack.
else
return ..()
@@ -136,7 +136,7 @@
desc = "A device which causes kinetic accelerators to permanently gain damage against creature types killed with it."
id = "bountymod"
materials = list(/datum/material/iron = 4000, /datum/material/silver = 4000, /datum/material/gold = 4000, /datum/material/bluespace = 4000)
reagents_list = list("blood" = 40)
reagents_list = list(/datum/reagent/blood = 40)
build_path = /obj/item/borg/upgrade/modkit/bounty
//Spooky special loot
+1 -1
View File
@@ -237,7 +237,7 @@
return /datum/reagent/blood/jellyblood
if(dna?.species?.exotic_blood)
return dna.species.exotic_blood
else if((NOBLOOD in dna.species.species_traits) || (HAS_TRAIT(src, TRAIT_NOCLONE)))
else if((dna && (NOBLOOD in dna.species.species_traits)) || HAS_TRAIT(src, TRAIT_NOCLONE))
return
else
return /datum/reagent/blood
+3
View File
@@ -24,6 +24,9 @@
/obj/item/mmi/update_overlays()
. = ..()
. += add_mmi_overlay()
/obj/item/mmi/proc/add_mmi_overlay()
if(brainmob && brainmob.stat != DEAD)
. += "mmi_alive"
else
@@ -193,3 +193,6 @@ GLOBAL_VAR(posibrain_notify_cooldown)
icon_state = "[initial(icon_state)]-occupied"
else
icon_state = initial(icon_state)
/obj/item/mmi/posibrain/add_mmi_overlay()
return
@@ -24,7 +24,7 @@
id = "spaceskeleton"
limbs_id = "skeleton"
blacklisted = 1
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT, TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
/datum/species/skeleton/space/check_roundstart_eligible()
return FALSE
+1 -1
View File
@@ -24,4 +24,4 @@
if(ranged_ability)
ranged_ability.add_ranged_ability(src, "<span class='notice'>You currently have <b>[ranged_ability]</b> active!</span>")
if(vore_init && !vorepref_init) //Vore's been initialized, voreprefs haven't. If this triggers then that means that voreprefs failed to load due to the client being missing.
apply_vore_prefs()
copy_from_prefs_vr()
@@ -1116,6 +1116,7 @@
desc = "Stop controlling your shell and resume normal core operations."
icon_icon = 'icons/mob/actions/actions_AI.dmi'
button_icon_state = "ai_core"
required_mobility_flags = NONE
/datum/action/innate/undeployment/Trigger()
if(!..())
@@ -913,8 +913,8 @@
/obj/item/crowbar/cyborg,
/obj/item/reagent_containers/borghypo/syndicate,
/obj/item/twohanded/shockpaddles/syndicate,
/obj/item/healthanalyzer,
/obj/item/surgical_drapes,
/obj/item/healthanalyzer/advanced,
/obj/item/surgical_drapes/advanced,
/obj/item/retractor,
/obj/item/hemostat,
/obj/item/cautery,
@@ -204,7 +204,7 @@
rapid = 2
icon_state = "syndicate_smg"
icon_living = "syndicate_smg"
casingtype = /obj/item/ammo_casing/c45/nostamina
casingtype = /obj/item/ammo_casing/c45
projectilesound = 'sound/weapons/gunshot_smg.ogg'
/mob/living/simple_animal/hostile/syndicate/ranged/smg/pilot //caravan ambush ruin
+3
View File
@@ -70,6 +70,9 @@
else
. = FALSE //as to not cancel attack_hand()
/obj/item/clothing/gloves/space_ninja/dropped(mob/user)
. = ..()
REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
/obj/item/clothing/gloves/space_ninja/proc/toggledrain()
var/mob/living/carbon/human/U = loc
+5 -1
View File
@@ -9,4 +9,8 @@
strip_delay = 12
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
blockTracking = 1//Roughly the only unique thing about this helmet.
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
/obj/item/clothing/head/helmet/space/space_ninja/dropped(mob/user)
. = ..()
REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
+4
View File
@@ -19,6 +19,10 @@ Contents:
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
modifies_speech = TRUE
/obj/item/clothing/mask/gas/space_ninja/dropped(mob/user)
. = ..()
REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
/obj/item/clothing/mask/gas/space_ninja/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
+1 -1
View File
@@ -204,7 +204,7 @@
w_class = WEIGHT_CLASS_NORMAL
name = "energy dagger"
hitsound = 'sound/weapons/blade1.ogg'
embedding = embedding.setRating(embed_chance = 100) //rule of cool
embedding = list("embed_chance" = 100, "embedded_fall_chance" = 0)//rule of cool
throwforce = 35
playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
to_chat(user, "<span class='warning'>[src] is now active.</span>")
@@ -24,9 +24,6 @@
caliber = ".45"
projectile_type = /obj/item/projectile/bullet/c45
/obj/item/ammo_casing/c45/nostamina
projectile_type = /obj/item/projectile/bullet/c45_nostamina
/obj/item/ammo_casing/c45/kitchengun
desc = "A .45 bullet casing. It has a small sponge attached to it."
projectile_type = /obj/item/projectile/bullet/c45_cleaning
@@ -1,17 +1,21 @@
/obj/item/ammo_casing/caseless/arrow
name = "wooden arrow"
desc = "An arrow made of wood, typically fired from a bow."
name = "arrow of questionable material"
desc = "You shouldn't be seeing this arrow."
projectile_type = /obj/item/projectile/bullet/reusable/arrow
caliber = "arrow"
icon_state = "arrow"
throwforce = 3 //good luck hitting someone with the pointy end of the arrow
throw_speed = 3
/obj/item/ammo_casing/caseless/arrow/ashen
/obj/item/ammo_casing/caseless/arrow/wood
name = "wooden arrow"
desc = "An arrow made of wood, typically fired from a bow."
/obj/item/ammo_casing/caseless/arrow/ash
name = "ashen arrow"
desc = "An arrow made of wood, hardened by fire."
icon_state = "ashenarrow"
projectile_type = /obj/item/projectile/bullet/reusable/arrow/ashen
projectile_type = /obj/item/projectile/bullet/reusable/arrow/ash
/obj/item/ammo_casing/caseless/arrow/bone
name = "bone arrow"
+1 -1
View File
@@ -60,7 +60,7 @@
/obj/item/ammo_box/magazine/smgm45
name = "SMG magazine (.45)"
icon_state = "c20r45-24"
ammo_type = /obj/item/ammo_casing/c45/nostamina
ammo_type = /obj/item/ammo_casing/c45
caliber = ".45"
max_ammo = 24
+24 -19
View File
@@ -28,6 +28,16 @@
/datum/duel/New()
id = next_id++
/datum/duel/Destroy()
if(gun_A)
gun_A.duel = null
gun_A = null
if(gun_B)
gun_B.duel = null
gun_B = null
STOP_PROCESSING(SSobj, src)
. = ..()
/datum/duel/proc/try_begin()
//Check if both guns are held and if so begin.
var/mob/living/A = get_duelist(gun_A)
@@ -45,13 +55,13 @@
message_duelists("<span class='notice'>Set your gun setting and move [required_distance] steps away from your opponent.</span>")
START_PROCESSING(SSobj,src)
START_PROCESSING(SSobj, src)
/datum/duel/proc/get_duelist(obj/gun)
var/mob/living/G = gun.loc
if(!istype(G) || !G.is_holding(gun))
return null
return G
/datum/duel/proc/get_duelist(obj/item/gun/energy/dueling/G)
var/mob/living/L = G.loc
if(!istype(L) || !L.is_holding(G))
return
return L
/datum/duel/proc/message_duelists(message)
var/mob/living/LA = get_duelist(gun_A)
@@ -66,7 +76,7 @@
/datum/duel/proc/end()
message_duelists("<span class='notice'>Duel finished. Re-engaging safety.</span>")
STOP_PROCESSING(SSobj,src)
STOP_PROCESSING(SSobj, src)
state = DUEL_IDLE
/datum/duel/process()
@@ -129,10 +139,11 @@
return FALSE
if(!isturf(A.loc) || !isturf(B.loc))
return FALSE
if(get_dist(A,B) != required_distance)
if(get_dist(A, B) != required_distance)
return FALSE
for(var/turf/T in getline(get_turf(A),get_turf(B)))
if(is_blocked_turf(T,TRUE))
for(var/i in getline(A.loc, B.loc))
var/turf/T = i
if(is_blocked_turf(T, TRUE))
return FALSE
return TRUE
@@ -180,7 +191,6 @@
return "duel_red"
/obj/item/gun/energy/dueling/attack_self(mob/living/user)
. = ..()
if(duel.state == DUEL_IDLE)
duel.try_begin()
else
@@ -205,12 +215,9 @@
add_overlay(setting_overlay)
/obj/item/gun/energy/dueling/Destroy()
. = ..()
if(duel.gun_A == src)
duel.gun_A = null
if(duel.gun_B == src)
duel.gun_B = null
duel = null
if(duel)
qdel(duel)
return ..()
/obj/item/gun/energy/dueling/can_trigger_gun(mob/living/user)
. = ..()
@@ -234,10 +241,8 @@
if(duel.state == DUEL_READY)
duel.confirmations[src] = TRUE
to_chat(user,"<span class='notice'>You confirm your readiness.</span>")
return
else if(!is_duelist(target)) //I kinda want to leave this out just to see someone shoot a bystander or missing.
to_chat(user,"<span class='warning'>[src] safety system prevents shooting anyone but your designated opponent.</span>")
return
else
duel.fired[src] = TRUE
. = ..()
@@ -181,13 +181,6 @@
listeningTo = null
return ..()
/obj/item/gun/energy/beam_rifle/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
chambered = null
recharge_newshot()
/obj/item/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE)
var/diff = abs(aiming_lastangle - lastangle)
if(!check_user())
@@ -302,7 +295,7 @@
if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher))
return
process_aim()
if(aiming_time_left <= aiming_time_fire_threshold && check_user() && ((lastfire + delay) <= world.time))
if(fire_check())
sync_ammo()
do_fire(M.client.mouseObject, M, FALSE, M.client.mouseParams, M.zone_selected)
stop_aiming()
@@ -310,11 +303,16 @@
return ..()
/obj/item/gun/energy/beam_rifle/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
if(!fire_check())
return
. = ..()
if(.)
lastfire = world.time
stop_aiming()
/obj/item/gun/energy/beam_rifle/proc/fire_check()
return (aiming_time_left <= aiming_time_fire_threshold) && check_user() && ((lastfire + delay) <= world.time)
/obj/item/gun/energy/beam_rifle/proc/sync_ammo()
for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents)
AC.sync_stats()
@@ -531,21 +529,15 @@
tracer_type = /obj/effect/projectile/tracer/tracer/beam_rifle
var/constant_tracer = FALSE
/obj/item/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, impacting = TRUE, highlander)
set waitfor = FALSE
if(isnull(highlander))
highlander = constant_tracer
if(highlander && istype(gun))
QDEL_LIST(gun.current_tracers)
for(var/datum/point/p in beam_segments)
gun.current_tracers += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, 0, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity)
/obj/item/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, impacting = TRUE, generation, highlander = constant_tracer)
if(!highlander)
return ..()
else
for(var/datum/point/p in beam_segments)
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity)
if(cleanup)
QDEL_LIST(beam_segments)
beam_segments = null
QDEL_NULL(beam_index)
duration = 0
. = ..()
if(!generation) //first one
QDEL_LIST(gun.current_tracers)
gun.current_tracers += .
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam
tracer_type = /obj/effect/projectile/tracer/tracer/aiming
@@ -560,4 +552,5 @@
hitscan_light_color_override = "#99ff99"
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target)
qdel(src)
return FALSE
@@ -0,0 +1,169 @@
// this is all shitcode never ever add it to the game it's for debugging only.
/datum/action/item_action/chameleon/change/gun/update_look(mob/user, obj/item/picked_item)
. = ..()
var/obj/item/gun/energy/laser/chameleon/CG = target
CG.get_chameleon_projectile(picked_item)
/obj/item/gun/energy/laser/chameleon
name = "practice laser gun"
desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice."
ammo_type = list(/obj/item/ammo_casing/energy/chameleon)
clumsy_check = 0
item_flags = NONE
pin = /obj/item/firing_pin
cell_type = /obj/item/stock_parts/cell/bluespace
var/datum/action/item_action/chameleon/change/gun/chameleon_action
var/list/chameleon_projectile_vars
var/list/chameleon_ammo_vars
var/list/chameleon_gun_vars
var/list/projectile_copy_vars
var/list/ammo_copy_vars
var/list/gun_copy_vars
var/badmin_mode = FALSE
var/can_hitscan = FALSE
var/hitscan_mode = FALSE
/obj/item/gun/energy/laser/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/gun
chameleon_action.chameleon_name = "Gun"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/gun/magic, ignore_root_path = FALSE)
chameleon_action.initialize_disguises()
projectile_copy_vars = list("name", "icon", "icon_state", "item_state", "speed", "color", "hitsound", "forcedodge", "impact_effect_type", "range", "suppressed", "hitsound_wall", "impact_effect_type", "pass_flags", "tracer_type", "muzzle_type", "impact_type")
chameleon_projectile_vars = list("name" = "practice laser", "icon" = 'icons/obj/projectiles.dmi', "icon_state" = "laser")
gun_copy_vars = list("fire_sound", "burst_size", "fire_delay")
chameleon_gun_vars = list()
ammo_copy_vars = list("firing_effect_type")
chameleon_ammo_vars = list()
recharge_newshot()
get_chameleon_projectile(/obj/item/gun/energy/laser)
/obj/item/gun/energy/laser/chameleon/emp_act(severity)
return
/obj/item/gun/energy/laser/chameleon/proc/reset_chameleon_vars()
chameleon_ammo_vars = list()
chameleon_gun_vars = list()
chameleon_projectile_vars = list()
var/static/list/blacklisted_vars = list("locs", "loc", "contents", "x", "y", "z", "parent_type", "type", "vars")
if(chambered)
for(var/v in ammo_copy_vars)
if(v in blacklisted_vars) //Just in case admins go crazy.
continue
chambered.vv_edit_var(v, initial(chambered.vars[v]))
for(var/v in gun_copy_vars)
if(v in blacklisted_vars)
continue
vv_edit_var(v, initial(vars[v]))
vars[v] = initial(vars[v])
QDEL_NULL(chambered.BB)
chambered.newshot()
/obj/item/gun/energy/laser/chameleon/proc/set_chameleon_ammo(obj/item/ammo_casing/AC, passthrough = TRUE, reset = FALSE)
if(!istype(AC))
CRASH("[AC] is not /obj/item/ammo_casing!")
return FALSE
for(var/V in ammo_copy_vars)
if(AC.vars.Find(V))
chameleon_ammo_vars[V] = AC.vars[V]
chambered?.vv_edit_var(V, AC.vars[V])
if(passthrough)
var/obj/item/projectile/P = AC.BB
set_chameleon_projectile(P)
/obj/item/gun/energy/laser/chameleon/proc/set_chameleon_projectile(obj/item/projectile/P)
if(!istype(P))
CRASH("[P] is not /obj/item/projectile!")
return FALSE
chameleon_projectile_vars = list("name" = "practice laser", "icon" = 'icons/obj/projectiles.dmi', "icon_state" = "laser", "nodamage" = TRUE)
for(var/V in projectile_copy_vars)
if(P.vars.Find(V))
chameleon_projectile_vars[V] = P.vars[V]
if(istype(chambered, /obj/item/ammo_casing/energy/chameleon))
var/obj/item/ammo_casing/energy/chameleon/AC = chambered
AC.projectile_vars = chameleon_projectile_vars.Copy()
if(!P.tracer_type)
can_hitscan = FALSE
set_hitscan(FALSE)
else
can_hitscan = TRUE
if(badmin_mode)
qdel(chambered.BB)
chambered.projectile_type = P.type
chambered.newshot()
/obj/item/gun/energy/laser/chameleon/proc/set_chameleon_gun(obj/item/gun/G , passthrough = TRUE)
if(!istype(G))
CRASH("[G] is not /obj/item/gun!")
return FALSE
for(var/V in gun_copy_vars)
if(vars.Find(V) && G.vars.Find(V))
chameleon_gun_vars[V] = G.vars[V]
vv_edit_var(V, G.vars[V])
if(passthrough)
if(istype(G, /obj/item/gun/ballistic))
var/obj/item/gun/ballistic/BG = G
var/obj/item/ammo_box/AB = new BG.mag_type(G)
qdel(BG)
if(!istype(AB)||!AB.ammo_type)
qdel(AB)
return FALSE
var/obj/item/ammo_casing/AC = new AB.ammo_type(G)
set_chameleon_ammo(AC)
else if(istype(G, /obj/item/gun/magic))
var/obj/item/gun/magic/MG = G
var/obj/item/ammo_casing/AC = new MG.ammo_type(G)
set_chameleon_ammo(AC)
else if(istype(G, /obj/item/gun/energy))
var/obj/item/gun/energy/EG = G
if(islist(EG.ammo_type) && EG.ammo_type.len)
var/obj/item/ammo_casing/AC = EG.ammo_type[1]
set_chameleon_ammo(AC)
else if(istype(G, /obj/item/gun/syringe))
var/obj/item/ammo_casing/AC = new /obj/item/ammo_casing/syringegun(src)
set_chameleon_ammo(AC)
/obj/item/gun/energy/laser/chameleon/attack_self(mob/user)
. = ..()
if(!can_hitscan)
to_chat(user, "<span class='warning'>[src]'s current disguised gun does not allow it to enable high velocity mode!</span>")
return
if(!chambered)
to_chat(user, "<span class='warning'>Unknown error in energy lens: Please reset chameleon disguise and try again.</span>")
return
set_hitscan(!hitscan_mode)
to_chat(user, "<span class='notice'>You toggle [src]'s high velocity beam mode to [hitscan_mode? "on" : "off"].</span>")
/obj/item/gun/energy/laser/chameleon/proc/set_hitscan(hitscan)
var/obj/item/ammo_casing/energy/chameleon/AC = chambered
AC.hitscan_mode = hitscan
hitscan_mode = hitscan
/obj/item/gun/energy/laser/chameleon/proc/get_chameleon_projectile(guntype)
reset_chameleon_vars()
var/obj/item/gun/G = new guntype(src)
set_chameleon_gun(G)
qdel(G)
/obj/item/ammo_casing/energy/chameleon
projectile_type = /obj/item/projectile/energy/chameleon
e_cost = 0
var/hitscan_mode = FALSE
var/list/projectile_vars = list()
/obj/item/ammo_casing/energy/chameleon/ready_proj(atom/target, mob/living/user, quiet, zone_override = "")
. = ..()
if(!BB)
newshot()
for(var/V in projectile_vars)
if(BB.vars.Find(V))
BB.vv_edit_var(V, projectile_vars[V])
if(hitscan_mode)
BB.hitscan = TRUE
/obj/item/projectile/energy/chameleon
nodamage = TRUE
+9 -4
View File
@@ -52,6 +52,8 @@
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
var/datum/point/beam_index
/// Used in generate_hitscan_tracers to determine which "cycle" we're on.
var/hitscan_effect_generation = 0
var/tracer_type
var/muzzle_type
var/impact_type
@@ -656,18 +658,20 @@
if(trajectory && beam_index)
var/datum/point/pcache = trajectory.copy_to()
beam_segments[beam_index] = pcache
generate_hitscan_tracers(null, null, impacting)
generate_hitscan_tracers(null, null, impacting, hitscan_effect_generation++)
/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3, impacting = TRUE)
/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3, impacting = TRUE, generation)
if(!length(beam_segments))
return
. = list()
if(tracer_type)
var/tempref = REF(src)
var/list/turfs = list()
for(var/datum/point/p in beam_segments)
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity, tempref)
. += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity, turfs)
if(muzzle_type && duration > 0)
var/datum/point/p = beam_segments[1]
var/atom/movable/thing = new muzzle_type
. += thing
p.move_atom_to_src(thing)
var/matrix/M = new
M.Turn(original_angle)
@@ -678,6 +682,7 @@
if(impacting && impact_type && duration > 0)
var/datum/point/p = beam_segments[beam_segments[beam_segments.len]]
var/atom/movable/thing = new impact_type
. += thing
p.move_atom_to_src(thing)
var/matrix/M = new
M.Turn(Angle)
@@ -1,18 +1,12 @@
// .45 (M1911 & C20r)
/obj/item/projectile/bullet/c45
name = ".45 bullet"
damage = 20
stamina = 65
/obj/item/projectile/bullet/c45_nostamina
name = ".45 bullet"
damage = 30
/obj/item/projectile/bullet/c45_cleaning
name = ".45 bullet"
damage = 24
stamina = 10
damage = 40 //BANG BANG BANG
/obj/item/projectile/bullet/c45_cleaning/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -9,7 +9,8 @@
stutter = 10
jitter = 20
hitsound = 'sound/weapons/taserhit.ogg'
range = 7
range = 14
speed = 0.6
tracer_type = /obj/effect/projectile/tracer/stun
muzzle_type = /obj/effect/projectile/muzzle/stun
impact_type = /obj/effect/projectile/impact/stun
@@ -42,9 +43,9 @@
knockdown_stamoverride = 0
knockdown_stam_max = 0
strong_tase = FALSE
range = 12
/obj/item/projectile/energy/electrode/security/hos
knockdown = 100
knockdown_stamoverride = 30
knockdown_stam_max = null
tase_duration = 10
@@ -3,13 +3,13 @@
desc = "Woosh!"
damage = 15
icon_state = "arrow"
ammo_type = /obj/item/ammo_casing/caseless/arrow
ammo_type = /obj/item/ammo_casing/caseless/arrow/wood
/obj/item/projectile/bullet/reusable/arrow/ashen
/obj/item/projectile/bullet/reusable/arrow/ash
name = "ashen arrow"
desc = "Fire harderned arrow."
damage = 25
ammo_type = /obj/item/ammo_casing/caseless/arrow/ashen
ammo_type = /obj/item/ammo_casing/caseless/arrow/ash
/obj/item/projectile/bullet/reusable/arrow/bone //AP for ashwalkers
name = "bone arrow"
@@ -356,7 +356,6 @@
replace_beaker(user, B)
to_chat(user, "<span class='notice'>You add [B] to [src].</span>")
updateUsrDialog()
update_icon()
else if(user.a_intent != INTENT_HARM && !istype(I, /obj/item/card/emag))
to_chat(user, "<span class='warning'>You can't load [I] into [src]!</span>")
return ..()
+3 -4
View File
@@ -43,14 +43,14 @@
set_APTFT()
return TRUE
/obj/item/reagent_containers/proc/set_APTFT(mob/user) //set amount_per_transfer_from_this
/obj/item/reagent_containers/proc/set_APTFT() //set amount_per_transfer_from_this
set name = "Set Transfer Amount"
set category = "Object"
set waitfor = FALSE
var/N = input("Amount per transfer from this:","[src]") as null|anything in possible_transfer_amounts
if(N)
amount_per_transfer_from_this = N
to_chat(user, "<span class='notice'>[src]'s transfer amount is now [amount_per_transfer_from_this] units.</span>")
to_chat(usr, "<span class='notice'>[src]'s transfer amount is now [amount_per_transfer_from_this] units.</span>")
/obj/item/reagent_containers/proc/add_initial_reagents()
if(list_reagents)
@@ -134,6 +134,7 @@
throwerstring = " THROWN BY [key_name(thrownby)] at [AT] (AREACOORD(AT)]"
log_reagent("SPLASH: [src] mob SplashReagents() onto [key_name(target)] at [TT] ([AREACOORD(TT)])[throwerstring] - [R]")
reagents.reaction(target, TOUCH)
reagents.clear_reagents()
else if(bartender_check(target) && thrown)
visible_message("<span class='notice'>[src] lands without spilling a single drop.</span>")
@@ -154,8 +155,6 @@
visible_message("<span class='notice'>[src] spills its contents all over [target].</span>")
reagents.reaction(target, TOUCH)
reagents.clear_reagents()
if(QDELETED(src))
return
//melts plastic beakers
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
+4
View File
@@ -55,6 +55,10 @@ Nothing else in the console has ID requirements.
if (istype(ID, /datum/material))
var/datum/material/material = ID
return material.name
else if(GLOB.chemical_reagents_list[ID])
var/datum/reagent/reagent = GLOB.chemical_reagents_list[ID]
return reagent.name
return ID
/obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any).
@@ -705,8 +705,9 @@
desc = "A miraculous chemical mix that grants human like intelligence to living beings. It has been modified with Syndicate technology to also grant an internal radio implant to the target and authenticate with identification systems."
/obj/item/slimepotion/slime/sentience/nuclear/after_success(mob/living/user, mob/living/simple_animal/SM)
var/obj/item/implant/radio/syndicate/imp = new
imp.implant(SM, user)
if(SM.can_be_implanted())
var/obj/item/implant/radio/syndicate/imp = new
imp.implant(SM, user)
SM.access_card = new /obj/item/card/id/syndicate(SM)
ADD_TRAIT(SM.access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
@@ -961,11 +962,12 @@
icon_state = "potgrey"
/obj/item/slimepotion/slime/slimeradio/attack(mob/living/M, mob/user)
if(!ismob(M))
return
if(!isanimal(M))
to_chat(user, "<span class='warning'>[M] is too complex for the potion!</span>")
return
if(!M.can_be_implanted())
to_chat(user, "<span class='warning'>[M] is incompatible with the potion!</span>")
return
if(M.stat)
to_chat(user, "<span class='warning'>[M] is dead!</span>")
return
@@ -163,7 +163,7 @@ GLOBAL_VAR_INIT(summon_magic_triggered, FALSE)
for(var/mob/living/carbon/human/H in GLOB.player_list)
var/turf/T = get_turf(H)
if(T && is_away_level(T.z))
if((T && is_away_level(T.z)) || HAS_TRAIT(H, TRAIT_NO_MIDROUND_ANTAG))
continue
if(summon_type == SUMMON_MAGIC)
give_magic(H)
+1 -1
View File
@@ -289,7 +289,7 @@
/obj/item/surgical_drapes/advanced
name = "smart surgical drapes"
desc = "A quite quirky set of drapes with wireless synchronization to the station's research networks, with an integrated display allowing users to execute advanced surgeries without the aid of an operating computer."
desc = "A smart set of drapes with wireless synchronization to the station's research networks, with an integrated display allowing users to execute advanced surgeries without the aid of an operating computer."
var/datum/techweb/linked_techweb
/obj/item/surgical_drapes/advanced/Initialize(mapload)
@@ -75,3 +75,11 @@
item = /obj/item/storage/fancy/cigarettes/cigpack_syndicate
cost = 2
illegal_tech = FALSE
/datum/uplink_item/badass/shades
name = "Big Sunglasses"
desc = "Prevents flashes and looks badbass with some Smokes."
item = /obj/item/clothing/glasses/sunglasses/big
cost = 1
surplus = 5
illegal_tech = FALSE
@@ -147,9 +147,9 @@
/datum/uplink_item/dangerous/rapier
name = "Rapier"
desc = "A fancy rapier with a diamond tip piercing anything that it comes into contack with. \
The rapier comes with its own sheath, this is rather noticeable as only the captain is known to carry a sheath. \
The sheath itself can be used to block melee attacks only. Its also jet black colours."
desc = "An elegant plastitanium rapier with a diamond tip and coated in a specialized knockout poison. \
The rapier comes with its own sheath, and is capable of puncturing through almost any defense. \
However, due to the size of the blade and obvious nature of the sheath, the weapon stands out as being obviously nefarious."
item = /obj/item/storage/belt/sabre/rapier
cost = 8
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
@@ -159,7 +159,7 @@
/datum/uplink_item/role_restricted/kitchen_gun
name = "Kitchen Gun (TM)"
desc = "A revolutionary .45 caliber cleaning solution! Say goodbye to daily stains and dirty surfaces with Kitchen Gun (TM)! \
Just five shots from Kitchen Gun (TM), and it'll sparkle like new! Includes two extra ammunition clips!"
Just three shots from Kitchen Gun (TM), and it'll sparkle like new! Includes two extra ammunition clips!"
cost = 10
surplus = 40
restricted_roles = list("Cook", "Janitor")
+39 -49
View File
@@ -41,7 +41,7 @@
return TRUE
//We'll load our client's organs if we have one
if(client && client.prefs_vr)
if(client?.prefs)
if(!copy_from_prefs_vr())
to_chat(src,"<span class='warning'>ERROR: You seem to have saved vore prefs, but they couldn't be loaded.</span>")
return FALSE
@@ -262,47 +262,22 @@
else
to_chat(src,"<span class='alert'>You aren't inside anyone, though, is the thing.</span>")
//
// Verb for saving vore preferences to save file
//
/mob/living/proc/save_vore_prefs()
if(!client || !client.prefs_vr)
return FALSE
if(!copy_to_prefs_vr())
return FALSE
if(!client.prefs_vr.save_vore())
return FALSE
return TRUE
/mob/living/proc/apply_vore_prefs()
if(!client || !client.prefs_vr)
return FALSE
if(!client.prefs_vr.load_vore())
return FALSE
if(!copy_from_prefs_vr())
return FALSE
return TRUE
/mob/living/proc/copy_to_prefs_vr()
if(!client || !client.prefs_vr)
to_chat(src,"<span class='warning'>You attempted to save your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.</span>")
if(!client || !client.prefs)
to_chat(src,"<span class='warning'>You attempted to save your vore prefs but somehow you're in this character without a client.prefs variable. Tell a dev.</span>")
return FALSE
var/datum/vore_preferences/P = client.prefs_vr
P.digestable = src.digestable
P.devourable = src.devourable
P.feeding = src.feeding
P.vore_taste = src.vore_taste
client.prefs.digestable = digestable
client.prefs.devourable = devourable
client.prefs.feeding = feeding
client.prefs.vore_taste = vore_taste
var/list/serialized = list()
for(var/belly in src.vore_organs)
for(var/belly in vore_organs)
var/obj/belly/B = belly
serialized += list(B.serialize()) //Can't add a list as an object to another list in Byond. Thanks.
P.belly_prefs = serialized
client.prefs.belly_prefs = serialized
return TRUE
@@ -310,21 +285,20 @@
// Proc for applying vore preferences, given bellies
//
/mob/living/proc/copy_from_prefs_vr()
if(!client || !client.prefs_vr)
to_chat(src,"<span class='warning'>You attempted to apply your vore prefs but somehow you're in this character without a client.prefs_vr variable. Tell a dev.</span>")
if(!client || !client.prefs)
to_chat(src,"<span class='warning'>You attempted to apply your vore prefs but somehow you're in this character without a client.prefs variable. Tell a dev.</span>")
return FALSE
vorepref_init = TRUE
var/datum/vore_preferences/P = client.prefs_vr
digestable = P.digestable
devourable = P.devourable
feeding = P.feeding
vore_taste = P.vore_taste
digestable = client.prefs.digestable
devourable = client.prefs.devourable
feeding = client.prefs.feeding
vore_taste = client.prefs.vore_taste
release_vore_contents(silent = TRUE)
vore_organs.Cut()
for(var/entry in P.belly_prefs)
QDEL_LIST(vore_organs)
for(var/entry in client.prefs.belly_prefs)
list_to_object(entry,src)
return TRUE
@@ -376,23 +350,31 @@
//
// Clearly super important. Obviously.
//
/mob/living/proc/lick(var/mob/living/tasted in oview(1))
/mob/living/proc/lick()
set name = "Lick Someone"
set category = "Vore"
set desc = "Lick someone nearby!"
if(!istype(tasted))
if(incapacitated(ignore_restraints = TRUE))
to_chat(src, "<span class='warning'>You can't do that while incapacitated.</span>")
return
if(!tasted.client?.prefs_vr.lickable)
var/list/choices
for(var/mob/living/L in view(1))
if(L != src && (!L.ckey || L.client?.prefs.lickable) && Adjacent(L))
LAZYADD(choices, L)
if(!choices)
return
if(src == stat)
var/mob/living/tasted = input(src, "Who would you like to lick? (Excluding yourself and those with the preference disabled)", "Licking") as null|anything in choices
if(QDELETED(tasted) || (tasted.ckey && !(tasted.client?.prefs.lickable)) || !Adjacent(tasted) || incapacitated(ignore_restraints = TRUE))
return
src.setClickCooldown(100)
setClickCooldown(100)
src.visible_message("<span class='warning'>[src] licks [tasted]!</span>","<span class='notice'>You lick [tasted]. They taste rather like [tasted.get_taste_message()].</span>","<b>Slurp!</b>")
visible_message("<span class='warning'>[src] licks [tasted]!</span>","<span class='notice'>You lick [tasted]. They taste rather like [tasted.get_taste_message()].</span>","<b>Slurp!</b>")
/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace)
@@ -408,3 +390,11 @@
else
taste_message += "a plain old normal [src]"
return taste_message
// Check if an object is capable of eating things, based on vore_organs
//
/proc/is_vore_predator(var/mob/living/O)
if(istype(O))
if(O.vore_organs.len > 0)
return TRUE
return FALSE
-174
View File
@@ -1,174 +0,0 @@
/*
VVVVVVVV VVVVVVVV OOOOOOOOO RRRRRRRRRRRRRRRRR EEEEEEEEEEEEEEEEEEEEEE
V::::::V V::::::V OO:::::::::OO R::::::::::::::::R E::::::::::::::::::::E
V::::::V V::::::V OO:::::::::::::OO R::::::RRRRRR:::::R E::::::::::::::::::::E
V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEEE::::E
V:::::V V:::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E::::::EEEEEEEEEE
V:::::V V:::::V O:::::O O:::::O R:::::::::::::RR E:::::::::::::::E
V:::::V V:::::V O:::::O O:::::O R::::RRRRRR:::::R E:::::::::::::::E
V:::::V V:::::V O:::::O O:::::O R::::R R:::::R E::::::EEEEEEEEEE
V:::::V:::::V O:::::O O:::::O R::::R R:::::R E:::::E
V:::::::::V O::::::O O::::::O R::::R R:::::R E:::::E EEEEEE
V:::::::V O:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEEEE:::::E
V:::::V OO:::::::::::::OO R::::::R R:::::RE::::::::::::::::::::E
V:::V OO:::::::::OO R::::::R R:::::RE::::::::::::::::::::E
VVV OOOOOOOOO RRRRRRRR RRRRRRREEEEEEEEEEEEEEEEEEEEEE
-Aro <3 */
//
// Overrides/additions to stock defines go here, as well as hooks. Sort them by
// the object they are overriding. So all /mob/living together, etc.
//
//
// The datum type bolted onto normal preferences datums for storing Vore stuff
//
#define VORE_VERSION 4
GLOBAL_LIST_EMPTY(vore_preferences_datums)
/client
var/datum/vore_preferences/prefs_vr
/datum/vore_preferences
//Actual preferences
var/digestable = FALSE
var/devourable = FALSE
var/feeding = FALSE
var/lickable = FALSE
// var/allowmobvore = TRUE
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
// var/can_be_drop_prey = FALSE
// var/can_be_drop_pred = FALSE
//Mechanically required
var/path
var/slot
var/client/client
var/client_ckey
/datum/vore_preferences/New(client/C)
if(istype(C))
client = C
client_ckey = C.ckey
load_vore()
//
// Check if an object is capable of eating things, based on vore_organs
//
/proc/is_vore_predator(var/mob/living/O)
if(istype(O,/mob/living))
if(O.vore_organs.len > 0)
return TRUE
return FALSE
//
// Belly searching for simplifying other procs
// Mostly redundant now with belly-objects and isbelly(loc)
//
/proc/check_belly(atom/movable/A)
return isbelly(A.loc)
//
// Save/Load Vore Preferences
//
/datum/vore_preferences/proc/load_path(ckey,slot,filename="character",ext="json")
if(!ckey || !slot) return
path = "data/player_saves/[ckey[1]]/[ckey]/vore/[filename][slot].[ext]"
/datum/vore_preferences/proc/load_vore()
if(!client || !client_ckey)
return FALSE //No client, how can we save?
if(!client.prefs || !client.prefs.default_slot)
return FALSE //Need to know what character to load!
slot = client.prefs.default_slot
load_path(client_ckey,slot)
if(!path) return FALSE //Path couldn't be set?
if(!fexists(path)) //Never saved before
save_vore() //Make the file first
return TRUE
var/list/json_from_file = json_decode(file2text(path))
if(!json_from_file)
return FALSE //My concern grows
var/version = json_from_file["version"]
json_from_file = patch_version(json_from_file,version)
digestable = json_from_file["digestable"]
devourable = json_from_file["devourable"]
feeding = json_from_file["feeding"]
lickable = json_from_file["lickable"]
vore_taste = json_from_file["vore_taste"]
belly_prefs = json_from_file["belly_prefs"]
//Quick sanitize
if(isnull(digestable))
digestable = FALSE
if(isnull(devourable))
devourable = FALSE
if(isnull(feeding))
feeding = FALSE
if(isnull(lickable))
lickable = FALSE
if(isnull(belly_prefs))
belly_prefs = list()
return TRUE
/datum/vore_preferences/proc/save_vore()
if(!path)
return FALSE
var/version = VORE_VERSION //For "good times" use in the future
var/list/settings_list = list(
"version" = version,
"digestable" = digestable,
"devourable" = devourable,
"feeding" = feeding,
"lickable" = lickable,
"vore_taste" = vore_taste,
"belly_prefs" = belly_prefs,
)
//List to JSON
var/json_to_file = json_encode(settings_list)
if(!json_to_file)
testing("Saving: [path] failed jsonencode")
return FALSE
//Write it out
//#ifdef RUST_G
// call(RUST_G, "file_write")(json_to_file, path)
//#else
// Fall back to using old format if we are not using rust-g
if(fexists(path))
fdel(path) //Byond only supports APPENDING to files, not replacing.
text2file(json_to_file, path)
//#endif
if(!fexists(path))
testing("Saving: [path] failed file write")
return FALSE
return TRUE
/* commented out list things
"allowmobvore" = allowmobvore,
"can_be_drop_prey" = can_be_drop_prey,
"can_be_drop_pred" = can_be_drop_pred, */
//Can do conversions here
datum/vore_preferences/proc/patch_version(var/list/json_from_file,var/version)
return json_from_file
#undef VORE_VERSION
+29 -25
View File
@@ -6,7 +6,6 @@
#define BELLIES_NAME_MIN 2
#define BELLIES_NAME_MAX 12
#define BELLIES_DESC_MAX 1024
#define FLAVOR_MAX 40
/mob/living/proc/insidePanel()
set name = "Vore Panel"
@@ -247,8 +246,8 @@
dat += "<br><a style='background:[user.digestable ? pref_on : pref_off];' href='?src=\ref[src];toggledg=1'>Toggle Digestable (Currently: [user.digestable ? "ON" : "OFF"])</a>"
dat += "<br><a style='background:[user.devourable ? pref_on : pref_off];' href='?src=\ref[src];toggledvor=1'>Toggle Devourable (Currently: [user.devourable ? "ON" : "OFF"])</a>"
dat += "<br><a style='background:[user.feeding ? pref_on : pref_off];' href='?src=\ref[src];toggledfeed=1'>Toggle Feeding (Currently: [user.feeding ? "ON" : "OFF"])</a>"
if(user.client.prefs_vr)
dat += "<br><a style='background:[user.client.prefs_vr.lickable ? pref_on : pref_off];' href='?src=\ref[src];toggledlickable=1'>Toggle Licking (Currently: [user.client.prefs_vr.lickable ? "ON" : "OFF"])</a>"
if(user.client.prefs)
dat += "<br><a style='background:[user.client.prefs.lickable ? pref_on : pref_off];' href='?src=\ref[src];toggledlickable=1'>Toggle Licking (Currently: [user.client.prefs.lickable ? "ON" : "OFF"])</a>"
//Returns the dat html to the vore_look
return dat
@@ -659,18 +658,19 @@
user.vore_selected = user.vore_organs[1]
if(href_list["saveprefs"])
if(!user.save_vore_prefs())
if(!(user.client?.prefs))
return FALSE
if(!user.client.prefs.save_character())
to_chat(user, "<span class='warning'>Belly Preferences not saved!</span>")
log_admin("Could not save vore prefs on USER: [user].")
else
to_chat(user, "<span class='notice'>Belly Preferences were saved!</span>")
log_admin("Could not save vore prefs on USER: [user].")
if(href_list["applyprefs"])
var/alert = alert("Are you sure you want to reload character slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel")
var/alert = alert("Are you sure you want to reload the current slot preferences? This will remove your current vore organs and eject their contents.","Confirmation","Reload","Cancel")
if(!alert == "Reload")
return FALSE
if(!user.apply_vore_prefs())
if(!user.copy_from_prefs_vr())
alert("ERROR: Vore preferences failed to apply!","Error")
else
to_chat(user,"<span class='notice'>Vore preferences applied from active slot!</span>")
@@ -681,13 +681,15 @@
return FALSE
new_flavor = readd_quotes(new_flavor)
if(length(new_flavor) > FLAVOR_MAX)
alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!")
if(length(new_flavor) > MAX_TASTE_LEN)
alert("Entered flavor/taste text too long. [MAX_TASTE_LEN] character limit.","Error!")
return FALSE
user.vore_taste = new_flavor
if(href_list["toggledg"])
var/choice = alert(user, "This button is for those who don't like being digested. It can make you undigestable to all mobs. Digesting you is currently: [user.digestable ? "Allowed" : "Prevented"]", "", "Allow Digestion", "Cancel", "Prevent Digestion")
if(!user || !user.client)
return
switch(choice)
if("Cancel")
return FALSE
@@ -696,11 +698,12 @@
if("Prevent Digestion")
user.digestable = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.digestable = user.digestable
user.client.prefs.digestable = user.digestable
if(href_list["toggledvor"])
var/choice = alert(user, "This button is for those who don't like vore at all. Devouring you is currently: [user.devourable ? "Allowed" : "Prevented"]", "", "Allow Devourment", "Cancel", "Prevent Devourment")
if(!user || !user.client)
return
switch(choice)
if("Cancel")
return FALSE
@@ -709,11 +712,12 @@
if("Prevent Devourment")
user.devourable = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.devourable = user.devourable
user.client.prefs.devourable = user.devourable
if(href_list["toggledfeed"])
var/choice = alert(user, "This button is to toggle your ability to be fed to others. Feeding predators is currently: [user.feeding ? "Allowed" : "Prevented"]", "", "Allow Feeding", "Cancel", "Prevent Feeding")
if(!user || !user.client)
return
switch(choice)
if("Cancel")
return FALSE
@@ -722,19 +726,19 @@
if("Prevent Feeding")
user.feeding = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.feeding = user.feeding
user.client.prefs.feeding = user.feeding
if(href_list["toggledlickable"])
if(user.client.prefs_vr)
var/choice = alert(user, "This button is to toggle your ability to be licked. Being licked is currently: [user.client.prefs_vr.lickable ? "Allowed" : "Prevented"]", "", "Allow Licking", "Cancel", "Prevent Licking")
switch(choice)
if("Cancel")
return FALSE
if("Allow Licking")
user.client.prefs_vr.lickable = TRUE
if("Prevent Licking")
user.client.prefs_vr.lickable = FALSE
var/choice = alert(user, "This button is to toggle your ability to be licked. Being licked is currently: [user.client.prefs.lickable ? "Allowed" : "Prevented"]", "", "Allow Licking", "Cancel", "Prevent Licking")
if(!user || !user.client)
return
switch(choice)
if("Cancel")
return FALSE
if("Allow Licking")
user.client.prefs.lickable = TRUE
if("Prevent Licking")
user.client.prefs.lickable = FALSE
//Refresh when interacted with, returning 1 makes vore_look.Topic update
return TRUE