Merge remote-tracking branch 'citadel/master' into shield_refactor
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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] != "*")
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user