Revert "PLASE"

This reverts commit 8af225e6e3.
This commit is contained in:
Fermi
2019-11-24 03:06:08 +00:00
parent aeb8606ce0
commit ba4fa1ef67
2145 changed files with 1387321 additions and 5257 deletions
@@ -0,0 +1,39 @@
/client/proc/citaPPoptions(mob/M) // why is this client and not /datum/admins? noone knows, in PP src == client, instead of holder. wtf.
var/body = "<br>"
if(M.client)
body += "<A href='?_src_=holder;[HrefToken()];makementor=[M.ckey]'>Make mentor</A> | "
body += "<A href='?_src_=holder;[HrefToken()];removementor=[M.ckey]'>Remove mentor</A>"
return body
/client/proc/cmd_admin_man_up(mob/M in GLOB.mob_list)
set category = "Special Verbs"
set name = "Man Up"
if(!M)
return
if(!check_rights(R_ADMIN))
return
to_chat(M, "<span class='warning bold reallybig'>Man up, and deal with it.</span><br><span class='warning big'>Move on.</span>")
M.playsound_local(M, 'sound/voice/manup.ogg', 50, FALSE, pressure_affected = FALSE)
log_admin("Man up: [key_name(usr)] told [key_name(M)] to man up")
var/message = "<span class='adminnotice'>[key_name_admin(usr)] told [key_name_admin(M)] to man up.</span>"
message_admins(message)
admin_ticket_log(M, message)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up")
/client/proc/cmd_admin_man_up_global()
set category = "Special Verbs"
set name = "Man Up Global"
if(!check_rights(R_ADMIN))
return
to_chat(world, "<span class='warning bold reallybig'>Man up, and deal with it.</span><br><span class='warning big'>Move on.</span>")
for(var/mob/M in GLOB.player_list)
M.playsound_local(M, 'sound/voice/manup.ogg', 50, FALSE, pressure_affected = FALSE)
log_admin("Man up global: [key_name(usr)] told everybody to man up")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] told everybody to man up.</span>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up Global")
@@ -0,0 +1,450 @@
//Mob vars
/mob/living
var/arousalloss = 0 //How aroused the mob is.
var/min_arousal = AROUSAL_MINIMUM_DEFAULT //The lowest this mobs arousal will get. default = 0
var/max_arousal = AROUSAL_MAXIMUM_DEFAULT //The highest this mobs arousal will get. default = 100
var/arousal_rate = AROUSAL_START_VALUE //The base rate that arousal will increase in this mob.
var/arousal_loss_rate = AROUSAL_START_VALUE //How easily arousal can be relieved for this mob.
var/canbearoused = FALSE //Mob-level disabler for arousal. Starts off and can be enabled as features are added for different mob types.
var/mb_cd_length = 5 SECONDS //5 second cooldown for masturbating because fuck spam.
var/mb_cd_timer = 0 //The timer itself
/mob/living/carbon/human
canbearoused = TRUE
var/saved_underwear = ""//saves their underwear so it can be toggled later
var/saved_undershirt = ""
var/saved_socks = ""
var/hidden_underwear = FALSE
var/hidden_undershirt = FALSE
var/hidden_socks = FALSE
//Species vars
/datum/species
var/arousal_gain_rate = AROUSAL_START_VALUE //Rate at which this species becomes aroused
var/arousal_lose_rate = AROUSAL_START_VALUE //Multiplier for how easily arousal can be relieved
var/list/cum_fluids = list("semen")
var/list/milk_fluids = list("milk")
var/list/femcum_fluids = list("femcum")
//Mob procs
/mob/living/carbon/human/proc/underwear_toggle()
set name = "Toggle undergarments"
set category = "IC"
var/confirm = input(src, "Select what part of your form to alter", "Undergarment Toggling") as null|anything in list("Top", "Bottom", "Socks", "All")
if(!confirm)
return
if(confirm == "Top")
hidden_undershirt = !hidden_undershirt
if(confirm == "Bottom")
hidden_underwear = !hidden_underwear
if(confirm == "Socks")
hidden_socks = !hidden_socks
if(confirm == "All")
var/on_off = (hidden_undershirt || hidden_underwear || hidden_socks) ? FALSE : TRUE
hidden_undershirt = on_off
hidden_underwear = on_off
hidden_socks = on_off
update_body()
/mob/living/proc/handle_arousal(times_fired)
return
/mob/living/carbon/handle_arousal(times_fired)
if(!canbearoused || !dna)
return
var/datum/species/S = dna.species
if(!S || (times_fired % 36) || !getArousalLoss() >= max_arousal)//Totally stolen from breathing code. Do this every 36 ticks.
return
var/our_loss = arousal_rate * S.arousal_gain_rate
if(HAS_TRAIT(src, TRAIT_EXHIBITIONIST) && client)
var/amt_nude = 0
for(var/obj/item/organ/genital/G in internal_organs)
if(G.is_exposed())
amt_nude++
if(amt_nude)
var/watchers = 0
for(var/mob/living/L in view(src))
if(L.client && !L.stat && !L.eye_blind && (src in view(L)))
watchers++
if(watchers)
our_loss += (amt_nude * watchers) + S.arousal_gain_rate
adjustArousalLoss(our_loss)
/mob/living/proc/getArousalLoss()
return arousalloss
/mob/living/proc/adjustArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return FALSE
arousalloss = CLAMP(arousalloss + amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/setArousalLoss(amount, updating_arousal=1)
if(status_flags & GODMODE || !canbearoused)
return FALSE
arousalloss = CLAMP(amount, min_arousal, max_arousal)
if(updating_arousal)
updatearousal()
/mob/living/proc/getPercentAroused()
var/percentage = ((100 / max_arousal) * arousalloss)
return percentage
/mob/living/proc/isPercentAroused(percentage)//returns true if the mob's arousal (measured in a percent of 100) is greater than the arg percentage.
if(!isnum(percentage) || percentage > 100 || percentage < 0)
CRASH("Provided percentage is invalid")
if(getPercentAroused() >= percentage)
return TRUE
return FALSE
//H U D//
/mob/living/proc/updatearousal()
update_arousal_hud()
/mob/living/carbon/updatearousal()
. = ..()
for(var/obj/item/organ/genital/G in internal_organs)
if(istype(G))
var/datum/sprite_accessory/S
switch(G.type)
if(/obj/item/organ/genital/penis)
S = GLOB.cock_shapes_list[G.shape]
if(/obj/item/organ/genital/testicles)
S = GLOB.balls_shapes_list[G.shape]
if(/obj/item/organ/genital/vagina)
S = GLOB.vagina_shapes_list[G.shape]
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
if(S?.alt_aroused)
G.aroused_state = isPercentAroused(G.aroused_amount)
else
G.aroused_state = FALSE
G.update_appearance()
/mob/living/proc/update_arousal_hud()
return FALSE
/mob/living/carbon/human/update_arousal_hud()
if(!client || !(hud_used?.arousal))
return FALSE
if(!canbearoused)
hud_used.arousal.icon_state = ""
return FALSE
else
var/value = FLOOR(getPercentAroused(), 10)
hud_used.arousal.icon_state = "arousal[value]"
return TRUE
/obj/screen/arousal
name = "arousal"
icon_state = "arousal0"
icon = 'modular_citadel/icons/obj/genitals/hud.dmi'
screen_loc = ui_arousal
/obj/screen/arousal/Click()
if(!isliving(usr))
return FALSE
var/mob/living/M = usr
if(M.canbearoused)
M.mob_climax()
return TRUE
else
to_chat(M, "<span class='warning'>Arousal is disabled. Feature is unavailable.</span>")
/mob/living/proc/mob_climax()//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while.
set name = "Masturbate"
set category = "IC"
if(canbearoused && !restrained() && !stat)
if(mb_cd_timer <= world.time)
//start the cooldown even if it fails
mb_cd_timer = world.time + mb_cd_length
if(getArousalLoss() >= 33)//one third of average max_arousal or greater required
visible_message("<span class='danger'>[src] starts masturbating!</span>", \
"<span class='userdanger'>You start masturbating.</span>")
if(do_after(src, 30, target = src))
visible_message("<span class='danger'>[src] relieves [p_them()]self!</span>", \
"<span class='userdanger'>You have relieved yourself.</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
setArousalLoss(min_arousal)
else
to_chat(src, "<span class='notice'>You aren't aroused enough for that.</span>")
/obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found.
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
. = reagents
else
if(linked_organ)
. = linked_organ.reagents
if(!. && !silent)
to_chat(H, "<span class='warning'>Your [name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE)
if(!G)
return
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
setArousalLoss(min_arousal)
if(!target || !R)
return
var/turfing = isturf(target)
if(spill & R.total_volume >= 5)
R.reaction(turfing ? target : target.loc, TOUCH, 1, 0)
if(!turfing)
R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1))
R.clear_reagents()
//These are various procs that we'll use later, split up for readability instead of having one, huge proc.
//For all of these, we assume the arguments given are proper and have been checked beforehand.
/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
var/obj/item/organ/genital/PP = CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) ? G.linked_organ : G
if(!PP)
to_chat(src, "<span class='warning'>You shudder, unable to cum with your [name].</span>")
if(mb_time)
visible_message("<span class='love'>[src] starts to [G.masturbation_verb] [p_their()] [G.name].</span>", \
"<span class='userlove'>You start to [G.masturbation_verb] your [G.name].</span>")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] orgasms, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with [p_their()] [PP.name]!</span>", \
"<span class='userlove'>You orgasm, [PP.orgasm_verb][isturf(loc) ? " onto [loc]" : ""] with your [PP.name].</span>")
do_climax(fluid_source, loc, G)
/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes
var/datum/reagents/fluid_source = G.climaxable(src, TRUE)
if(!fluid_source)
visible_message("<span class='danger'>[src] shudders, their [G.name] unable to cum.</span>", \
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>")
return
if(mb_time) //as long as it's not instant, give a warning
visible_message("<span class='love'>[src] looks like they're about to cum.</span>", \
"<span class='userlove'>You feel yourself about to orgasm.</span>")
if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] orgasms[isturf(loc) ? " onto [loc]" : ""], using [p_their()] [G.name]!</span>", \
"<span class='userlove'>You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].</span>")
do_climax(fluid_source, loc, G)
/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
if(mb_time) //Skip warning if this is an instant climax.
visible_message("<span class='love'>[src] is about to climax with [L]!</span>", \
"<span class='userlove'>You're about to climax with [L]!</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE))
return
if(spillage)
visible_message("<span class='love'>[src] climaxes with [L], overflowing and spilling, using [p_their()] [G.name]!</span>", \
"<span class='userlove'>You orgasm with [L], spilling out of them, using your [G.name].</span>")
else //knots and other non-spilling orgasms
visible_message("<span class='love'>[src] climaxes with [L], [p_their()] [G.name] spilling nothing!</span>", \
"<span class='userlove'>You ejaculate with [L], your [G.name] spilling nothing.</span>")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm)
do_climax(fluid_source, spillage ? loc : L, G, spillage)
/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender
var/datum/reagents/fluid_source = G.climaxable(src)
if(!fluid_source)
return
if(mb_time)
visible_message("<span class='love'>[src] starts to [G.masturbation_verb] their [G.name] over [container].</span>", \
"<span class='userlove'>You start to [G.masturbation_verb] your [G.name] over [container].</span>")
if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE))
return
visible_message("<span class='love'>[src] uses [p_their()] [G.name] to fill [container]!</span>", \
"<span class='userlove'>You used your [G.name] to fill [container].</span>")
do_climax(fluid_source, container, G, FALSE)
/mob/living/carbon/human/proc/pick_masturbate_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
for(var/obj/item/organ/genital/G in internal_organs)
if(CHECK_BITFIELD(G.genital_flags, CAN_MASTURBATE_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with
if(CHECK_BITFIELD(G.genital_flags, MASTURBATE_LINKED_ORGAN) && !G.linked_organ)
continue
LAZYADD(genitals_list, G)
if(LAZYLEN(genitals_list))
var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list
return ret_organ
else if(!silent)
to_chat(src, "<span class='warning'>You cannot masturbate without available genitals.</span>")
/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE)
var/list/genitals_list
var/list/worn_stuff = get_equipped_items()
for(var/obj/item/organ/genital/G in internal_organs)
if(CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with
LAZYADD(genitals_list, G)
if(LAZYLEN(genitals_list))
var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list
return ret_organ
else if(!silent)
to_chat(src, "<span class='warning'>You cannot climax without available genitals.</span>")
/mob/living/carbon/human/proc/pick_partner(silent = FALSE)
var/list/partners = list()
if(pulling)
partners += pulling
if(pulledby)
partners += pulledby
//Now we got both of them, let's check if they're proper
for(var/mob/living/L in partners)
if(iscarbon(L))
var/mob/living/carbon/C = L
if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed()) //Nothing through_clothing, no proper partner.
partners -= C
//NOW the list should only contain correct partners
if(!partners.len)
if(!silent)
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return //No one left.
var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null
if(target && in_range(src, target))
return target
/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE)
var/list/containers_list = list()
for(var/obj/item/reagent_containers/C in held_items)
if(C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks))
containers_list += C
for(var/obj/item/reagent_containers/C in range(1, src))
if((C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) && CanReach(C))
containers_list += C
if(containers_list.len)
var/obj/item/reagent_containers/SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list
if(SC && CanReach(SC))
return SC
else if(!silent)
to_chat(src, "<span class='warning'>You cannot do this without an appropriate container.</span>")
/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE, list/whitelist_typepaths = list(/obj/item/dildo))
if(restrained(TRUE)) //TRUE ignores grabs
if(!silent)
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
return FALSE
if(!get_num_arms() || !get_empty_held_indexes())
if(whitelist_typepaths)
if(!islist(whitelist_typepaths))
whitelist_typepaths = list(whitelist_typepaths)
for(var/path in whitelist_typepaths)
if(is_holding_item_of_type(path))
return TRUE
if(!silent)
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
return FALSE
return TRUE
//Here's the main proc itself
/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
if(mb_cd_timer > world.time)
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
to_chat(src, "<span class='warning'>You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!</span>")
return
if(!canbearoused || !has_dna())
return
if(stat == DEAD)
if(!forced_climax)
to_chat(src, "<span class='warning'>You can't do that while dead!</span>")
return
if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks
for(var/obj/item/organ/genital/G in internal_organs)
if(!CHECK_BITFIELD(G.genital_flags, CAN_CLIMAX_WITH)) //Skip things like wombs and testicles
continue
var/mob/living/partner
var/check_target
var/list/worn_stuff = get_equipped_items()
if(G.is_exposed(worn_stuff))
if(pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick
if(isliving(pulling)) //Don't fuck objects
check_target = pulling
if(pulledby && !check_target) //prioritise pulled over pulledby
if(isliving(pulledby))
check_target = pulledby
//Now we should have a partner, or else we have to come alone
if(check_target)
if(iscarbon(check_target)) //carbons can have clothes
var/mob/living/carbon/C = check_target
if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough?
partner = C
else //A cat is fine too
partner = check_target
if(partner) //Did they pass the clothing checks?
mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced
continue //You've climaxed once with this organ, continue on
//not exposed OR if no partner was found while exposed, climax alone
mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms
//Now all genitals that could climax, have.
//Since this was a forced climax, we do not need to continue with the other stuff
mb_cd_timer = world.time + mb_cd_length
return
//If we get here, then this is not a forced climax and we gotta check a few things.
if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious.
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
return
if(getArousalLoss() < 33) //flat number instead of percentage
to_chat(src, "<span class='warning'>You aren't aroused enough for that!</span>")
return
//Ok, now we check what they want to do.
var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Masturbate", "Climax alone", "Climax with partner", "Fill container")
if(!choice)
return
switch(choice)
if("Masturbate")
if(!available_rosie_palms())
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ = pick_masturbate_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_masturbate(picked_organ)
return
if("Climax alone")
if(!available_rosie_palms())
return
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
if(picked_organ && available_rosie_palms(TRUE))
mob_climax_outside(picked_organ)
if("Climax with partner")
//We need no hands, we can be restrained and so on, so let's pick an organ
var/obj/item/organ/genital/picked_organ = pick_climax_genitals()
if(picked_organ)
var/mob/living/partner = pick_partner() //Get someone
if(partner)
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No")
if(spillage && in_range(src, partner))
mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE)
if("Fill container")
//We'll need hands and no restraints.
if(!available_rosie_palms(FALSE, /obj/item/reagent_containers))
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
if(picked_organ)
//Good, got an organ, time to pick a container
var/obj/item/reagent_containers/fluid_container = pick_climax_container()
if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers))
mob_fill_container(picked_organ, fluid_container)
mb_cd_timer = world.time + mb_cd_length
@@ -0,0 +1,342 @@
/obj/item/organ/genital
color = "#fcccb3"
w_class = WEIGHT_CLASS_NORMAL
var/shape = "human"
var/sensitivity = AROUSAL_START_VALUE
var/genital_flags //see citadel_defines.dm
var/masturbation_verb = "masturbate"
var/orgasm_verb = "cumming" //present continous
var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this?
var/size = 2 //can vary between num or text, just used in icon_state strings
var/fluid_id = null
var/fluid_max_volume = 50
var/fluid_efficiency = 1
var/fluid_rate = CUM_RATE
var/fluid_mult = 1
var/aroused_state = FALSE //Boolean used in icon_state strings
var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons.
var/obj/item/organ/genital/linked_organ
var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link().
var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
/obj/item/organ/genital/Initialize(mapload, mob/living/carbon/human/H)
. = ..()
if(fluid_id)
create_reagents(fluid_max_volume)
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
reagents.add_reagent(fluid_id, fluid_max_volume)
if(H)
get_features(H)
Insert(H)
else
update()
/obj/item/organ/genital/Destroy()
if(linked_organ)
update_link(TRUE)//this should remove any other links it has
if(owner)
Remove(owner, TRUE)//this should remove references to it, so it can be GCd correctly
return ..()
/obj/item/organ/genital/proc/update(removing = FALSE)
if(QDELETED(src))
return
update_size()
update_appearance()
if(linked_organ_slot || (linked_organ && removing))
update_link(removing)
//exposure and through-clothing code
/mob/living/carbon
var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed
/obj/item/organ/genital/proc/is_exposed()
if(!owner || CHECK_BITFIELD(genital_flags, GENITAL_INTERNAL) || CHECK_BITFIELD(genital_flags, GENITAL_HIDDEN))
return FALSE
if(CHECK_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES))
return TRUE
switch(zone) //update as more genitals are added
if(BODY_ZONE_CHEST)
return owner.is_chest_exposed()
if(BODY_ZONE_PRECISE_GROIN)
return owner.is_groin_exposed()
/obj/item/organ/genital/proc/toggle_visibility(visibility)
switch(visibility)
if("Always visible")
ENABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES)
DISABLE_BITFIELD(genital_flags, GENITAL_HIDDEN)
if(!(src in owner.exposed_genitals))
owner.exposed_genitals += src
if("Hidden by clothes")
DISABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES)
DISABLE_BITFIELD(genital_flags, GENITAL_HIDDEN)
if(src in owner.exposed_genitals)
owner.exposed_genitals -= src
if("Always hidden")
DISABLE_BITFIELD(genital_flags, GENITAL_THROUGH_CLOTHES)
ENABLE_BITFIELD(genital_flags, GENITAL_HIDDEN)
if(src in owner.exposed_genitals)
owner.exposed_genitals -= src
if(ishuman(owner)) //recast to use update genitals proc
var/mob/living/carbon/human/H = owner
H.update_genitals()
/mob/living/carbon/verb/toggle_genitals()
set category = "IC"
set name = "Expose/Hide genitals"
set desc = "Allows you to toggle which genitals should show through clothes or not."
var/list/genital_list = list()
for(var/obj/item/organ/O in internal_organs)
if(isgenital(O))
var/obj/item/organ/genital/G = O
if(!CHECK_BITFIELD(G.genital_flags, GENITAL_INTERNAL))
genital_list += G
if(!genital_list.len) //There is nothing to expose
return
//Full list of exposable genitals created
var/obj/item/organ/genital/picked_organ
picked_organ = input(src, "Choose which genitalia to expose/hide", "Expose/Hide genitals", null) in genital_list
if(picked_organ)
var/picked_visibility = input(src, "Choose visibility setting", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden")
picked_organ.toggle_visibility(picked_visibility)
return
/obj/item/organ/genital/proc/modify_size(modifier, min = -INFINITY, max = INFINITY)
fluid_max_volume += modifier*2.5
fluid_rate += modifier/10
if(reagents)
reagents.maximum_volume = fluid_max_volume
return
/obj/item/organ/genital/proc/update_size()
return
/obj/item/organ/genital/proc/update_appearance()
if(!owner || owner.stat == DEAD)
aroused_state = FALSE
/obj/item/organ/genital/on_life()
if(!reagents || !owner)
return
reagents.maximum_volume = fluid_max_volume
if(fluid_id && CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION))
generate_fluid()
/obj/item/organ/genital/proc/generate_fluid()
var/amount = fluid_rate
if(!reagents.total_volume && amount < 0.1) // Apparently, 0.015 gets rounded down to zero and no reagents are created if we don't start it with 0.1 in the tank.
amount += 0.1
var/multiplier = fluid_mult
if(reagents.total_volume >= 5)
multiplier *= 0.5
if(reagents.total_volume < reagents.maximum_volume)
reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally
reagents.add_reagent(fluid_id, (amount * multiplier))//generate the cum
return TRUE
return FALSE
/obj/item/organ/genital/proc/update_link(removing = FALSE)
if(!removing && owner)
if(linked_organ)
return
linked_organ = owner.getorganslot(linked_organ_slot)
if(linked_organ)
linked_organ.linked_organ = src
linked_organ.upon_link()
upon_link()
return TRUE
else
if(linked_organ)
linked_organ.linked_organ = null
linked_organ = null
return FALSE
//post organ duo making arrangements.
/obj/item/organ/genital/proc/upon_link()
return
/obj/item/organ/genital/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE)
. = ..()
if(.)
update()
RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance)
/obj/item/organ/genital/Remove(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE)
. = ..()
if(.)
update(TRUE)
UnregisterSignal(M, COMSIG_MOB_DEATH)
//proc to give a player their genitals and stuff when they log in
/mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA
if(clean)
for(var/obj/item/organ/genital/G in internal_organs)
qdel(G)
if (NOGENITALS in dna.species.species_traits)
return
if(dna.features["has_vag"])
give_genital(/obj/item/organ/genital/vagina)
if(dna.features["has_womb"])
give_genital(/obj/item/organ/genital/womb)
if(dna.features["has_balls"])
give_genital(/obj/item/organ/genital/testicles)
if(dna.features["has_breasts"])
give_genital(/obj/item/organ/genital/breasts)
if(dna.features["has_cock"])
give_genital(/obj/item/organ/genital/penis)
/*
if(dna.features["has_ovi"])
give_genital(/obj/item/organ/genital/ovipositor)
if(dna.features["has_eggsack"])
give_genital(/obj/item/organ/genital/eggsack)
*/
/mob/living/carbon/human/proc/give_genital(obj/item/organ/genital/G)
if(!dna || (NOGENITALS in dna.species.species_traits) || getorganslot(initial(G.slot)))
return FALSE
G = new G(null, src)
return G
/obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H)
return
/datum/species/proc/genitals_layertext(layer)
switch(layer)
if(GENITALS_BEHIND_LAYER)
return "BEHIND"
if(GENITALS_FRONT_LAYER)
return "FRONT"
//procs to handle sprite overlays being applied to humans
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot)
. = ..()
if(!. && I && slot && !(slot in GLOB.no_genitals_update_slots)) //the item was successfully equipped, and the chosen slot wasn't merely storage, hands or cuffs.
update_genitals()
/mob/living/carbon/human/doUnEquip(obj/item/I, force, newloc, no_move, invdrop = TRUE)
var/no_update = FALSE
if(!I || I == l_store || I == r_store || I == s_store || I == handcuffed || I == legcuffed || get_held_index_of_item(I)) //stops storages, cuffs and held items from triggering it.
no_update = TRUE
. = ..()
if(!. || no_update)
return
update_genitals()
/mob/living/carbon/human/proc/update_genitals()
if(!QDELETED(src))
dna.species.handle_genitals(src)
//Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours.
/mob/living/carbon/human/proc/emergent_genital_call()
if(!canbearoused)
return FALSE
var/organCheck = locate(/obj/item/organ/genital) in internal_organs
var/breastCheck = getorganslot(ORGAN_SLOT_BREASTS)
var/willyCheck = getorganslot(ORGAN_SLOT_PENIS)
if(organCheck == FALSE)
if(ishuman(src) && dna.species.id == "human")
dna.features["genitals_use_skintone"] = TRUE
dna.species.use_skintones = TRUE
if(MUTCOLORS)
if(src.dna.species.fixed_mut_color)
dna.features["cock_color"] = "[dna.species.fixed_mut_color]"
dna.features["breasts_color"] = "[dna.species.fixed_mut_color]"
return
//So people who haven't set stuff up don't get rainbow surprises.
dna.features["cock_color"] = "[dna.features["mcolor"]]"
dna.features["breasts_color"] = "[dna.features["mcolor"]]"
else //If there's a new organ, make it the same colour.
if(breastCheck == FALSE)
dna.features["breasts_color"] = dna.features["cock_color"]
else if (willyCheck == FALSE)
dna.features["cock_color"] = dna.features["breasts_color"]
return TRUE
/datum/species/proc/handle_genitals(mob/living/carbon/human/H)//more like handle sadness
if(!H)//no args
CRASH("H = null")
if(!LAZYLEN(H.internal_organs) || ((NOGENITALS in species_traits) && !H.genital_override) || HAS_TRAIT(H, TRAIT_HUSK))
return
var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER)
for(var/L in relevant_layers) //Less hardcode
H.remove_overlay(L)
H.remove_overlay(GENITALS_EXPOSED_LAYER)
//start scanning for genitals
var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH]
var/list/genitals_to_add
var/list/fully_exposed
for(var/obj/item/organ/genital/G in H.internal_organs)
if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes
LAZYADD(gen_index[G.layer_index], G)
for(var/L in gen_index)
if(L) //skip nulls
LAZYADD(genitals_to_add, L)
if(!genitals_to_add)
return
//Now we added all genitals that aren't internal and should be rendered
//start applying overlays
for(var/layer in relevant_layers)
var/list/standing = list()
var/layertext = genitals_layertext(layer)
for(var/A in genitals_to_add)
var/obj/item/organ/genital/G = A
var/datum/sprite_accessory/S
var/size = G.size
var/aroused_state = G.aroused_state
switch(G.type)
if(/obj/item/organ/genital/penis)
S = GLOB.cock_shapes_list[G.shape]
if(/obj/item/organ/genital/testicles)
S = GLOB.balls_shapes_list[G.shape]
if(/obj/item/organ/genital/vagina)
S = GLOB.vagina_shapes_list[G.shape]
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
if(!S || S.icon_state == "none")
continue
var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer)
genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[aroused_state]_[layertext]"
if(S.center)
genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y)
if(use_skintones && H.dna.features["genitals_use_skintone"])
genital_overlay.color = "#[skintone2hex(H.skin_tone)]"
genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]-s_[aroused_state]_[layertext]"
else
switch(S.color_src)
if("cock_color")
genital_overlay.color = "#[H.dna.features["cock_color"]]"
if("balls_color")
genital_overlay.color = "#[H.dna.features["balls_color"]]"
if("breasts_color")
genital_overlay.color = "#[H.dna.features["breasts_color"]]"
if("vag_color")
genital_overlay.color = "#[H.dna.features["vag_color"]]"
if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES))
genital_overlay.layer = -GENITALS_EXPOSED_LAYER
LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag.
else
standing += genital_overlay
if(LAZYLEN(standing))
H.overlays_standing[layer] = standing
if(LAZYLEN(fully_exposed))
H.overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed
H.apply_overlay(GENITALS_EXPOSED_LAYER)
for(var/L in relevant_layers)
H.apply_overlay(L)
@@ -0,0 +1,151 @@
/datum/sprite_accessory
var/alt_aroused = FALSE //CIT CODE if this is TRUE, then the genitals will use an alternate icon_state when aroused.
//DICKS,COCKS,PENISES,WHATEVER YOU WANT TO CALL THEM
/datum/sprite_accessory/penis
icon = 'modular_citadel/icons/obj/genitals/penis_onmob.dmi'
name = "penis" //the preview name of the accessory
color_src = "cock_color"
alt_aroused = TRUE
/datum/sprite_accessory/penis/human
icon_state = "human"
name = "Human"
/datum/sprite_accessory/penis/knotted
icon_state = "knotted"
name = "Knotted"
/datum/sprite_accessory/penis/flared
icon_state = "flared"
name = "Flared"
/datum/sprite_accessory/penis/barbknot
icon_state = "barbknot"
name = "Barbed, Knotted"
/datum/sprite_accessory/penis/tapered
icon_state = "tapered"
name = "Tapered"
/datum/sprite_accessory/penis/tentacle
icon_state = "tentacle"
name = "Tentacled"
/datum/sprite_accessory/penis/hemi
icon_state = "hemi"
name = "Hemi"
/datum/sprite_accessory/penis/hemiknot
icon_state = "hemiknot"
name = "Knotted Hemi"
////////////////////////
// Taur cocks go here //
////////////////////////
/datum/sprite_accessory/penis/taur_flared
icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' //Needed larger width
icon_state = "flared"
name = "Taur, Flared"
center = TRUE //Center the image 'cause 2-tile wide.
dimension_x = 64
/datum/sprite_accessory/penis/taur_knotted
icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' //Needed larger width
icon_state = "knotted"
name = "Taur, Knotted"
center = TRUE //Center the image 'cause 2-tile wide.
dimension_x = 64
/datum/sprite_accessory/penis/taur_tapered
icon = 'modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi' //Needed larger width
icon_state = "tapered"
name = "Taur, Tapered"
center = TRUE //Center the image 'cause 2-tile wide.
dimension_x = 64
//Testicles
//These ones aren't inert
/datum/sprite_accessory/testicles
icon = 'modular_citadel/icons/obj/genitals/testicles_onmob.dmi'
icon_state = "testicle"
name = "testicle" //the preview name of the accessory
color_src = "balls_color"
/datum/sprite_accessory/testicles/hidden
icon_state = "none"
name = "Hidden"
/datum/sprite_accessory/testicles/single
icon_state = "single"
name = "Single"
//Vaginas
/datum/sprite_accessory/vagina
icon = 'modular_citadel/icons/obj/genitals/vagina_onmob.dmi'
icon_state = null
name = "vagina"
color_src = "vag_color"
/datum/sprite_accessory/vagina/human
icon_state = "human"
name = "Human"
alt_aroused = TRUE
/datum/sprite_accessory/vagina/tentacles
icon_state = "tentacle"
name = "Tentacle"
alt_aroused = TRUE
/datum/sprite_accessory/vagina/dentata
icon_state = "dentata"
name = "Dentata"
alt_aroused = TRUE
/datum/sprite_accessory/vagina/hairy
icon_state = "hairy"
name = "Hairy"
/datum/sprite_accessory/vagina/spade
icon_state = "spade"
name = "Spade"
/datum/sprite_accessory/vagina/furred
icon_state = "furred"
name = "Furred"
/datum/sprite_accessory/vagina/gaping
icon_state = "gaping"
name = "Gaping"
//BREASTS BE HERE
/datum/sprite_accessory/breasts
icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi'
name = "breasts"
color_src = "breasts_color"
alt_aroused = TRUE
/datum/sprite_accessory/breasts/pair
icon_state = "pair"
name = "Pair"
/datum/sprite_accessory/breasts/quad
icon_state = "quad"
name = "Quad"
/datum/sprite_accessory/breasts/sextuple
icon_state = "sextuple"
name = "Sextuple"
//OVIPOSITORS BE HERE
/datum/sprite_accessory/ovipositor
icon = 'modular_citadel/icons/obj/genitals/penis_onmob.dmi'
icon_state = null
name = "Ovipositor" //the preview name of the accessory
color_src = "cock_color"
/datum/sprite_accessory/ovipositor/knotted
icon_state = "knotted"
name = "Knotted"
@@ -0,0 +1,128 @@
/obj/item/organ/genital/breasts
name = "breasts"
desc = "Female milk producing organs."
icon_state = "breasts"
icon = 'modular_citadel/icons/obj/genitals/breasts.dmi'
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_BREASTS
size = "c" //refer to the breast_values static list below for the cups associated number values
fluid_id = "milk"
shape = "pair"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION
masturbation_verb = "massage"
orgasm_verb = "leaking"
fluid_transfer_factor = 0.5
var/static/list/breast_values = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "flat" = 0)
var/cached_size //these two vars pertain size modifications and so should be expressed in NUMBERS.
var/prev_size //former cached_size value, to allow update_size() to early return should be there no significant changes.
/obj/item/organ/genital/breasts/Initialize(mapload, mob/living/carbon/human/H)
if(!H)
cached_size = breast_values[size]
prev_size = cached_size
return ..()
/obj/item/organ/genital/breasts/update_appearance()
. = ..()
var/lowershape = lowertext(shape)
switch(lowershape)
if("pair")
desc = "You see a pair of breasts."
if("quad")
desc = "You see two pairs of breast, one just under the other."
if("sextuple")
desc = "You see three sets of breasts, running from their chest to their belly."
else
desc = "You see some breasts, they seem to be quite exotic."
if(size == "huge")
desc = "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(cached_size)]cm in diameter."
else
if (size == "flat")
desc += " They're very small and flatchested, however."
else
desc += " You estimate that they're [uppertext(size)]-cups."
if(CHECK_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION) && aroused_state)
desc += " They're leaking [fluid_id]."
var/string
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = "#[skintone2hex(H.skin_tone)]"
string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]-s"
else
color = "#[owner.dna.features["breasts_color"]]"
string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]"
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
icon_state = sanitize_text(string)
H.update_genitals()
icon_state = sanitize_text(string)
//Allows breasts to grow and change size, with sprite changes too.
//maximum wah
//Comical sizes slow you down in movement and actions.
//Rediculous sizes makes you more cumbersome.
//this is far too lewd wah
/obj/item/organ/genital/breasts/modify_size(modifier, min = -INFINITY, max = INFINITY)
var/new_value = CLAMP(cached_size + modifier, min, max)
if(new_value == cached_size)
return
prev_size = cached_size
cached_size = new_value
update()
..()
/obj/item/organ/genital/breasts/update_size()//wah
var/rounded_cached = round(cached_size)
if(cached_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!!fixed
if(owner)
to_chat(owner, "<span class='warning'>You feel your breasts shrinking away from your body as your chest flattens out.</span>")
QDEL_IN(src, 1)
return
var/enlargement = FALSE
switch(rounded_cached)
if(0) //flatchested
size = "flat"
if(1 to 8) //modest
size = breast_values[rounded_cached]
if(9 to 15) //massive
size = breast_values[rounded_cached]
enlargement = TRUE
if(16 to INFINITY) //rediculous
size = "huge"
enlargement = TRUE
if(owner)
var/status_effect = owner.has_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
if(enlargement && !status_effect)
owner.apply_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
else if(!enlargement && status_effect)
owner.remove_status_effect(STATUS_EFFECT_BREASTS_ENLARGEMENT)
if(rounded_cached < 16 && owner)//Because byond doesn't count from 0, I have to do this.
var/mob/living/carbon/human/H = owner
var/r_prev_size = round(prev_size)
if (rounded_cached > r_prev_size)
to_chat(H, "<span class='warning'>Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size)]-cup.</span>")
else if (rounded_cached < r_prev_size)
to_chat(H, "<span class='warning'>Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.</span>")
/obj/item/organ/genital/breasts/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = "#[skintone2hex(H.skin_tone)]"
else
color = "#[D.features["breasts_color"]]"
size = D.features["breasts_size"]
shape = D.features["breasts_shape"]
fluid_id = D.features["breasts_fluid"]
if(!D.features["breasts_producing"])
DISABLE_BITFIELD(genital_flags, GENITAL_FUID_PRODUCTION)
if(!isnum(size))
cached_size = breast_values[size]
else
cached_size = size
size = breast_values[size]
prev_size = cached_size
@@ -0,0 +1,14 @@
/obj/item/organ/genital/eggsack
name = "Egg sack"
desc = "An egg producing reproductive organ."
icon_state = "egg_sack"
icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
genital_flags = GENITAL_INTERNAL|GENITAL_BLACKLISTED //unimplemented
linked_organ_slot = ORGAN_SLOT_PENIS
color = null //don't use the /genital color since it already is colored
var/egg_girth = EGG_GIRTH_DEF
var/cum_mult = CUM_RATE_MULT
var/cum_rate = CUM_RATE
var/cum_efficiency = CUM_EFFICIENCY
@@ -0,0 +1,16 @@
/obj/item/organ/genital/ovipositor
name = "Ovipositor"
desc = "An egg laying reproductive organ."
icon_state = "ovi_knotted_2"
icon = 'modular_citadel/icons/obj/genitals/ovipositor.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
genital_flags = GENITAL_BLACKLISTED //unimplemented
shape = "knotted"
size = 3
layer_index = PENIS_LAYER_INDEX
var/length = 6 //inches
var/girth = 0
var/girth_ratio = COCK_GIRTH_RATIO_DEF //citadel_defines.dm for these defines
var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF
var/list/oviflags = list()
@@ -0,0 +1,101 @@
/obj/item/organ/genital/penis
name = "penis"
desc = "A male reproductive organ."
icon_state = "penis"
icon = 'modular_citadel/icons/obj/genitals/penis.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_PENIS
masturbation_verb = "stroke"
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
linked_organ_slot = ORGAN_SLOT_TESTICLES
fluid_transfer_factor = 0.5
size = 2 //arbitrary value derived from length and girth for sprites.
layer_index = PENIS_LAYER_INDEX
var/length = 6 //inches
var/prev_length = 6 //really should be renamed to prev_length
var/girth = 4.38
var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm
/obj/item/organ/genital/penis/modify_size(modifier, min = -INFINITY, max = INFINITY)
var/new_value = CLAMP(length + modifier, min, max)
if(new_value == length)
return
prev_length = length
length = CLAMP(length + modifier, min, max)
update()
..()
/obj/item/organ/genital/penis/update_size(modified = FALSE)
if(length < 0)//I don't actually know what round() does to negative numbers, so to be safe!!
if(owner)
to_chat(owner, "<span class='warning'>You feel your tallywacker shrinking away from your body as your groin flattens out!</b></span>")
QDEL_IN(src, 1)
if(linked_organ)
QDEL_IN(linked_organ, 1)
return
var/rounded_length = round(length)
var/new_size
var/enlargement = FALSE
switch(rounded_length)
if(0 to 6) //If modest size
new_size = 1
if(7 to 11) //If large
new_size = 2
if(12 to 20) //If massive
new_size = 3
if(21 to 34) //If massive and due for large effects
new_size = 3
enlargement = TRUE
if(35 to INFINITY) //If comical
new_size = 4 //no new sprites for anything larger yet
enlargement = TRUE
if(owner)
var/status_effect = owner.has_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
if(enlargement && !status_effect)
owner.apply_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
else if(!enlargement && status_effect)
owner.remove_status_effect(STATUS_EFFECT_PENIS_ENLARGEMENT)
if(linked_organ)
linked_organ.size = CLAMP(size + new_size, BALLS_SIZE_MIN, BALLS_SIZE_MAX)
linked_organ.update()
size = new_size
if(owner)
if (round(length) > round(prev_length))
to_chat(owner, "<span class='warning'>Your [pick(GLOB.gentlemans_organ_names)] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [uppertext(round(length))] inch penis.</b></span>")
else if ((round(length) < round(prev_length)) && (length > 0.5))
to_chat(owner, "<span class='warning'>Your [pick(GLOB.gentlemans_organ_names)] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [uppertext(round(length))] inch penis.</b></span>")
icon_state = sanitize_text("penis_[shape]_[size]")
girth = (length * girth_ratio)//Is it just me or is this ludicous, why not make it exponentially decay?
/obj/item/organ/genital/penis/update_appearance()
. = ..()
var/string
var/lowershape = lowertext(shape)
desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth."
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = "#[skintone2hex(H.skin_tone)]"
string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]-s"
else
color = "#[owner.dna.features["cock_color"]]"
string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]"
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
icon_state = sanitize_text(string)
H.update_genitals()
/obj/item/organ/genital/penis/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = "#[skintone2hex(H.skin_tone)]"
else
color = "#[D.features["cock_color"]]"
length = D.features["cock_length"]
girth_ratio = D.features["cock_girth_ratio"]
shape = D.features["cock_shape"]
prev_length = length
@@ -0,0 +1,72 @@
/obj/item/organ/genital/testicles
name = "testicles"
desc = "A male reproductive organ."
icon_state = "testicles"
icon = 'modular_citadel/icons/obj/genitals/testicles.dmi'
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_TESTICLES
size = BALLS_SIZE_MIN
linked_organ_slot = ORGAN_SLOT_PENIS
genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FUID_PRODUCTION
var/size_name = "average"
shape = "Single"
var/sack_size = BALLS_SACK_SIZE_DEF
fluid_id = "semen"
masturbation_verb = "massage"
layer_index = TESTICLES_LAYER_INDEX
/obj/item/organ/genital/testicles/generate_fluid()
if(!linked_organ && !update_link())
return FALSE
. = ..()
if(. && reagents.holder_full())
to_chat(owner, "Your balls finally feel full, again.")
/obj/item/organ/genital/testicles/upon_link()
size = linked_organ.size
update_size()
update_appearance()
/obj/item/organ/genital/testicles/update_size(modified = FALSE)
switch(size)
if(BALLS_SIZE_MIN)
size_name = "average"
if(BALLS_SIZE_DEF)
size_name = "enlarged"
if(BALLS_SIZE_MAX)
size_name = "engorged"
else
size_name = "nonexistant"
/obj/item/organ/genital/testicles/update_appearance()
. = ..()
desc = "You see an [size_name] pair of testicles."
if(owner)
var/string
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = "#[skintone2hex(H.skin_tone)]"
string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]-s"
else
color = "#[owner.dna.features["balls_color"]]"
string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]"
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
icon_state = sanitize_text(string)
H.update_genitals()
/obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = "#[skintone2hex(H.skin_tone)]"
else
color = "#[D.features["balls_color"]]"
sack_size = D.features["balls_sack_size"]
shape = D.features["balls_shape"]
if(D.features["balls_shape"] == "Hidden")
ENABLE_BITFIELD(genital_flags, GENITAL_INTERNAL)
fluid_id = D.features["balls_fluid"]
fluid_rate = D.features["balls_cum_rate"]
fluid_mult = D.features["balls_cum_mult"]
fluid_efficiency = D.features["balls_efficiency"]
@@ -0,0 +1,71 @@
/obj/item/organ/genital/vagina
name = "vagina"
desc = "A female reproductive organ."
icon = 'modular_citadel/icons/obj/genitals/vagina.dmi'
icon_state = ORGAN_SLOT_VAGINA
zone = BODY_ZONE_PRECISE_GROIN
slot = "vagina"
size = 1 //There is only 1 size right now
genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH
masturbation_verb = "finger"
fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS
layer_index = VAGINA_LAYER_INDEX
var/cap_length = 8//D E P T H (cap = capacity)
var/cap_girth = 12
var/cap_girth_ratio = 1.5
var/clits = 1
var/clit_diam = 0.25
var/clit_len = 0.25
var/list/vag_types = list("tentacle", "dentata", "hairy", "spade", "furred")
/obj/item/organ/genital/vagina/update_appearance()
. = ..()
var/string //Keeping this code here, so making multiple sprites for the different kinds is easier.
var/lowershape = lowertext(shape)
var/details
switch(lowershape)
if("tentacle")
details = "Its opening is lined with several tentacles and "
if("dentata")
details = "There's teeth inside it and it "
if("hairy")
details = "It has quite a bit of hair growing on it and "
if("human")
details = "It is taut with smooth skin, though without much hair and "
if("gaping")
details = "It is gaping slightly open, though without much hair and "
if("spade")
details = "It is a plush canine spade, it "
if("furred")
details = "It has neatly groomed fur around the outer folds, it "
else
details = "It has an exotic shape and "
if(aroused_state)
details += "is slick with female arousal."
else
details += "seems to be dry."
desc = "You see a vagina. [details]"
if(owner)
if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"])
if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow...
var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need.
color = "#[skintone2hex(H.skin_tone)]"
string = "vagina-s"
else
color = "#[owner.dna.features["vag_color"]]"
string = "vagina"
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
icon_state = sanitize_text(string)
H.update_genitals()
/obj/item/organ/genital/vagina/get_features(mob/living/carbon/human/H)
var/datum/dna/D = H.dna
if(D.species.use_skintones && D.features["genitals_use_skintone"])
color = "#[skintone2hex(H.skin_tone)]"
else
color = "[D.features["vag_color"]]"
shape = "[D.features["vag_shape"]]"
@@ -0,0 +1,10 @@
/obj/item/organ/genital/womb
name = "womb"
desc = "A female reproductive organ."
icon = 'modular_citadel/icons/obj/genitals/vagina.dmi'
icon_state = "womb"
zone = BODY_ZONE_PRECISE_GROIN
slot = ORGAN_SLOT_WOMB
genital_flags = GENITAL_INTERNAL|GENITAL_FUID_PRODUCTION
fluid_id = "femcum"
linked_organ_slot = ORGAN_SLOT_VAGINA
@@ -0,0 +1,460 @@
//This is the file that handles donator loadout items.
/datum/gear/pingcoderfailsafe
name = "IF YOU SEE THIS, PING A CODER RIGHT NOW!"
category = SLOT_IN_BACKPACK
path = /obj/item/bikehorn/golden
ckeywhitelist = list("This entry should never appear with this variable set.") //If it does, then that means somebody fucked up the whitelist system pretty hard
/datum/gear/donortestingbikehorn
name = "Donor item testing bikehorn"
category = SLOT_IN_BACKPACK
path = /obj/item/bikehorn
geargroupID = list("DONORTEST") //This is a list mainly for the sake of testing, but geargroupID works just fine with ordinary strings
/datum/gear/kevhorn
name = "Airhorn"
category = SLOT_IN_BACKPACK
path = /obj/item/bikehorn/airhorn
ckeywhitelist = list("kevinz000")
/datum/gear/cebusoap
name = "Cebutris' soap"
category = SLOT_IN_BACKPACK
path = /obj/item/custom/ceb_soap
ckeywhitelist = list("cebutris")
/datum/gear/kiaracloak
name = "Kiara's cloak"
category = SLOT_NECK
path = /obj/item/clothing/neck/cloak/inferno
ckeywhitelist = list("inferno707")
/datum/gear/kiaracollar
name = "Kiara's collar"
category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/inferno
ckeywhitelist = list("inferno707")
/datum/gear/kiaramedal
name = "Insignia of Steele"
category = SLOT_IN_BACKPACK
path = /obj/item/clothing/accessory/medal/steele
ckeywhitelist = list("inferno707")
/datum/gear/hheart
name = "The Hollow Heart"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/hheart
ckeywhitelist = list("inferno707")
/datum/gear/engravedzippo
name = "Engraved zippo"
category = SLOT_HANDS
path = /obj/item/lighter/gold
ckeywhitelist = list("dirtyoldharry")
/datum/gear/geisha
name = "Geisha suit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/geisha
ckeywhitelist = list("atiefling")
/datum/gear/specialscarf
name = "Special scarf"
category = SLOT_NECK
path = /obj/item/clothing/neck/scarf/zomb
ckeywhitelist = list("zombierobin")
/datum/gear/redmadcoat
name = "The Mad's labcoat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/toggle/labcoat/mad/red
ckeywhitelist = list("zombierobin")
/datum/gear/santahat
name = "Santa hat"
category = SLOT_HEAD
path = /obj/item/clothing/head/santa/fluff
ckeywhitelist = list("illotafv")
/datum/gear/reindeerhat
name = "Reindeer hat"
category = SLOT_HEAD
path = /obj/item/clothing/head/hardhat/reindeer/fluff
ckeywhitelist = list("illotafv")
/datum/gear/treeplushie
name = "Christmas tree plushie"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/tree
ckeywhitelist = list("illotafv")
/datum/gear/santaoutfit
name = "Santa costume"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/space/santa/fluff
ckeywhitelist = list("illotafv")
/datum/gear/treecloak
name = "Christmas tree cloak"
category = SLOT_NECK
path = /obj/item/clothing/neck/cloak/festive
ckeywhitelist = list("illotafv")
/datum/gear/carrotplush
name = "Carrot plushie"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/carrot
ckeywhitelist = list("improvedname")
/datum/gear/carrotcloak
name = "Carrot cloak"
category = SLOT_NECK
path = /obj/item/clothing/neck/cloak/carrot
ckeywhitelist = list("improvedname")
/datum/gear/albortorosamask
name = "Alborto Rosa mask"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/luchador/zigfie
ckeywhitelist = list("zigfie")
/datum/gear/mankini
name = "Mankini"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/mankini
ckeywhitelist = list("zigfie")
/datum/gear/pinkshoes
name = "Pink shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/pink
ckeywhitelist = list("zigfie")
/datum/gear/reecesgreatcoat
name = "Reece's Great Coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/trenchcoat/green
ckeywhitelist = list("geemiesif")
/datum/gear/russianflask
name = "Russian flask"
category = SLOT_IN_BACKPACK
path = /obj/item/reagent_containers/food/drinks/flask/russian
cost = 2
ckeywhitelist = list("slomka")
/datum/gear/stalkermask
name = "S.T.A.L.K.E.R. mask"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/gas/stalker
ckeywhitelist = list("slomka")
/datum/gear/stripedcollar
name = "Striped collar"
category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/stripe
ckeywhitelist = list("jademanique")
/datum/gear/performersoutfit
name = "Bluish performer's outfit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/singery/custom
ckeywhitelist = list("killer402402")
/datum/gear/vermillion
name = "Vermillion clothing"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/suit/vermillion
ckeywhitelist = list("fractious")
/datum/gear/AM4B
name = "Foam Force AM4-B"
category = SLOT_IN_BACKPACK
path = /obj/item/gun/ballistic/automatic/AM4B
ckeywhitelist = list("zeronetalpha")
/datum/gear/carrotsatchel
name = "Carrot Satchel"
category = SLOT_HANDS
path = /obj/item/storage/backpack/satchel/carrot
ckeywhitelist = list("improvedname")
/datum/gear/naomisweater
name = "worn black sweater"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/bb_sweater/black/naomi
ckeywhitelist = list("technicalmagi")
/datum/gear/naomicollar
name = "worn pet collar"
category = SLOT_NECK
path = /obj/item/clothing/neck/petcollar/naomi
ckeywhitelist = list("technicalmagi")
/datum/gear/gladiator
name = "Gladiator Armor"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/gladiator
ckeywhitelist = list("aroche")
/datum/gear/bloodredtie
name = "Blood Red Tie"
category = SLOT_NECK
path = /obj/item/clothing/neck/tie/bloodred
ckeywhitelist = list("kyutness")
/datum/gear/puffydress
name = "Puffy Dress"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/puffydress
ckeywhitelist = list("stallingratt")
/datum/gear/labredblack
name = "Black and Red Coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/toggle/labcoat/labredblack
ckeywhitelist = list("blakeryan", "durandalphor")
/datum/gear/torisword
name = "Rainbow Zweihander"
category = SLOT_IN_BACKPACK
path = /obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow
ckeywhitelist = list("annoymous35")
/datum/gear/darksabre
name = "Dark Sabre"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/darksabre
ckeywhitelist = list("inferno707")
datum/gear/darksabresheath
name = "Dark Sabre Sheath"
category = SLOT_IN_BACKPACK
path = /obj/item/storage/belt/sabre/darksabre
ckeywhitelist = list("inferno707")
/datum/gear/toriball
name = "Rainbow Tennis Ball"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/rainbow
ckeywhitelist = list("annoymous35")
/datum/gear/izzyball
name = "Katlin's Ball"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/tennis/rainbow/izzy
ckeywhitelist = list("izzyinbox")
/datum/gear/cloak
name = "Green Cloak"
category = SLOT_NECK
path = /obj/item/clothing/neck/cloak/green
ckeywhitelist = list("killer402402")
/datum/gear/steelflask
name = "Steel Flask"
category = SLOT_IN_BACKPACK
path = /obj/item/reagent_containers/food/drinks/flask/steel
cost = 2
ckeywhitelist = list("nik707")
/datum/gear/paperhat
name = "Paper Hat"
category = SLOT_HEAD
path = /obj/item/clothing/head/paperhat
ckeywhitelist = list("kered2")
/datum/gear/cloakce
name = "Polychromic CE Cloak"
category = SLOT_IN_BACKPACK
path = /obj/item/clothing/neck/cloak/polychromic/polyce
ckeywhitelist = list("worksbythesea", "blakeryan")
/datum/gear/ssk
name = "Stun Sword Kit"
category = SLOT_IN_BACKPACK
path = /obj/item/ssword_kit
ckeywhitelist = list("phillip458")
/datum/gear/techcoat
name = "Techomancers Labcoat"
category = SLOT_IN_BACKPACK
path = /obj/item/clothing/suit/toggle/labcoat/mad/techcoat
ckeywhitelist = list("wilchen")
/datum/gear/leechjar
name = "Jar of Leeches"
category = SLOT_IN_BACKPACK
path = /obj/item/custom/leechjar
ckeywhitelist = list("sgtryder")
/datum/gear/darkarmor
name = "Dark Armor"
category = SLOT_IN_BACKPACK
path = /obj/item/clothing/suit/armor/vest/darkcarapace
ckeywhitelist = list("inferno707")
/datum/gear/devilwings
name = "Strange Wings"
category = SLOT_NECK
path = /obj/item/clothing/neck/devilwings
ckeywhitelist = list("kitsun")
/datum/gear/flagcape
name = "US Flag Cape"
category = SLOT_IN_BACKPACK
path = /obj/item/bedsheet/custom/flagcape
ckeywhitelist = list("darnchacha")
/datum/gear/luckyjack
name = "Lucky Jackboots"
category = SLOT_IN_BACKPACK
path = /obj/item/clothing/shoes/lucky
ckeywhitelist = list("donaldtrumpthecommunist")
/datum/gear/raiqbawks
name = "Miami Boombox"
category = SLOT_HANDS
cost = 2
path = /obj/item/boombox/raiq
ckeywhitelist = list("chefferz")
/datum/gear/m41
name = "Toy M41"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/gun/m41
ckeywhitelist = list("thalverscholen")
/datum/gear/Divine_robes
name = "Divine robes"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/lunasune
ckeywhitelist = list("invader4352")
/datum/gear/gothcoat
name = "Goth Coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/gothcoat
ckeywhitelist = list("norko")
/datum/gear/corgisuit
name = "Corgi Suit"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/ian_costume
ckeywhitelist = list("cathodetherobot")
/datum/gear/sharkcloth
name = "Leon's Skimpy Outfit"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/leoskimpy
ckeywhitelist = list("spectrosis")
/datum/gear/mimemask
name = "Mime Mask"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/gas/mime
ckeywhitelist = list("pireamaineach")
/datum/gear/mimeoveralls
name = "Mime's Overalls"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/under/mimeoveralls
ckeywhitelist = list("pireamaineach")
/datum/gear/soulneck
name = "Soul Necklace"
category = SLOT_NECK
path = /obj/item/clothing/neck/undertale
ckeywhitelist = list("twilightic")
/datum/gear/frenchberet
name = "French Beret"
category = SLOT_HEAD
path = /obj/item/clothing/head/frenchberet
ckeywhitelist = list("notazoltan")
/datum/gear/zuliecloak
name = "Project: Zul-E"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/cloak/zuliecloak
ckeywhitelist = list("asky")
/datum/gear/blackredgold
name = "Black, Red, and Gold Coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/blackredgold
ckeywhitelist = list("ttbnc")
/datum/gear/fritzplush
name = "Fritz Plushie"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/mammal/dog/fritz
ckeywhitelist = list("analwerewolf")
/datum/gear/kimono
name = "Kimono"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/kimono
ckeywhitelist = list("sfox63")
/datum/gear/commjacket
name = "Dusty Commisar's Cloak"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/commjacket
ckeywhitelist = list("sadisticbatter")
/datum/gear/mw2_russian_para
name = "Russian Paratrooper Jumper"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/mw2_russian_para
ckeywhitelist = list("investigator77")
/datum/gear/longblackgloves
name = "Luna's Gauntlets"
category = SLOT_GLOVES
path = /obj/item/clothing/gloves/longblackgloves
ckeywhitelist = list("bigmanclancy")
/datum/gear/trendy_fit
name = "Trendy Fit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/trendy_fit
ckeywhitelist = list("midgetdragon")
/datum/gear/singery
name = "Yellow Performer Outfit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/singery
ckeywhitelist = list("maxlynchy")
/datum/gear/csheet
name = "NT Bedsheet"
category = SLOT_NECK
path = /obj/item/bedsheet/captain
ckeywhitelist = list("tikibomb")
/datum/gear/borgplush
name = "Robot Plush"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/borgplushie
ckeywhitelist = list("nicholaiavenicci")
/datum/gear/donorberet
name = "Atmos Beret"
category = SLOT_HEAD
path = /obj/item/clothing/head/blueberet
ckeywhitelist = list("foxystalin")
/datum/gear/donorgoggles
name = "Flight Goggles"
category = SLOT_HEAD
path = /obj/item/clothing/head/flight
ckeywhitelist = list("maxlynchy")
/datum/gear/onionneck
name = "Onion Necklace"
category = SLOT_NECK
path = /obj/item/clothing/neck/necklace/onion
ckeywhitelist = list("cdrcross")
@@ -0,0 +1,33 @@
/datum/gear/greytidestationwide
name = "Grey jumpsuit"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/color/grey
restricted_roles = list("Assistant")
/datum/gear/neetsuit
name = "D.A.B. suit"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/assu_suit
restricted_roles = list("Assistant")
cost = 2
/datum/gear/neethelm
name = "D.A.B. helmet"
category = SLOT_HEAD
path = /obj/item/clothing/head/assu_helmet
restricted_roles = list("Assistant")
cost = 2
/datum/gear/plushvar
name = "Ratvar Plushie"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/plushvar
cost = 5
restricted_roles = list("Chaplain")
/datum/gear/narplush
name = "Narsie Plushie"
category = SLOT_IN_BACKPACK
path = /obj/item/toy/plush/narplush
cost = 5
restricted_roles = list("Chaplain")
@@ -0,0 +1,59 @@
/datum/gear/laceup
name = "Laceup shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/laceup
/datum/gear/workboots
name = "Work boots"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/workboots
/datum/gear/jackboots
name = "Jackboots"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/jackboots
/datum/gear/winterboots
name = "Winter boots"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/winterboots
/datum/gear/sandals
name = "Sandals"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sandal
/datum/gear/blackshoes
name = "Black shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/black
/datum/gear/brownshoes
name = "Brown shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/brown
/datum/gear/whiteshoes
name = "White shoes"
category = SLOT_SHOES
path = /obj/item/clothing/shoes/sneakers/white
/datum/gear/gildedcuffs
name = "Gilded leg wraps"
category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps
/datum/gear/silvercuffs
name = "Silver leg wraps"
category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/silver
/datum/gear/redcuffs
name = "Red leg wraps"
category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/red
/datum/gear/bluecuffs
name = "Blue leg wraps"
category = SLOT_SHOES
path= /obj/item/clothing/shoes/wraps/blue
@@ -0,0 +1,203 @@
/datum/gear/poncho
name = "Poncho"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho
/datum/gear/ponchogreen
name = "Green poncho"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho/green
/datum/gear/ponchored
name = "Red poncho"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/poncho/red
/datum/gear/redhood
name = "Red cloak"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/cloak/david
cost = 3
/datum/gear/jacketbomber
name = "Bomber jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket
/datum/gear/jacketleather
name = "Leather jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/leather
/datum/gear/overcoatleather
name = "Leather overcoat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/leather/overcoat
/datum/gear/jacketpuffer
name = "Puffer jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/puffer
/datum/gear/vestpuffer
name = "Puffer vest"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/puffer/vest
/datum/gear/jacketlettermanbrown
name = "Brown letterman jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman
/datum/gear/jacketlettermanred
name = "Red letterman jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman_red
/datum/gear/jacketlettermanNT
name = "Nanotrasen letterman jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/letterman_nanotrasen
/datum/gear/coat
name = "Winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat
/* Commented out until it is "balanced"
/datum/gear/coat/sec
name = "Security winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/security
restricted_roles = list("Head of Security", "Warden", "Detective", "Security Officer") // Reserve it to the Security Departement
*/
/datum/gear/coat/med
name = "Medical winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/medical
restricted_roles = list("Chief Medical Officer", "Medical Doctor") // Reserve it to Medical Doctors and their boss, the Chief Medical Officer
/* Commented out until there is a Chemistry Winter Coat
/datum/gear/coat/med/chem
name = "Chemistry winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/medical/chemistry
restricted_roles = list("Chief Medical Officer", "Chemist") // Reserve it to Chemists and their boss, the Chief Medical Officer
*/
/datum/gear/coat/sci
name = "Science winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/science
restricted_roles = list("Research Director", "Scientist", "Roboticist") // Reserve it to the Science Departement
/datum/gear/coat/eng
name = "Engineering winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/engineering
restricted_roles = list("Chief Engineer", "Station Engineer") // Reserve it to Station Engineers and their boss, the Chief Engineer
/datum/gear/coat/eng/atmos
name = "Atmospherics winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/engineering/atmos
restricted_roles = list("Chief Engineer", "Atmospheric Technician") // Reserve it to Atmos Techs and their boss, the Chief Engineer
/datum/gear/coat/hydro
name = "Hydroponics winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/hydro
restricted_roles = list("Head of Personnel", "Botanist") // Reserve it to Botanists and their boss, the Head of Personnel
/datum/gear/coat/cargo
name = "Cargo winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/cargo
restricted_roles = list("Quartermaster", "Cargo Technician") // Reserve it to Cargo Techs and their boss, the Quartermaster
/datum/gear/coat/miner
name = "Mining winter coat"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/hooded/wintercoat/miner
restricted_roles = list("Quartermaster", "Shaft Miner") // Reserve it to Miners and their boss, the Quartermaster
/datum/gear/militaryjacket
name = "Military Jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/jacket/miljacket
/datum/gear/ianshirt
name = "Ian Shirt"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/ianshirt
/datum/gear/flakjack
name = "Flak Jacket"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/flakjack
cost = 2
/datum/gear/trekds9_coat
name = "DS9 Overcoat (use uniform)"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/trek/ds9
restricted_desc = "All, barring Service and Civilian"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster",
"Medical Doctor","Chemist","Virologist","Geneticist","Scientist", "Roboticist",
"Atmospheric Technician","Station Engineer","Warden","Detective","Security Officer",
"Cargo Technician", "Shaft Miner") //everyone who actually deserves a job.
//Federation jackets from movies
/datum/gear/trekcmdcap
name = "Fed (movie) uniform, Black"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/capt
restricted_roles = list("Captain","Head of Personnel")
/datum/gear/trekcmdmov
name = "Fed (movie) uniform, Red"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat
restricted_desc = "Heads of Staff and Security"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer")
/datum/gear/trekmedscimov
name = "Fed (movie) uniform, Blue"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/medsci
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Geneticist","Research Director","Scientist", "Roboticist")
/datum/gear/trekengmov
name = "Fed (movie) uniform, Yellow"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/fedcoat/eng
restricted_desc = "Engineering and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster")
/datum/gear/trekcmdcapmod
name = "Fed (Modern) uniform, White"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat
restricted_roles = list("Captain","Head of Personnel")
/datum/gear/trekcmdmod
name = "Fed (Modern) uniform, Red"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/sec
restricted_desc = "Heads of Staff and Security"
restricted_roles = list("Head of Security","Captain","Head of Personnel","Chief Engineer","Research Director","Chief Medical Officer","Quartermaster","Warden","Detective","Security Officer")
/datum/gear/trekmedscimod
name = "Fed (Modern) uniform, Blue"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/medsci
restricted_desc = "Medical and Science"
restricted_roles = list("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Geneticist","Research Director","Scientist", "Roboticist")
/datum/gear/trekengmod
name = "Fed (Modern) uniform, Yellow"
category = SLOT_WEAR_SUIT
path = /obj/item/clothing/suit/storage/fluff/modernfedcoat/eng
restricted_desc = "Engineering and Cargo"
restricted_roles = list("Chief Engineer","Atmospheric Technician","Station Engineer","Cargo Technician", "Shaft Miner", "Quartermaster")
@@ -0,0 +1,83 @@
/datum/preferences/proc/cit_character_pref_load(savefile/S)
//ipcs
S["feature_ipc_screen"] >> features["ipc_screen"]
S["feature_ipc_antenna"] >> features["ipc_antenna"]
features["ipc_screen"] = sanitize_inlist(features["ipc_screen"], GLOB.ipc_screens_list)
features["ipc_antenna"] = sanitize_inlist(features["ipc_antenna"], GLOB.ipc_antennas_list)
//Citadel
features["flavor_text"] = sanitize_text(features["flavor_text"], initial(features["flavor_text"]))
if(!features["mcolor2"] || features["mcolor"] == "#000")
features["mcolor2"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
if(!features["mcolor3"] || features["mcolor"] == "#000")
features["mcolor3"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
features["mcolor2"] = sanitize_hexcolor(features["mcolor2"], 3, 0)
features["mcolor3"] = sanitize_hexcolor(features["mcolor3"], 3, 0)
//gear loadout
var/text_to_load
S["loadout"] >> text_to_load
var/list/saved_loadout_paths = splittext(text_to_load, "|")
LAZYCLEARLIST(chosen_gear)
gear_points = initial(gear_points)
for(var/i in saved_loadout_paths)
var/datum/gear/path = text2path(i)
if(path)
LAZYADD(chosen_gear, path)
gear_points -= initial(path.cost)
/datum/preferences/proc/cit_character_pref_save(savefile/S)
//ipcs
WRITE_FILE(S["feature_ipc_screen"], features["ipc_screen"])
WRITE_FILE(S["feature_ipc_antenna"], features["ipc_antenna"])
//Citadel
WRITE_FILE(S["feature_genitals_use_skintone"], features["genitals_use_skintone"])
WRITE_FILE(S["feature_mcolor2"], features["mcolor2"])
WRITE_FILE(S["feature_mcolor3"], features["mcolor3"])
WRITE_FILE(S["feature_mam_body_markings"], features["mam_body_markings"])
WRITE_FILE(S["feature_mam_tail"], features["mam_tail"])
WRITE_FILE(S["feature_mam_ears"], features["mam_ears"])
WRITE_FILE(S["feature_mam_tail_animated"], features["mam_tail_animated"])
WRITE_FILE(S["feature_taur"], features["taur"])
WRITE_FILE(S["feature_mam_snouts"], features["mam_snouts"])
//Xeno features
WRITE_FILE(S["feature_xeno_tail"], features["xenotail"])
WRITE_FILE(S["feature_xeno_dors"], features["xenodorsal"])
WRITE_FILE(S["feature_xeno_head"], features["xenohead"])
//cock features
WRITE_FILE(S["feature_has_cock"], features["has_cock"])
WRITE_FILE(S["feature_cock_shape"], features["cock_shape"])
WRITE_FILE(S["feature_cock_color"], features["cock_color"])
WRITE_FILE(S["feature_cock_length"], features["cock_length"])
WRITE_FILE(S["feature_cock_girth"], features["cock_girth"])
WRITE_FILE(S["feature_has_sheath"], features["sheath_color"])
//balls features
WRITE_FILE(S["feature_has_balls"], features["has_balls"])
WRITE_FILE(S["feature_balls_color"], features["balls_color"])
WRITE_FILE(S["feature_balls_size"], features["balls_size"])
WRITE_FILE(S["feature_balls_shape"], features["balls_shape"])
WRITE_FILE(S["feature_balls_sack_size"], features["balls_sack_size"])
WRITE_FILE(S["feature_balls_fluid"], features["balls_fluid"])
//breasts features
WRITE_FILE(S["feature_has_breasts"], features["has_breasts"])
WRITE_FILE(S["feature_breasts_size"], features["breasts_size"])
WRITE_FILE(S["feature_breasts_shape"], features["breasts_shape"])
WRITE_FILE(S["feature_breasts_color"], features["breasts_color"])
WRITE_FILE(S["feature_breasts_fluid"], features["breasts_fluid"])
WRITE_FILE(S["feature_breasts_producing"], features["breasts_producing"])
//vagina features
WRITE_FILE(S["feature_has_vag"], features["has_vag"])
WRITE_FILE(S["feature_vag_shape"], features["vag_shape"])
WRITE_FILE(S["feature_vag_color"], features["vag_color"])
//womb features
WRITE_FILE(S["feature_has_womb"], features["has_womb"])
//flavor text
WRITE_FILE(S["feature_flavor_text"], features["flavor_text"])
//gear loadout
if(islist(chosen_gear))
if(chosen_gear.len)
var/text_to_save = chosen_gear.Join("|")
S["loadout"] << text_to_save
else
S["loadout"] << "" //empty string to reset the value
@@ -0,0 +1,44 @@
/obj/item/clothing/glasses/phantomthief
name = "suspicious paper mask"
desc = "A cheap, Syndicate-branded paper face mask. They'll never see it coming."
alternate_worn_icon = 'icons/mob/mask.dmi'
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "s-ninja"
item_state = "s-ninja"
/obj/item/clothing/glasses/phantomthief/ComponentInitialize()
. = ..()
AddComponent(/datum/component/wearertargeting/phantomthief)
/obj/item/clothing/glasses/phantomthief/syndicate
name = "suspicious plastic mask"
desc = "A cheap, bulky, Syndicate-branded plastic face mask. You have to break in to break out."
var/nextadrenalinepop
/obj/item/clothing/glasses/phantomthief/syndicate/examine(mob/user)
. = ..()
if(user.get_item_by_slot(SLOT_GLASSES) == src)
if(world.time >= nextadrenalinepop)
to_chat(user, "<span class='notice'>The built-in adrenaline injector is ready for use.</span>")
else
to_chat(user, "<span class='notice'>[DisplayTimeText(nextadrenalinepop - world.time)] left before the adrenaline injector can be used again.")
/obj/item/clothing/glasses/phantomthief/syndicate/proc/injectadrenaline(mob/user, combatmodestate)
if(istype(user) && combatmodestate && world.time >= nextadrenalinepop)
nextadrenalinepop = world.time + 5 MINUTES
user.reagents.add_reagent("syndicateadrenals", 5)
user.playsound_local(user, 'sound/misc/adrenalinject.ogg', 100, 0, pressure_affected = FALSE)
/obj/item/clothing/glasses/phantomthief/syndicate/equipped(mob/user, slot)
. = ..()
if(!istype(user))
return
if(slot != SLOT_GLASSES)
return
RegisterSignal(user, COMSIG_COMBAT_TOGGLED, .proc/injectadrenaline)
/obj/item/clothing/glasses/phantomthief/syndicate/dropped(mob/user)
. = ..()
if(!istype(user))
return
UnregisterSignal(user, COMSIG_COMBAT_TOGGLED)
@@ -0,0 +1,23 @@
/datum/action/item_action/zanderlocket
name = "Activate the locket"
/obj/item/clothing/neck/undertale
name = "Sylphaen Heart Locket"
desc = "A heart shaped locket...The name: 'Zander Sylphaen is inscribed on the front. Something about this necklace fills you with determination."
icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
item_state = "undertale"
icon_state = "undertale"
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/necks.dmi'
resistance_flags = FIRE_PROOF
actions_types = list(/datum/action/item_action/zanderlocket)
var/toggled = FALSE
var/obj/effect/heart/heart
/datum/action/item_action/zanderlocket/Trigger()
new/obj/effect/temp_visual/souldeath(owner.loc, owner)
playsound(owner, 'sound/misc/souldeath.ogg', 100, FALSE)
/obj/item/clothing/neck/undertale/Initialize()
..()
AddComponent(/datum/component/souldeath/neck)
@@ -0,0 +1,511 @@
//For custom items.
// Unless there's a digitigrade version make sure you add mutantrace_variation = NO_MUTANTRACE_VARIATION to all clothing/under and shoes - Pooj
// Digitigrade stuff is uniform_digi.dmi and digishoes.dmi in modular_citadel/icons/mob
/obj/item/custom/ceb_soap
name = "Cebutris' Soap"
desc = "A generic bar of soap that doesn't really seem to work right."
gender = PLURAL
icon = 'icons/obj/custom.dmi'
icon_state = "cebu"
w_class = WEIGHT_CLASS_TINY
item_flags = NOBLUDGEON
/obj/item/soap/cebu //real versions, for admin shenanigans. Adminspawn only
desc = "A bright blue bar of soap that smells of wolves"
icon = 'icons/obj/custom.dmi'
icon_state = "cebu"
/obj/item/soap/cebu/fast //speedyquick cleaning version. Still not as fast as Syndiesoap. Adminspawn only.
cleanspeed = 15
/obj/item/clothing/neck/cloak/inferno
name = "Kiara's Cloak"
desc = "The design on this seems a little too familiar."
icon = 'icons/obj/custom.dmi'
icon_state = "infcloak"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "infcloak"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/clothing/neck/petcollar/inferno
name = "Kiara's Collar"
desc = "A soft black collar that seems to stretch to fit whoever wears it."
icon = 'icons/obj/custom.dmi'
icon_state = "infcollar"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "infcollar"
item_color = null
tagname = null
/obj/item/clothing/accessory/medal/steele
name = "Insignia Of Steele"
desc = "An intricate pendant given to those who help a key member of the Steele Corporation."
icon = 'icons/obj/custom.dmi'
icon_state = "steele"
item_color = "steele"
medaltype = "medal-silver"
/obj/item/toy/darksabre
name = "Kiara's Sabre"
desc = "This blade looks as dangerous as its owner."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "darksabre"
item_state = "darksabre"
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
attack_verb = list("attacked", "struck", "hit")
/obj/item/toy/darksabre/get_belt_overlay()
return mutable_appearance('icons/obj/custom.dmi', "darksheath-darksabre")
/obj/item/toy/darksabre/get_worn_belt_overlay(icon_file)
return mutable_appearance(icon_file, "darksheath-darksabre")
/obj/item/storage/belt/sabre/darksabre
name = "Ornate Sheathe"
desc = "An ornate and rather sinister looking sabre sheathe."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "darksheath"
item_state = "darksheath"
fitting_swords = list(/obj/item/toy/darksabre)
starting_sword = /obj/item/toy/darksabre
/obj/item/clothing/suit/armor/vest/darkcarapace
name = "Dark Armor"
desc = "A dark, non-functional piece of armor sporting a red and black finish."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "darkcarapace"
item_state = "darkcarapace"
blood_overlay_type = "armor"
dog_fashion = /datum/dog_fashion/back
mutantrace_variation = NO_MUTANTRACE_VARIATION
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/lighter/gold
name = "\improper Engraved Zippo"
desc = "A shiny and relatively expensive zippo lighter. There's a small etched in verse on the bottom that reads, 'No Gods, No Masters, Only Man.'"
icon = 'icons/obj/custom.dmi'
icon_state = "gold_zippo"
item_state = "gold_zippo"
w_class = WEIGHT_CLASS_TINY
flags_1 = CONDUCT_1
slot_flags = SLOT_BELT
heat = 1500
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
/obj/item/clothing/neck/scarf/zomb
name = "A special scarf"
icon = 'icons/obj/custom.dmi'
icon_state = "zombscarf"
desc = "A fashionable collar"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_color = "zombscarf"
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/suit/toggle/labcoat/mad/red
name = "\improper The Mad's labcoat"
desc = "An oddly special looking coat."
icon = 'icons/obj/custom.dmi'
icon_state = "labred"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "labred"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/toggle/labcoat/labredblack
name = "Black and Red Coat"
desc = "An oddly special looking coat."
icon = 'icons/obj/custom.dmi'
icon_state = "labredblack"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "labredblack"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/toy/plush/carrot
name = "carrot plushie"
desc = "While a normal carrot would be good for your eyes, this one seems a bit more for hugging then eating."
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state = "carrot"
item_state = "carrot"
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("slapped")
resistance_flags = FLAMMABLE
squeak_override = list('sound/items/bikehorn.ogg'= 1)
/obj/item/clothing/neck/cloak/carrot
name = "carrot cloak"
desc = "A cloak in the shape and color of a carrot!"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "carrotcloak"
item_state = "carrotcloak"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/storage/backpack/satchel/carrot
name = "carrot satchel"
desc = "An satchel that is designed to look like an carrot"
icon = 'icons/obj/custom.dmi'
icon_state = "satchel_carrot"
item_state = "satchel_carrot"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
/obj/item/storage/backpack/satchel/carrot/Initialize()
. = ..()
AddComponent(/datum/component/squeak, list('sound/items/toysqueak1.ogg'=1), 50)
/obj/item/toy/plush/tree
name = "christmass tree plushie"
desc = "A festive plush that squeeks when you squeeze it!"
icon = 'icons/obj/custom.dmi'
icon_state = "pine_c"
item_state = "pine_c"
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("slapped")
resistance_flags = FLAMMABLE
squeak_override = list('sound/misc/server-ready.ogg'= 1)
/obj/item/clothing/neck/cloak/festive
name = "Celebratory Cloak of Morozko"
desc = " It probably will protect from snow, charcoal or elves."
icon = 'icons/obj/custom.dmi'
icon_state = "festive"
item_state = "festive"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/clothing/mask/luchador/zigfie
name = "Alboroto Rosa mask"
icon = 'icons/obj/custom.dmi'
icon_state = "lucharzigfie"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "lucharzigfie"
/obj/item/clothing/head/hardhat/reindeer/fluff
name = "novelty reindeer hat"
desc = "Some fake antlers and a very fake red nose - Sponsored by PWR Game(tm)"
icon_state = "hardhat0_reindeer"
item_state = "hardhat0_reindeer"
item_color = "reindeer"
flags_inv = 0
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0)
brightness_on = 0 //luminosity when on
dynamic_hair_suffix = ""
/obj/item/clothing/head/santa/fluff
name = "santa's hat"
desc = "On the first day of christmas my employer gave to me! - From Vlad with Salad"
icon_state = "santahatnorm"
item_state = "that"
dog_fashion = /datum/dog_fashion/head/santa
//Removed all of the space flags from this suit so it utilizes nothing special.
/obj/item/clothing/suit/space/santa/fluff
name = "Santa's suit"
desc = "Festive!"
icon_state = "santa"
item_state = "santa"
slowdown = 0
/obj/item/clothing/mask/hheart
name = "The Hollow heart"
desc = "Sometimes things are too much to hide."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "hheart"
item_state = "hheart"
flags_inv = HIDEFACE|HIDEFACIALHAIR
/obj/item/clothing/suit/trenchcoat/green
name = "Reece's Great Coat"
desc = "You would swear this was in your nightmares after eating too many veggies."
icon = 'icons/obj/custom.dmi'
icon_state = "hos-g"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "hos-g"
body_parts_covered = CHEST|GROIN|ARMS|LEGS
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/reagent_containers/food/drinks/flask/russian
name = "russian flask"
desc = "Every good russian spaceman knows it's a good idea to bring along a couple of pints of whiskey wherever they go."
icon = 'icons/obj/custom.dmi'
icon_state = "russianflask"
volume = 60
/obj/item/clothing/mask/gas/stalker
name = "S.T.A.L.K.E.R. mask"
desc = "Smells like reactor four."
icon = 'icons/obj/custom.dmi'
item_state = "stalker"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "stalker"
/obj/item/reagent_containers/food/drinks/flask/steel
name = "The End"
desc = "A plain steel flask, sealed by lock and key. The front is inscribed with The End."
icon = 'icons/obj/custom.dmi'
icon_state = "steelflask"
volume = 60
/obj/item/clothing/neck/petcollar/stripe //don't really wear this though please c'mon seriously guys
name = "collar"
desc = "It's a collar..."
icon = 'icons/obj/custom.dmi'
icon_state = "petcollar-stripe"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "petcollar-stripe"
tagname = null
/obj/item/clothing/under/singery/custom
name = "bluish performer's outfit"
desc = "Just looking at this makes you want to sing."
icon = 'icons/obj/custom.dmi'
icon_state = "singer"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "singer"
item_color = "singer"
fitted = NO_FEMALE_UNIFORM
alternate_worn_layer = ABOVE_SHOES_LAYER
can_adjust = 0
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/shoes/sneakers/pink
icon = 'icons/obj/custom.dmi'
icon_state = "pink"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "pink"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/neck/tie/bloodred
name = "Blood Red Tie"
desc = "A neosilk clip-on tie. This one has a black S on the tipping and looks rather unique."
icon = 'icons/obj/custom.dmi'
icon_state = "bloodredtie"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
/obj/item/clothing/suit/puffydress
name = "Puffy Dress"
desc = "A formal puffy black and red Victorian dress."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "puffydress"
item_state = "puffydress"
body_parts_covered = CHEST|GROIN|LEGS
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/vermillion
name = "vermillion clothing"
desc = "Some clothing."
icon_state = "vermillion"
item_state = "vermillion"
body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/bb_sweater/black/naomi
name = "worn black sweater"
mutantrace_variation = NO_MUTANTRACE_VARIATION
desc = "A well-loved sweater, showing signs of several cleanings and re-stitchings. And a few stains. Is that cat fur?"
/obj/item/clothing/neck/petcollar/naomi
name = "worn pet collar"
desc = "a pet collar that looks well used."
/obj/item/clothing/neck/cloak/green
name = "Generic Green Cloak"
desc = "This cloak doesn't seem too special."
icon = 'icons/obj/custom.dmi'
icon_state = "wintergreencloak"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "wintergreencloak"
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
/obj/item/clothing/head/paperhat
name = "paperhat"
desc = "A piece of paper folded into neat little hat."
icon_state = "paperhat"
item_state = "paperhat"
/obj/item/clothing/suit/toggle/labcoat/mad/techcoat
name = "Techomancers Labcoat"
desc = "An oddly special looking coat."
icon = 'icons/obj/custom.dmi'
icon_state = "rdcoat"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
item_state = "rdcoat"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/custom/leechjar
name = "Jar of Leeches"
desc = "A dubious cure-all. The cork seems to be sealed fairly well, and the glass impossible to break."
icon = 'icons/obj/custom.dmi'
icon_state = "leechjar"
item_state = "leechjar"
/obj/item/clothing/neck/devilwings
name = "Strange Wings"
desc = "These strange wings look like they once attached to something... or someone...? Whatever the case, their presence makes you feel uneasy.."
icon = 'icons/obj/custom.dmi'
icon_state = "devilwings"
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/devilwings64x64.dmi'
item_state = "devilwings"
worn_x_dimension = 64
worn_y_dimension = 34
/obj/item/bedsheet/custom/flagcape
name = "Flag Cape"
desc = "A truly patriotic form of heroic attire."
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "flagcape"
item_state = "flagcape"
/obj/item/clothing/shoes/lucky
name = "Lucky Jackboots"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
desc = "Comfy Lucky Jackboots with the word Luck on them."
item_state = "luckyjack"
icon_state = "luckyjack"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/lunasune
name = "Divine Robes"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
desc = "Heavenly robes of the kitsune Luna Pumpkin,you can feel radiance coming from them."
item_state = "Divine_robes"
icon_state = "Divine_robes"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/leoskimpy
name = "Leon's Skimpy Outfit"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
desc = "A rather skimpy outfit."
item_state = "shark_cloth"
icon_state = "shark_cloth"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/mimeoveralls
name = "Mime's Overalls"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
desc = "A less-than-traditional mime's attire, completed by a set of dorky-looking overalls."
item_state = "moveralls"
icon_state = "moveralls"
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/hooded/cloak/zuliecloak
name = "Project: Zul-E"
desc = "A standard version of a prototype cloak given out by Nanotrasen higher ups. It's surprisingly thick and heavy for a cloak despite having most of it's tech stripped. It also comes with a bluespace trinket which calls it's accompanying hat onto the user. A worn inscription on the inside of the cloak reads 'Fleuret' ...the rest is faded away."
icon_state = "zuliecloak"
item_state = "zuliecloak"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
hoodtype = /obj/item/clothing/head/hooded/cloakhood/zuliecloak
body_parts_covered = CHEST|GROIN|ARMS
slot_flags = SLOT_WEAR_SUIT | ITEM_SLOT_NECK //it's a cloak. it's cosmetic. so why the hell not? what could possibly go wrong?
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/head/hooded/cloakhood/zuliecloak
name = "NT Special Issue"
desc = "This hat is unquestionably the best one, bluespaced to and from CentComm. It smells of Fish and Tea with a hint of antagonism"
icon_state = "zuliecap"
item_state = "zuliecap"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
flags_inv = HIDEEARS|HIDEHAIR
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/blackredgold
name = "Multicolor Coat"
desc = "An oddly special looking coat with black, red, and gold"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "redgoldjacket"
item_state = "redgoldjacket"
body_parts_covered = CHEST|GROIN|LEGS|ARMS
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/kimono
name = "Blue Kimono"
desc = "A traditional kimono, this one is blue with purple flowers."
icon_state = "kimono"
item_state = "kimono"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
body_parts_covered = CHEST|GROIN|LEGS|ARMS
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/suit/commjacket
name = "Dusty Commisar's Cloak"
desc = "An Imperial Commisar's Coat, straight from the frontline of battle, filled with dirt, bulletholes, and dozens of little pockets. Alongside a curious golden eagle sitting on it's left breast, the marking '200th Venoland' is clearly visible on the inner workings of the coat. It certainly holds an imposing flair, however."
icon_state = "commjacket"
item_state = "commjacket"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
body_parts_covered = CHEST|GROIN|LEGS|ARMS
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/under/mw2_russian_para
name = "Russian Paratrooper Jumper"
desc = "A Russian made old paratrooper jumpsuit, has many pockets for easy storage of gear from a by gone era. As bulky as it looks, its shockingly light!"
icon_state = "mw2_russian_para"
item_state = "mw2_russian_para"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/gloves/longblackgloves
name = "Luna's Gauntlets"
desc = "These gloves seem to have a coating of slime fluid on them, you should possibly return them to their rightful owner."
icon_state = "longblackgloves"
item_state = "longblackgloves"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
/obj/item/clothing/under/trendy_fit
name = "Trendy Fitting Clothing"
desc = "An outfit straight from the boredom of space, its the type of thing only someone trying to entertain themselves on the way to their next destination would wear."
icon_state = "trendy_fit"
item_state = "trendy_fit"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
mutantrace_variation = NO_MUTANTRACE_VARIATION
/obj/item/clothing/head/blueberet
name = "Atmos Beret"
desc = "A fitted beret designed to be worn by Atmos Techs."
icon_state = "blueberet"
item_state = "blueberet"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
/obj/item/clothing/head/flight
name = "flight goggles"
desc = "Old style flight goggles with a leather cap attached."
icon_state = "flight-g"
item_state = "flight-g"
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
/obj/item/clothing/neck/necklace/onion
name = "Onion Necklace"
desc = "A string of onions sequenced together to form a necklace."
icon = 'icons/obj/custom.dmi'
icon_state = "onion"
item_state = "onion"
alternate_worn_icon = 'icons/mob/custom_w.dmi'
@@ -0,0 +1,12 @@
GLOBAL_LIST_INIT(mentor_verbs, list(
/client/proc/cmd_mentor_say,
/client/proc/show_mentor_memo
))
GLOBAL_PROTECT(mentor_verbs)
/client/proc/add_mentor_verbs()
if(mentor_datum)
verbs += GLOB.mentor_verbs
/client/proc/remove_mentor_verbs()
verbs -= GLOB.mentor_verbs
@@ -0,0 +1,83 @@
/mob/living/carbon
var/combatmode = FALSE //literally lifeweb
var/lastmousedir
var/wrongdirmovedelay
var/lastdirchange
var/combatmessagecooldown
//oh no vore time
var/voremode = FALSE
/mob/living/carbon/CanPass(atom/movable/mover, turf/target)
. = ..()
if(.)
var/mob/living/mobdude = mover
if(istype(mobdude))
if(!resting && mobdude.resting)
if(!(mobdude.pass_flags & PASSMOB))
return FALSE
return .
/mob/living/carbon/proc/toggle_combat_mode(forced)
if(recoveringstam)
return TRUE
if(!forced)
for(var/datum/status_effect/S in status_effects)
if(S.blocks_combatmode)
return TRUE
combatmode = !combatmode
if(voremode)
toggle_vore_mode()
if(combatmode)
playsound_local(src, 'sound/misc/ui_toggle.ogg', 50, FALSE, pressure_affected = FALSE) //Sound from interbay!
else
playsound_local(src, 'sound/misc/ui_toggleoff.ogg', 50, FALSE, pressure_affected = FALSE) //Slightly modified version of the above!
if(client)
client.show_popup_menus = !combatmode // So we can right-click for alternate actions and all that other good shit. Also moves examine to shift+rightclick to make it possible to attack while sprinting
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/combattoggle/selector in hud_used.static_inventory)
selector.rebasetointerbay(src)
if(world.time >= combatmessagecooldown && combatmode)
if(a_intent != INTENT_HELP)
visible_message("<span class='warning'>[src] [resting ? "tenses up" : (prob(95)? "drops into a combative stance" : (prob(95)? "poses aggressively" : "asserts dominance with their pose"))].</span>")
else
visible_message("<span class='notice'>[src] [pick("looks","seems","goes")] [pick("alert","attentive","vigilant")].</span>")
combatmessagecooldown = 10 SECONDS + world.time //This is set 100% of the time to make sure squeezing regen out of process cycles doesn't result in the combat mode message getting spammed
SEND_SIGNAL(src, COMSIG_COMBAT_TOGGLED, src, combatmode)
return TRUE
mob/living/carbon/proc/toggle_vore_mode()
voremode = !voremode
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/voretoggle/selector in hud_used.static_inventory)
selector.rebaseintomygut(src)
if(combatmode)
return FALSE //let's not override the main draw of the game these days
SEND_SIGNAL(src, COMSIG_VORE_TOGGLED, src, voremode)
return TRUE
/mob/living/carbon/Move(atom/newloc, direct = 0)
var/currentdirection = dir
. = ..()
wrongdirmovedelay = FALSE
if(combatmode && client && lastmousedir)
if(lastmousedir != dir)
wrongdirmovedelay = TRUE
setDir(lastmousedir, ismousemovement = TRUE)
if(currentdirection != dir)
lastdirchange = world.time
/mob/living/carbon/onMouseMove(object, location, control, params)
if(!combatmode)
return
mouse_face_atom(object)
lastmousedir = dir
/mob/living/carbon/setDir(newdir, ismousemovement = FALSE)
if(!combatmode || ismousemovement)
if(dir != newdir)
lastdirchange = world.time
. = ..()
else
return
@@ -0,0 +1,28 @@
/mob/living/proc/resist_embedded()
return
/mob/living/carbon/human/resist_embedded()
if(handcuffed || legcuffed || (wear_suit && wear_suit.breakouttime))
return
if(canmove && !on_fire)
for(var/obj/item/bodypart/L in bodyparts)
if(istype(L) && L.embedded_objects.len)
for(var/obj/item/I in L.embedded_objects)
if(istype(I) && I.w_class >= WEIGHT_CLASS_NORMAL) //minimum weight class to insta-ripout via resist
remove_embedded_unsafe(L, I, src, 1.5) //forcefully call the remove embedded unsafe proc but with extra pain multiplier. if you want to remove it less painfully, examine and remove it carefully.
return TRUE //Hands are occupied
return
/mob/living/carbon/human/proc/remove_embedded_unsafe(obj/item/bodypart/L, obj/item/I, mob/user, painmul = 1)
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
return
L.embedded_objects -= I
L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class*painmul)//It hurts to rip it out, get surgery you dingus. And if you're ripping it out quickly via resist, it's gonna hurt even more
I.forceMove(get_turf(src))
user.put_in_hands(I)
user.emote("scream")
user.visible_message("[user] rips [I] out of [user.p_their()] [L.name]!","<span class='notice'>You remove [I] from your [L.name].</span>")
if(!has_embedded_objects())
clear_alert("embeddedobject")
SEND_SIGNAL(user, COMSIG_CLEAR_MOOD_EVENT, "embedded")
return
@@ -0,0 +1,37 @@
/mob/living/carbon/human
var/sprinting = FALSE
/mob/living/carbon/human/Move(NewLoc, direct)
var/oldpseudoheight = pseudo_z_axis
. = ..()
if(. && sprinting && !(movement_type & FLYING) && canmove && !resting && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby)
doSprintLossTiles(1)
if((oldpseudoheight - pseudo_z_axis) >= 8)
to_chat(src, "<span class='warning'>You trip off of the elevated surface!</span>")
for(var/obj/item/I in held_items)
accident(I)
Knockdown(80)
/mob/living/carbon/human/movement_delay()
. = 0
if(!resting && m_intent == MOVE_INTENT_RUN && !sprinting)
. += 1
if(wrongdirmovedelay)
. += 1
. += ..()
/mob/living/carbon/human/proc/togglesprint() // If you call this proc outside of hotkeys or clicking the HUD button, I'll be disappointed in you.
sprinting = !sprinting
if(!resting && m_intent == MOVE_INTENT_RUN && canmove)
if(sprinting)
playsound_local(src, 'sound/misc/sprintactivate.ogg', 50, FALSE, pressure_affected = FALSE)
else
playsound_local(src, 'sound/misc/sprintdeactivate.ogg', 50, FALSE, pressure_affected = FALSE)
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
return TRUE
/mob/living/carbon/human/proc/sprint_hotkey(targetstatus)
if(targetstatus ? !sprinting : sprinting)
togglesprint()
@@ -0,0 +1,132 @@
/mob/living
var/recoveringstam = FALSE
var/incomingstammult = 1
var/bufferedstam = 0
var/stambuffer = 20
var/stambufferregentime
var/attemptingstandup = FALSE
var/intentionalresting = FALSE
var/attemptingcrawl = FALSE
//Sprint buffer---
var/sprint_buffer = 42 //Tiles
var/sprint_buffer_max = 42
var/sprint_buffer_regen_ds = 0.3 //Tiles per world.time decisecond
var/sprint_buffer_regen_last = 0 //last world.time this was regen'd for math.
var/sprint_stamina_cost = 0.70 //stamina loss per tile while insufficient sprint buffer.
//---End
/mob/living/movement_delay(ignorewalk = 0)
. = ..()
if(resting)
. += 6
/atom
var/pseudo_z_axis
/atom/proc/get_fake_z()
return pseudo_z_axis
/obj/structure/table
pseudo_z_axis = 8
/turf/open/get_fake_z()
var/objschecked
for(var/obj/structure/structurestocheck in contents)
objschecked++
if(structurestocheck.pseudo_z_axis)
return structurestocheck.pseudo_z_axis
if(objschecked >= 25)
break
return pseudo_z_axis
/mob/living/Move(atom/newloc, direct)
. = ..()
if(.)
pseudo_z_axis = newloc.get_fake_z()
pixel_z = pseudo_z_axis
/mob/living/proc/lay_down()
set name = "Rest"
set category = "IC"
if(client && client.prefs && client.prefs.autostand)
intentionalresting = !intentionalresting
to_chat(src, "<span class='notice'>You are now attempting to [intentionalresting ? "[!resting ? "lay down and ": ""]stay down" : "[resting ? "get up and ": ""]stay up"].</span>")
if(intentionalresting && !resting)
resting = TRUE
update_canmove()
else
resist_a_rest()
else
if(!resting)
resting = TRUE
to_chat(src, "<span class='notice'>You are now laying down.</span>")
update_canmove()
else
resist_a_rest()
/mob/living/proc/resist_a_rest(automatic = FALSE, ignoretimer = FALSE) //Lets mobs resist out of resting. Major QOL change with combat reworks.
if(!resting || stat || attemptingstandup)
return FALSE
if(ignoretimer)
resting = FALSE
update_canmove()
return TRUE
else
var/totaldelay = 3 //A little bit less than half of a second as a baseline for getting up from a rest
if(getStaminaLoss() >= STAMINA_SOFTCRIT)
to_chat(src, "<span class='warning'>You're too exhausted to get up!")
return FALSE
attemptingstandup = TRUE
var/health_deficiency = max((maxHealth - (health - getStaminaLoss()))*0.5, 0)
if(!has_gravity())
health_deficiency = health_deficiency*0.2
totaldelay += health_deficiency
var/standupwarning = "[src] and everyone around them should probably yell at the dev team"
switch(health_deficiency)
if(-INFINITY to 10)
standupwarning = "[src] stands right up!"
if(10 to 35)
standupwarning = "[src] tries to stand up."
if(35 to 60)
standupwarning = "[src] slowly pushes [p_them()]self upright."
if(60 to 80)
standupwarning = "[src] weakly attempts to stand up."
if(80 to INFINITY)
standupwarning = "[src] struggles to stand up."
var/usernotice = automatic ? "<span class='notice'>You are now getting up. (Auto)</span>" : "<span class='notice'>You are now getting up.</span>"
visible_message("<span class='notice'>[standupwarning]</span>", usernotice, vision_distance = 5)
if(do_after(src, totaldelay, target = src))
resting = FALSE
attemptingstandup = FALSE
update_canmove()
return TRUE
else
visible_message("<span class='notice'>[src] falls right back down.</span>", "<span class='notice'>You fall right back down.</span>")
attemptingstandup = FALSE
if(has_gravity())
playsound(src, "bodyfall", 20, 1)
return FALSE
/mob/living/carbon/update_stamina()
var/total_health = getStaminaLoss()
if(total_health)
if(!recoveringstam && total_health >= STAMINA_CRIT && !stat)
to_chat(src, "<span class='notice'>You're too exhausted to keep going...</span>")
resting = TRUE
if(combatmode)
toggle_combat_mode(TRUE)
recoveringstam = TRUE
filters += CIT_FILTER_STAMINACRIT
update_canmove()
if(recoveringstam && total_health <= STAMINA_SOFTCRIT)
to_chat(src, "<span class='notice'>You don't feel nearly as exhausted anymore.</span>")
recoveringstam = FALSE
filters -= CIT_FILTER_STAMINACRIT
update_canmove()
update_health_hud()
/mob/living/proc/update_hud_sprint_bar()
if(hud_used && hud_used.sprint_buffer)
hud_used.sprint_buffer.update_to_mob(src)
@@ -0,0 +1,466 @@
/*
DOG BORG EQUIPMENT HERE
SLEEPER CODE IS IN game/objects/items/devices/dogborg_sleeper.dm !
*/
/obj/item/dogborg/jaws
name = "Dogborg jaws"
desc = "The jaws of the debug errors oh god."
icon = 'icons/mob/dogborg.dmi'
flags_1 = CONDUCT_1
force = 1
throwforce = 0
w_class = 3
hitsound = 'sound/weapons/bite.ogg'
sharpness = IS_SHARP
var/stamtostunconversion = 0.1 //Total stamloss gets multiplied by this value for the help intent hard stun. Resting adds an additional 2x multiplier on top. Keep this low or so help me god.
var/stuncooldown = 4 SECONDS //How long it takes before you're able to attempt to stun a target again
var/nextstuntime
/obj/item/dogborg/jaws/examine(mob/user)
. = ..()
if(!CONFIG_GET(flag/weaken_secborg))
to_chat(user, "<span class='notice'>Use help intent to attempt to non-lethally incapacitate the target by latching on with your maw. This is more effective against exhausted and resting targets.</span>")
/obj/item/dogborg/jaws/big
name = "combat jaws"
desc = "The jaws of the law. Very sharp."
icon_state = "jaws"
force = 15 //Chomp chomp. Crew harm.
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
stamtostunconversion = 0.2 // 100*0.2*2=40. Stun's just long enough to slap on cuffs with click delay if the target is near hard stamcrit.
stuncooldown = 6 SECONDS
/obj/item/dogborg/jaws/small
name = "puppy jaws"
desc = "Rubberized teeth designed to protect accidental harm. Sharp enough for specialized tasks however."
icon_state = "smalljaws"
force = 6
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
var/status = 0
/obj/item/dogborg/jaws/attack(atom/A, mob/living/silicon/robot/user)
if(!istype(user))
return
if(!CONFIG_GET(flag/weaken_secborg) && user.a_intent != INTENT_HARM && istype(A, /mob/living))
if(A == user.pulling)
to_chat(user, "<span class='warning'>You already have [A] in your jaws.</span>")
return
if(nextstuntime >= world.time)
to_chat(user, "<span class='warning'>Your jaw servos are still recharging.</span>")
return
nextstuntime = world.time + stuncooldown
var/mob/living/M = A
var/cachedstam = M.getStaminaLoss()
var/totalstuntime = cachedstam * stamtostunconversion * (M.lying ? 2 : 1)
if(!M.resting)
M.Knockdown(cachedstam*2) //BORK BORK. GET DOWN.
M.Stun(totalstuntime)
user.do_attack_animation(A, ATTACK_EFFECT_BITE)
user.start_pulling(M, TRUE) //Yip yip. Come with.
user.changeNext_move(CLICK_CD_MELEE)
M.visible_message("<span class='danger'>[user] clamps [user.p_their()] [src] onto [M] and latches on!</span>", "<span class='userdanger'>[user] clamps [user.p_their()] [src] onto you and latches on!</span>")
if(totalstuntime >= 4 SECONDS)
playsound(usr, 'sound/effects/k9_jaw_strong.ogg', 75, FALSE, 2) //Wuff wuff. Big stun.
else
playsound(usr, 'sound/effects/k9_jaw_weak.ogg', 50, TRUE, -1) //Arf arf. Pls buff.
else
. = ..()
user.do_attack_animation(A, ATTACK_EFFECT_BITE)
/obj/item/dogborg/jaws/small/attack_self(mob/user)
var/mob/living/silicon/robot/R = user
if(R.cell && R.cell.charge > 100)
if(R.emagged && status == 0)
name = "combat jaws"
icon_state = "jaws"
desc = "The jaws of the law."
force = 12
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
stamtostunconversion = 0.15
stuncooldown = 5 SECONDS
status = 1
to_chat(user, "<span class='notice'>Your jaws are now [status ? "Combat" : "Pup'd"].</span>")
else
name = "puppy jaws"
icon_state = "smalljaws"
desc = "The jaws of a small dog."
force = initial(force)
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
stamtostunconversion = initial(stamtostunconversion)
stuncooldown = initial(stuncooldown)
status = 0
if(R.emagged)
to_chat(user, "<span class='notice'>Your jaws are now [status ? "Combat" : "Pup'd"].</span>")
update_icon()
//Boop
/obj/item/analyzer/nose
name = "boop module"
icon = 'icons/mob/dogborg.dmi'
icon_state = "nose"
desc = "The BOOP module"
flags_1 = CONDUCT_1
force = 0
throwforce = 0
attack_verb = list("nuzzles", "pushes", "boops")
w_class = 1
/obj/item/analyzer/nose/attack_self(mob/user)
user.visible_message("[user] sniffs around the air.", "<span class='warning'>You sniff the air for gas traces.</span>")
var/turf/location = user.loc
if(!istype(location))
return
var/datum/gas_mixture/environment = location.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
to_chat(user, "<span class='info'><B>Results:</B></span>")
if(abs(pressure - ONE_ATMOSPHERE) < 10)
to_chat(user, "<span class='info'>Pressure: [round(pressure,0.1)] kPa</span>")
else
to_chat(user, "<span class='alert'>Pressure: [round(pressure,0.1)] kPa</span>")
if(total_moles)
var/list/env_gases = environment.gases
var/o2_concentration = env_gases[/datum/gas/oxygen]/total_moles
var/n2_concentration = env_gases[/datum/gas/nitrogen]/total_moles
var/co2_concentration = env_gases[/datum/gas/carbon_dioxide]/total_moles
var/plasma_concentration = env_gases[/datum/gas/plasma]/total_moles
GAS_GARBAGE_COLLECT(environment.gases)
if(abs(n2_concentration - N2STANDARD) < 20)
to_chat(user, "<span class='info'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='alert'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>")
if(abs(o2_concentration - O2STANDARD) < 2)
to_chat(user, "<span class='info'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='alert'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>")
if(co2_concentration > 0.01)
to_chat(user, "<span class='alert'>CO2: [round(co2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='info'>CO2: [round(co2_concentration*100, 0.01)] %</span>")
if(plasma_concentration > 0.005)
to_chat(user, "<span class='alert'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='info'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>")
for(var/id in env_gases)
if(id in GLOB.hardcoded_gases)
continue
var/gas_concentration = env_gases[id]/total_moles
to_chat(user, "<span class='alert'>[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] %</span>")
to_chat(user, "<span class='info'>Temperature: [round(environment.temperature-T0C)] &deg;C</span>")
/obj/item/analyzer/nose/AltClick(mob/user) //Barometer output for measuring when the next storm happens
. = ..()
/obj/item/analyzer/nose/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
return
do_attack_animation(target, null, src)
user.visible_message("<span class='notice'>[user] [pick(attack_verb)] \the [target.name] with their nose!</span>")
//Delivery
/obj/item/storage/bag/borgdelivery
name = "fetching storage"
desc = "Fetch the thing!"
icon = 'icons/mob/dogborg.dmi'
icon_state = "dbag"
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/bag/borgdelivery/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_BULKY
STR.max_combined_w_class = 5
STR.max_items = 1
STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear, /obj/item/radio/intercom))
//Tongue stuff
/obj/item/soap/tongue
name = "synthetic tongue"
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
icon = 'icons/mob/dogborg.dmi'
icon_state = "synthtongue"
hitsound = 'sound/effects/attackblob.ogg'
cleanspeed = 80
var/status = 0
/obj/item/soap/tongue/scrubpup
cleanspeed = 25 //slightly faster than a mop.
/obj/item/soap/tongue/New()
..()
item_flags |= NOBLUDGEON //No more attack messages
/obj/item/soap/tongue/attack_self(mob/user)
var/mob/living/silicon/robot/R = user
if(R.cell && R.cell.charge > 100)
if(R.emagged && status == 0)
status = !status
name = "energized tongue"
desc = "Your tongue is energized for dangerously maximum efficency."
icon_state = "syndietongue"
to_chat(user, "<span class='notice'>Your tongue is now [status ? "Energized" : "Normal"].</span>")
cleanspeed = 10 //(nerf'd)tator soap stat
else
status = 0
name = "synthetic tongue"
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
icon_state = "synthtongue"
cleanspeed = initial(cleanspeed)
if(R.emagged)
to_chat(user, "<span class='notice'>Your tongue is now [status ? "Energized" : "Normal"].</span>")
update_icon()
/obj/item/soap/tongue/afterattack(atom/target, mob/user, proximity)
var/mob/living/silicon/robot/R = user
if(!proximity || !check_allowed_items(target))
return
if(R.client && (target in R.client.screen))
to_chat(R, "<span class='warning'>You need to take that [target.name] off before cleaning it!</span>")
else if(is_cleanable(target))
R.visible_message("[R] begins to lick off \the [target.name].", "<span class='warning'>You begin to lick off \the [target.name]...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish licking off \the [target.name].</span>")
qdel(target)
R.cell.give(50)
else if(isobj(target)) //hoo boy. danger zone man
if(istype(target,/obj/item/trash))
R.visible_message("[R] nibbles away at \the [target.name].", "<span class='warning'>You begin to nibble away at \the [target.name]...</span>")
if(!do_after(R, src.cleanspeed, target = target))
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
qdel(target)
R.cell.give(250)
return
if(istype(target,/obj/item/stock_parts/cell))
R.visible_message("[R] begins cramming \the [target.name] down its throat.", "<span class='warning'>You begin cramming \the [target.name] down your throat...</span>")
if(!do_after(R, 50, target = target))
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
var/obj/item/stock_parts/cell.C = target
R.cell.charge = R.cell.charge + (C.charge / 3) //Instant full cell upgrades op idgaf
qdel(target)
return
var/obj/item/I = target //HAHA FUCK IT, NOT LIKE WE ALREADY HAVE A SHITTON OF WAYS TO REMOVE SHIT
if(!I.anchored && R.emagged)
R.visible_message("[R] begins chewing up \the [target.name]. Looks like it's trying to loophole around its diet restriction!", "<span class='warning'>You begin chewing up \the [target.name]...</span>")
if(!do_after(R, 100, target = I)) //Nerf dat time yo
return //If they moved away, you can't eat them.
visible_message("<span class='warning'>[R] chews up \the [target.name] and cleans off the debris!</span>")
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
qdel(I)
R.cell.give(500)
return
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
else if(ishuman(target))
var/mob/living/L = target
if(status == 0 && check_zone(R.zone_selected) == "head")
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [L]'s face!</span>", "<span class='notice'>You affectionally lick \the [L]'s face!</span>")
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
if(istype(L) && L.fire_stacks > 0)
L.adjust_fire_stacks(-10)
return
else if(status == 0)
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [L]!</span>", "<span class='notice'>You affectionally lick \the [L]!</span>")
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
if(istype(L) && L.fire_stacks > 0)
L.adjust_fire_stacks(-10)
return
else
if(R.cell.charge <= 800)
to_chat(R, "Insufficent Power!")
return
L.Stun(4) // normal stunbaton is force 7 gimme a break good sir!
L.Knockdown(80)
L.apply_effect(EFFECT_STUTTER, 4)
L.visible_message("<span class='danger'>[R] has shocked [L] with its tongue!</span>", \
"<span class='userdanger'>[R] has shocked you with its tongue!</span>")
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
R.cell.use(666)
log_combat(R, L, "tongue stunned")
else if(istype(target, /obj/structure/window))
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
if(do_after(user, src.cleanspeed, target = target))
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
target.set_opacity(initial(target.opacity))
else
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
if(do_after(user, src.cleanspeed, target = target))
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
var/obj/effect/decal/cleanable/C = locate() in target
qdel(C)
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
target.wash_cream()
return
//Nerfed tongue for flavour reasons (haha geddit?). Used for aux skins for regular borgs
/obj/item/soap/tongue/flavour
desc = "For giving affectionate kisses."
/obj/item/soap/tongue/flavour/attack_self(mob/user)
return
/obj/item/soap/tongue/flavour/afterattack(atom/target, mob/user, proximity)
if(!proximity)
return
var/mob/living/silicon/robot.R = user
if(ishuman(target))
var/mob/living/L = target
if(status == 0 && check_zone(R.zone_selected) == "head")
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [L]'s face!</span>", "<span class='notice'>You affectionally lick \the [L]'s face!</span>")
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
return
else if(status == 0)
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [L]!</span>", "<span class='notice'>You affectionally lick \the [L]!</span>")
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
return
//Same as above but for noses
/obj/item/analyzer/nose/flavour/AltClick(mob/user)
return
/obj/item/analyzer/nose/flavour/attack_self(mob/user)
return
/obj/item/analyzer/nose/flavour/afterattack(atom/target, mob/user, proximity)
if(!proximity)
return
do_attack_animation(target, null, src)
user.visible_message("<span class='notice'>[user] [pick(attack_verb)] \the [target.name] with their nose!</span>")
//Dogfood
/obj/item/trash/rkibble
name = "robo kibble"
desc = "A novelty bowl of assorted mech fabricator byproducts. Mockingly feed this to the sec-dog to help it recharge."
icon = 'icons/mob/dogborg.dmi'
icon_state= "kibble"
//Defibs
/obj/item/twohanded/shockpaddles/cyborg/hound
name = "Paws of Life"
desc = "MediHound specific shock paws."
icon = 'icons/mob/dogborg.dmi'
icon_state = "defibpaddles0"
item_state = "defibpaddles0"
// Pounce stuff for K-9
/obj/item/dogborg/pounce
name = "pounce"
icon = 'icons/mob/dogborg.dmi'
icon_state = "pounce"
desc = "Leap at your target to momentarily stun them."
force = 0
throwforce = 0
/obj/item/dogborg/pounce/New()
..()
item_flags |= NOBLUDGEON
/mob/living/silicon/robot
var/leaping = 0
var/pounce_cooldown = 0
var/pounce_cooldown_time = 30 //Time in deciseconds between pounces
var/pounce_spoolup = 5 //Time in deciseconds for the pounce to happen after clicking
var/pounce_stamloss_cap = 120 //How much staminaloss pounces alone are capable of bringing a spaceman to
var/pounce_stamloss = 80 //Base staminaloss value of the pounce
var/leap_at
var/disabler
var/laser
var/sleeper_g
var/sleeper_r
var/sleeper_nv
#define MAX_K9_LEAP_DIST 4 //because something's definitely borked the pounce functioning from a distance.
/obj/item/dogborg/pounce/afterattack(atom/A, mob/user)
var/mob/living/silicon/robot/R = user
if(R && (world.time >= R.pounce_cooldown))
R.pounce_cooldown = world.time + R.pounce_cooldown_time
to_chat(R, "<span class ='warning'>Your targeting systems lock on to [A]...</span>")
playsound(R, 'sound/effects/servostep.ogg', 100, TRUE)
addtimer(CALLBACK(R, /mob/living/silicon/robot.proc/leap_at, A), R.pounce_spoolup)
else if(R && (world.time < R.pounce_cooldown))
to_chat(R, "<span class='danger'>Your leg actuators are still recharging!</span>")
/mob/living/silicon/robot/proc/leap_at(atom/A)
if(leaping || stat || buckled || lying)
return
if(!has_gravity(src) || !has_gravity(A))
to_chat(src,"<span class='danger'>It is unsafe to leap without gravity!</span>")
//It's also extremely buggy visually, so it's balance+bugfix
return
if(cell.charge <= 750)
to_chat(src,"<span class='danger'>Insufficent reserves for jump actuators!</span>")
return
else
leaping = 1
weather_immunities += "lava"
pixel_y = 10
update_icons()
throw_at(A, MAX_K9_LEAP_DIST, 1, spin=0, diagonals_first = 1)
cell.use(750) //Less than a stunbaton since stunbatons hit everytime.
playsound(src, 'sound/effects/stealthoff.ogg', 25, TRUE, -1)
weather_immunities -= "lava"
/mob/living/silicon/robot/throw_impact(atom/A)
if(!leaping)
return ..()
if(A)
if(isliving(A))
var/mob/living/L = A
var/blocked = 0
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(H.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
blocked = 1
if(!blocked)
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
L.Knockdown(iscarbon(L) ? 60 : 45, override_stamdmg = CLAMP(pounce_stamloss, 0, pounce_stamloss_cap-L.getStaminaLoss())) // Temporary. If someone could rework how dogborg pounces work to accomodate for combat changes, that'd be nice.
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src,L)
log_combat(src, L, "borg pounced")
else
Knockdown(15, 1, 1)
pounce_cooldown = !pounce_cooldown
spawn(pounce_cooldown_time) //3s by default
pounce_cooldown = !pounce_cooldown
else if(A.density && !A.CanPass(src))
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='userdanger'>You smash into [A]!</span>")
playsound(src, 'sound/items/trayhit1.ogg', 50, 1)
Knockdown(15, 1, 1)
if(leaping)
leaping = 0
pixel_y = initial(pixel_y)
update_icons()
update_canmove()
@@ -11,6 +11,7 @@
. = ..()
if(!resting && !sprinting)
. += 1
. += speed
/mob/living/silicon/robot/proc/togglesprint(shutdown = FALSE) //Basically a copypaste of the proc from /mob/living/carbon/human
if(!shutdown && (!cell || cell.charge < 25))
@@ -18,11 +19,11 @@
sprinting = shutdown ? FALSE : !sprinting
if(!resting && canmove)
if(sprinting)
playsound_local(src, 'modular_citadel/sound/misc/sprintactivate.ogg', 50, FALSE, pressure_affected = FALSE)
playsound_local(src, 'sound/misc/sprintactivate.ogg', 50, FALSE, pressure_affected = FALSE)
else
if(shutdown)
playsound_local(src, 'sound/effects/light_flicker.ogg', 50, FALSE, pressure_affected = FALSE)
playsound_local(src, 'modular_citadel/sound/misc/sprintdeactivate.ogg', 50, FALSE, pressure_affected = FALSE)
playsound_local(src, 'sound/misc/sprintdeactivate.ogg', 50, FALSE, pressure_affected = FALSE)
if(hud_used && hud_used.static_inventory)
for(var/obj/screen/sprintbutton/selector in hud_used.static_inventory)
selector.insert_witty_toggle_joke_here(src)
@@ -1,151 +0,0 @@
/obj/item/seeds/banana/Initialize()
. = ..()
mutatelist += /obj/item/seeds/banana/exotic_banana
/obj/item/seeds/banana/exotic_banana
name = "pack of exotic banana seeds"
desc = "They're seeds that grow into banana trees. However, those bananas might be alive."
icon = 'modular_citadel/icons/mob/BananaSpider.dmi'
icon_state = "seed_ExoticBanana"
species = "banana"
plantname = "Exotic Banana Tree"
product = /obj/item/reagent_containers/food/snacks/grown/banana/banana_spider_spawnable
growing_icon = 'modular_citadel/icons/mob/BananaSpider.dmi'
icon_dead = "banana-dead"
mutatelist = list()
genes = list(/datum/plant_gene/trait/slip)
reagents_add = list("banana" = 0.1, "potassium" = 0.1, "vitamin" = 0.04, "nutriment" = 0.02)
/obj/item/reagent_containers/food/snacks/grown/banana/banana_spider_spawnable
seed = /obj/item/seeds/banana/exotic_banana
name = "banana spider"
desc = "You do not know what it is, but you can bet the clown would love it."
icon = 'modular_citadel/icons/mob/BananaSpider.dmi'
icon_state = "banana"
item_state = "banana"
filling_color = "#FFFF00"
list_reagents = list("nutriment" = 3, "vitamin" = 2)
foodtype = GROSS | MEAT | RAW | FRUIT
grind_results = list("blood" = 20, "liquidgibs" = 5)
juice_results = list("banana" = 0)
var/awakening = 0
/obj/item/reagent_containers/food/snacks/grown/banana/banana_spider_spawnable/attack_self(mob/user)
if(awakening || isspaceturf(user.loc))
return
to_chat(user, "<span class='notice'>You decide to wake up the banana spider...</span>")
awakening = 1
spawn(30)
if(!QDELETED(src))
var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc))
S.speed += round(10 / seed.potency)
S.visible_message("<span class='notice'>The banana spider chitters as it stretches its legs.</span>")
qdel(src)
/mob/living/simple_animal/banana_spider
icon = 'modular_citadel/icons/mob/BananaSpider.dmi'
name = "banana spider"
desc = "What the fuck is this abomination?"
icon_state = "banana"
icon_dead = "banana_peel"
health = 1
maxHealth = 1
turns_per_move = 5 //this isn't player speed =|
speed = 2 //this is player speed
loot = list(/obj/item/reagent_containers/food/snacks/deadbanana_spider)
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 270
maxbodytemp = INFINITY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
response_help = "pokes"
response_disarm = "shoos"
response_harm = "splats"
speak_emote = list("chitters")
mouse_opacity = 2
density = TRUE
ventcrawler = VENTCRAWLER_ALWAYS
gold_core_spawnable = FRIENDLY_SPAWN
verb_say = "chitters"
verb_ask = "chitters inquisitively"
verb_exclaim = "chitters loudly"
verb_yell = "chitters loudly"
var/squish_chance = 50
var/projectile_density = TRUE //griffons get shot
del_on_death = TRUE
/mob/living/simple_animal/banana_spider/Initialize()
. = ..()
var/area/A = get_area(src)
if(A)
notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE)
/mob/living/simple_animal/banana_spider/attack_ghost(mob/user)
if(key) //please stop using src. without a good reason.
return
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
if(!isnum(user.client.player_age))
return
if(!SSticker.mode)
to_chat(user, "Can't become a banana spider before the game has started.")
return
var/be_spider = alert("Become a banana spider? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_spider == "No" || QDELETED(src) || !isobserver(user))
return
sentience_act()
user.transfer_ckey(src, FALSE)
density = TRUE
/mob/living/simple_animal/banana_spider/ComponentInitialize()
. = ..()
AddComponent(/datum/component/slippery, 40)
/mob/living/simple_animal/banana_spider/Crossed(atom/movable/AM) //no /var in proc headers
. = ..()
if(istype(AM, /obj/item/projectile) && projectile_density) //forced projectile density
var/obj/item/projectile/P = AM
P.Bump(src)
if(ismob(AM))
if(isliving(AM))
var/mob/living/A = AM
if(A.mob_size > MOB_SIZE_SMALL && !(A.movement_type & FLYING))
if(prob(squish_chance))
A.visible_message("<span class='notice'>[A] squashed [src].</span>", "<span class='notice'>You squashed [src] under your weight as you fell.</span>")
adjustBruteLoss(1)
else
visible_message("<span class='notice'>[src] avoids getting crushed.</span>")
else
if(isstructure(AM))
if(prob(squish_chance))
AM.visible_message("<span class='notice'>[src] was crushed under [AM]'s weight as they fell.</span>")
adjustBruteLoss(1)
else
visible_message("<span class='notice'>[src] avoids getting crushed.</span>")
/mob/living/simple_animal/banana_spider/ex_act()
return
/mob/living/simple_animal/banana_spider/start_pulling()
return FALSE //No.
/obj/item/reagent_containers/food/snacks/deadbanana_spider
name = "dead banana spider"
desc = "Thank god it's gone...but it does look slippery."
icon = 'modular_citadel/icons/mob/BananaSpider.dmi'
icon_state = "banana_peel"
bitesize = 3
eatverb = "devours"
list_reagents = list("nutriment" = 3, "vitamin" = 2)
foodtype = GROSS | MEAT | RAW
grind_results = list("blood" = 20, "liquidgibs" = 5)
juice_results = list("banana" = 0)
/obj/item/reagent_containers/food/snacks/deadbanana_spider/Initialize()
. = ..()
AddComponent(/datum/component/slippery, 20)
@@ -1,134 +0,0 @@
/mob/living/simple_animal/kiwi
name = "space kiwi"
desc = "Exposure to low gravity made them grow larger."
gender = FEMALE
icon = 'modular_citadel/icons/mob/kiwi.dmi'
icon_state = "kiwi"
icon_living = "kiwi"
icon_dead = "dead"
speak = list("Chirp!","Cheep cheep chirp!!","Cheep.")
speak_emote = list("chirps","trills")
emote_hear = list("chirps.")
emote_see = list("pecks at the ground.","jumps in place.")
density = FALSE
speak_chance = 2
turns_per_move = 3
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 3)
var/egg_type = /obj/item/reagent_containers/food/snacks/egg/kiwiEgg
var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
attacktext = "kicks"
health = 25
maxHealth = 25
ventcrawler = VENTCRAWLER_ALWAYS
var/eggsleft = 0
var/eggsFertile = TRUE
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
var/list/feedMessages = list("It chirps happily.","It chirps happily.")
var/list/layMessage = list("lays an egg.","squats down and croons.","begins making a huge racket.","begins chirping raucously.")
gold_core_spawnable = FRIENDLY_SPAWN
var/static/kiwi_count = 0
/mob/living/simple_animal/kiwi/Destroy()
--kiwi_count
return ..()
/mob/living/simple_animal/kiwi/Initialize()
. = ..()
++kiwi_count
/mob/living/simple_animal/kiwi/Life()
. =..()
if(!.)
return
if((!stat && prob(3) && eggsleft > 0) && egg_type)
visible_message("[src] [pick(layMessage)]")
eggsleft--
var/obj/item/E = new egg_type(get_turf(src))
E.pixel_x = rand(-6,6)
E.pixel_y = rand(-6,6)
if(eggsFertile)
if(kiwi_count < MAX_CHICKENS && prob(25))
START_PROCESSING(SSobj, E)
/obj/item/reagent_containers/food/snacks/egg/kiwiEgg/process()
if(isturf(loc))
amount_grown += rand(1,2)
if(amount_grown >= 100)
visible_message("[src] hatches with a quiet cracking sound.")
new /mob/living/simple_animal/babyKiwi(get_turf(src))
STOP_PROCESSING(SSobj, src)
qdel(src)
else
STOP_PROCESSING(SSobj, src)
/mob/living/simple_animal/kiwi/attackby(obj/item/O, mob/user, params)
if(istype(O, food_type)) //feedin' dem kiwis
if(!stat && eggsleft < 8)
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
user.visible_message(feedmsg)
qdel(O)
eggsleft += rand(1, 4)
else
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
else
..()
/mob/living/simple_animal/babyKiwi
name = "baby space kiwi"
desc = "So huggable."
icon = 'modular_citadel/icons/mob/kiwi.dmi'
icon_state = "babyKiwi"
icon_living = "babyKiwi"
icon_dead = "deadBaby"
icon_gib = "chick_gib"
gender = FEMALE
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
speak_emote = list("chirps")
emote_hear = list("chirps.")
emote_see = list("pecks at the ground.","Happily bounces in place.")
density = FALSE
speak_chance = 2
turns_per_move = 2
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2)
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
attacktext = "kicks"
health = 10
maxHealth = 10
ventcrawler = VENTCRAWLER_ALWAYS
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
/mob/living/simple_animal/babyKiwi/Initialize()
. = ..()
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
/mob/living/simple_animal/babyKiwi/Life()
. =..()
if(!.)
return
if(!stat && !ckey)
amount_grown += rand(1,2)
if(amount_grown >= 100)
new /mob/living/simple_animal/kiwi(src.loc)
qdel(src)
/obj/item/reagent_containers/food/snacks/egg/kiwiEgg
name = "kiwi egg"
icon = 'modular_citadel/icons/mob/kiwi.dmi'
desc = "A slightly bigger egg!"
icon_state = "egg"
@@ -1,135 +0,0 @@
//CARBON MOBS
/mob/living/carbon/alien
devourable = TRUE
digestable = TRUE
feeding = TRUE
/mob/living/carbon/monkey
devourable = TRUE
digestable = TRUE
feeding = TRUE
/*
REFER TO code/modules/mob/living/simple_animal/simple_animal_vr.dm for Var information!
*/
//NUETRAL MOBS
/mob/living/simple_animal/crab
devourable = TRUE
digestable = TRUE
feeding = TRUE
/mob/living/simple_animal/cow
devourable = TRUE
digestable = TRUE
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_HOLD
/mob/living/simple_animal/chick
devourable = TRUE
digestable = TRUE
/mob/living/simple_animal/chicken
devourable = TRUE
digestable = TRUE
/mob/living/simple_animal/mouse
devourable = TRUE
digestable = TRUE
/mob/living/simple_animal/kiwi
devourable = TRUE
digestable = TRUE
//STATION PETS
/mob/living/simple_animal/pet
devourable = TRUE
digestable = TRUE
feeding = TRUE
/mob/living/simple_animal/pet/fox
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_HOLD
/mob/living/simple_animal/pet/cat
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_HOLD
/mob/living/simple_animal/pet/dog
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_HOLD
/mob/living/simple_animal/sloth
devourable = TRUE
digestable = TRUE
/mob/living/simple_animal/parrot
devourable = TRUE
digestable = TRUE
//HOSTILE MOBS
/mob/living/simple_animal/hostile/retaliate/goat
devourable = TRUE
digestable = TRUE
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_stomach_flavor = "You find yourself squeezed into the hollow of the goat, the smell of oats and hay thick in the tight space, all of which grinds in on you. Harmless for now..."
vore_default_mode = DM_HOLD
/mob/living/simple_animal/hostile/lizard
devourable = TRUE
digestable = TRUE
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/alien
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/bear
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/poison/giant_spider
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/retaliate/poison/snake
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/gorilla
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/asteroid/goliath
feeding = TRUE //for pet Goliaths I guess or something.
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
/mob/living/simple_animal/hostile/carp
feeding = TRUE
vore_active = TRUE
isPredator = TRUE
vore_default_mode = DM_DIGEST
+4 -2
View File
@@ -3,9 +3,11 @@
/mob/say_mod(input, message_mode)
var/customsayverb = findtext(input, "*")
if(customsayverb)
if(customsayverb && message_mode != MODE_WHISPER_CRIT)
message_mode = MODE_CUSTOM_SAY
return lowertext(copytext(input, 1, customsayverb))
. = ..()
else
return ..()
/atom/movable/proc/attach_spans(input, list/spans)
var/customsayverb = findtext(input, "*")
@@ -1,7 +0,0 @@
/obj/machinery/light
bulb_colour = "#FFEEDD"
bulb_power = 0.75
/obj/machinery/light/small
bulb_colour = "#FFDDBB"
bulb_power = 0.75
@@ -29,27 +29,27 @@
build_path = /obj/item/ammo_box/magazine/m10mm/hp
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/m10mm/ap
name = "pistol magazine (10mm AP)"
desc = "A gun magazine. Loaded with rounds which penetrate armour, but are less effective against normal targets."
id = "10mmap"
build_type = PROTOLATHE
materials = list(MAT_METAL = 40000, MAT_TITANIUM = 60000)
build_path = /obj/item/ammo_box/magazine/m10mm/ap
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/m10mm/ap
name = "pistol magazine (10mm AP)"
desc = "A gun magazine. Loaded with rounds which penetrate armour, but are less effective against normal targets."
id = "10mmap"
build_type = PROTOLATHE
materials = list(MAT_METAL = 40000, MAT_TITANIUM = 60000)
build_path = /obj/item/ammo_box/magazine/m10mm/ap
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/bolt_clip
name = "Surplus Rifle Clip"
desc = "A stripper clip used to quickly load bolt action rifles. Contains 5 rounds."
id = "bolt_clip"
build_type = PROTOLATHE
materials = list(MAT_METAL = 8000)
build_path = /obj/item/ammo_box/a762
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
name = "Surplus Rifle Clip"
desc = "A stripper clip used to quickly load bolt action rifles. Contains 5 rounds."
id = "bolt_clip"
build_type = PROTOLATHE
materials = list(MAT_METAL = 8000)
build_path = /obj/item/ammo_box/a762
category = list("Ammo")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/m45 //Kinda NT in throey
name = "handgun magazine (.45)"
id = "m45"
@@ -1,4 +1,4 @@
/obj/item/projectile/bullet/c46x30mm_tx
name = "toxin tipped 4.6x30mm bullet"
damage = 15
damage = 10
damage_type = TOX
@@ -57,10 +57,9 @@
icon_state = "magjectile-nl"
damage = 2
knockdown = 0
stamina = 25
armour_penetration = -10
stamina = 20
light_range = 2
speed = 0.7
speed = 0.6
range = 25
light_color = LIGHT_COLOR_BLUE
@@ -109,9 +108,10 @@
fire_sound = 'sound/weapons/magpistol.ogg'
mag_type = /obj/item/ammo_box/magazine/mmag/small
can_suppress = 0
casing_ejector = 0
casing_ejector = FALSE
fire_delay = 2
recoil = 0.2
recoil = 0.1
inaccuracy_modifier = 0.25
/obj/item/gun/ballistic/automatic/pistol/mag/update_icon()
..()
@@ -123,7 +123,6 @@
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
///research memes///
/*
/obj/item/gun/ballistic/automatic/pistol/mag/nopin
pin = null
spawnwithmagazine = FALSE
@@ -155,7 +154,7 @@
materials = list(MAT_METAL = 3000, MAT_SILVER = 250, MAT_TITANIUM = 250)
build_path = /obj/item/ammo_box/magazine/mmag/small
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
*/
//////toy memes/////
/obj/item/projectile/bullet/reusable/foam_dart/mag
@@ -201,9 +200,9 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "magjectile-large"
damage = 20
armour_penetration = 25
armour_penetration = 20
light_range = 3
speed = 0.7
speed = 0.6
range = 35
light_color = LIGHT_COLOR_RED
@@ -212,10 +211,10 @@
icon_state = "magjectile-large-nl"
damage = 2
knockdown = 0
stamina = 25
armour_penetration = -10
stamina = 20
armour_penetration = 10
light_range = 3
speed = 0.65
speed = 0.6
range = 35
light_color = LIGHT_COLOR_BLUE
@@ -227,6 +226,8 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "mag-casing-live"
projectile_type = /obj/item/projectile/bullet/magrifle
click_cooldown_override = 2.5
delay = 3
/obj/item/ammo_casing/caseless/anlmagm
desc = "A large, specialized ferromagnetic slug designed with a less-than-lethal payload."
@@ -234,10 +235,12 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "mag-casing-live"
projectile_type = /obj/item/projectile/bullet/nlmagrifle
click_cooldown_override = 2.5
delay = 3
///magazines///
/obj/item/ammo_box/magazine/mmag/
/obj/item/ammo_box/magazine/mmag
name = "magrifle magazine (non-lethal disabler)"
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "mediummagmag"
@@ -261,17 +264,20 @@
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
icon_state = "magrifle"
item_state = "arg"
slot_flags = 0
slot_flags = NONE
mag_type = /obj/item/ammo_box/magazine/mmag
fire_sound = 'sound/weapons/magrifle.ogg'
can_suppress = 0
burst_size = 3
fire_delay = 2
spread = 5
recoil = 0.15
casing_ejector = 0
burst_size = 1
actions_types = null
fire_delay = 3
spread = 0
recoil = 0.1
casing_ejector = FALSE
inaccuracy_modifier = 0.5
weapon_weight = WEAPON_MEDIUM
dualwield_spread_mult = 1.4
/*
//research///
/obj/item/gun/ballistic/automatic/magrifle/nopin
@@ -305,7 +311,7 @@
materials = list(MAT_METAL = 6000, MAT_SILVER = 500, MAT_TITANIUM = 500)
build_path = /obj/item/ammo_box/magazine/mmag
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
*/
///foamagrifle///
/obj/item/ammo_box/magazine/toy/foamag
@@ -327,7 +333,6 @@
spread = 60
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_HEAVY
/*
// TECHWEBS IMPLEMENTATION
//
@@ -339,7 +344,6 @@
design_ids = list("magrifle", "magpisol", "mag_magrifle", "mag_magrifle_nl", "mag_magpistol", "mag_magpistol_nl")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
*/
//////Hyper-Burst Rifle//////
@@ -143,6 +143,7 @@
// TECHWEBS IMPLEMENTATION
*/
/*
/datum/techweb_node/magnetic_weapons
id = "magnetic_weapons"
display_name = "Magnetic Weapons"
@@ -151,6 +152,7 @@
design_ids = list("magrifle_e", "magpistol_e", "mag_magrifle_e", "mag_magrifle_e_nl", "mag_magpistol_e", "mag_magpistol_e_nl")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
*/
///magrifle///
@@ -1,11 +0,0 @@
/*
// REVOLVER THINGS GO HERE
*/
/obj/item/gun/ballistic/revolver //regular, classic sprite
name = "\improper .357 revolver"
desc = "A typical revolver. Uses .357 ammo."
/obj/item/gun/ballistic/revolver/syndie //New and improved 100% syndicate technology!
desc = "A suspicious revolver. Uses .357 ammo."
icon = 'modular_citadel/icons/obj/guns/revolver.dmi'
@@ -1,13 +1,6 @@
/obj/item/gun/energy/e_gun
name = "blaster carbine"
desc = "A high powered particle blaster carbine with varitable setting for stunning or lethal applications."
icon = 'modular_citadel/icons/obj/guns/OVERRIDE_energy.dmi'
lefthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_lefthand.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_righthand.dmi'
ammo_x_offset = 2
flight_x_offset = 17
flight_y_offset = 11
/*/////////////////////////////////////////////////////////////////////////////////////////////
The Recolourable Energy Gun
@@ -1,19 +1,11 @@
/obj/item/gun/energy/laser
name = "blaster rifle"
desc = "a high energy particle blaster, efficient and deadly."
icon = 'modular_citadel/icons/obj/guns/OVERRIDE_energy.dmi'
ammo_x_offset = 1
shaded_charge = 1
lefthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_lefthand.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_righthand.dmi'
/obj/item/gun/energy/laser/practice
icon = 'modular_citadel/icons/obj/guns/energy.dmi'
icon_state = "laser-p"
/obj/item/gun/energy/laser/bluetag
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
/obj/item/gun/energy/laser/redtag
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
lefthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_lefthand.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/OVERRIDE_guns_righthand.dmi'
ammo_x_offset = 1
shaded_charge = 1
@@ -75,9 +75,9 @@
/obj/item/gun/energy/pumpaction/proc/pump(mob/M) //pumping proc. Checks if the gun is empty and plays a different sound if it is.
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
if(cell.charge < shot.e_cost)
playsound(M, 'modular_citadel/sound/weapons/laserPumpEmpty.ogg', 100, 1) //Ends with three beeps made from highly processed knife honing noises
playsound(M, 'sound/weapons/laserPumpEmpty.ogg', 100, 1) //Ends with three beeps made from highly processed knife honing noises
else
playsound(M, 'modular_citadel/sound/weapons/laserPump.ogg', 100, 1) //Ends with high pitched charging noise
playsound(M, 'sound/weapons/laserPump.ogg', 100, 1) //Ends with high pitched charging noise
recharge_newshot() //try to charge a new shot
update_icon()
return 1
@@ -152,14 +152,14 @@
e_cost = 150
pellets = 4
variance = 30
fire_sound = 'modular_citadel/sound/weapons/ParticleBlaster.ogg'
fire_sound = 'sound/weapons/ParticleBlaster.ogg'
select_name = "disable"
/obj/item/ammo_casing/energy/disabler/slug
projectile_type = /obj/item/projectile/beam/disabler/slug
select_name = "overdrive"
e_cost = 200
fire_sound = 'modular_citadel/sound/weapons/LaserSlugv3.ogg'
fire_sound = 'sound/weapons/LaserSlugv3.ogg'
/obj/item/ammo_casing/energy/laser/pump
projectile_type = /obj/item/projectile/beam/weak
@@ -167,12 +167,12 @@
select_name = "kill"
pellets = 3
variance = 15
fire_sound = 'modular_citadel/sound/weapons/ParticleBlaster.ogg'
fire_sound = 'sound/weapons/ParticleBlaster.ogg'
/obj/item/ammo_casing/energy/electrode/pump
projectile_type = /obj/item/projectile/energy/electrode/pump
select_name = "stun"
fire_sound = 'modular_citadel/sound/weapons/LaserSlugv3.ogg'
fire_sound = 'sound/weapons/LaserSlugv3.ogg'
e_cost = 300
pellets = 3
variance = 20
@@ -39,7 +39,7 @@
projectile_type = /obj/item/projectile/beam/lasertag/wavemotion
select_name = "overdrive"
e_cost = 300
fire_sound = 'modular_citadel/sound/weapons/LaserSlugv3.ogg'
fire_sound = 'sound/weapons/LaserSlugv3.ogg'
/obj/item/ammo_casing/energy/laser/dispersal
projectile_type = /obj/item/projectile/beam/lasertag/dispersal
@@ -47,7 +47,7 @@
pellets = 5
variance = 25
e_cost = 200
fire_sound = 'modular_citadel/sound/weapons/ParticleBlaster.ogg'
fire_sound = 'sound/weapons/ParticleBlaster.ogg'
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TOY REVOLVER
@@ -1,2 +0,0 @@
/obj/item/projectile/energy/electrode
stamina = 36
@@ -1,6 +1,6 @@
/obj/item/projectile/bullet/reusable/foam_dart/tag
name = "lastag foam dart"
var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag)
name = "lastag foam dart"
var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag)
/obj/item/projectile/bullet/reusable/foam_dart/tag/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -89,6 +89,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
if(!SM.mind) //Something went wrong, use alt mechanics
return ..()
SM.mind.enslave_mind_to_creator(M)
SM.mind.store_memory(M.mind.memory)
//If they're a zombie, they can try to negate it with this.
//I seriously wonder if anyone will ever use this function.
@@ -30,17 +30,15 @@
inverse_chem_val = 0.35
inverse_chem = "BEsmaller" //At really impure vols, it just becomes 100% inverse
can_synth = FALSE
var/message_spam = FALSE
/datum/reagent/fermi/breast_enlarger/on_mob_add(mob/living/carbon/M)
/datum/reagent/fermi/breast_enlarger/on_mob_metabolize(mob/living/M)
. = ..()
if(!ishuman(M)) //The monkey clause
if(volume >= 15) //To prevent monkey breast farms
var/turf/T = get_turf(M)
var/obj/item/organ/genital/breasts/B = new /obj/item/organ/genital/breasts(T)
var/list/seen = viewers(8, T)
for(var/mob/S in seen)
to_chat(S, "<span class='warning'>A pair of breasts suddenly fly out of the [M]!</b></span>")
//var/turf/T2 = pick(turf in view(5, M))
M.visible_message("<span class='warning'>A pair of breasts suddenly fly out of the [M]!</b></span>")
var/T2 = get_random_station_turf()
M.adjustBruteLoss(25)
M.Knockdown(50)
@@ -48,94 +46,82 @@
B.throw_at(T2, 8, 1)
M.reagents.remove_reagent(id, volume)
return
log_game("FERMICHEM: [M] ckey: [M.key] has ingested Sucubus milk")
var/mob/living/carbon/human/H = M
H.genital_override = TRUE
var/obj/item/organ/genital/breasts/B = H.getorganslot("breasts")
if(!B)
H.emergent_genital_call()
return
if(!B.size == "huge")
var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5)
B.prev_size = B.size
B.cached_size = sizeConv[B.size]
if(!H.getorganslot(ORGAN_SLOT_BREASTS) && H.emergent_genital_call())
H.genital_override = TRUE
/datum/reagent/fermi/breast_enlarger/on_mob_life(mob/living/carbon/M) //Increases breast size
if(!ishuman(M))//Just in case
return..()
var/mob/living/carbon/human/H = M
var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS)
if(!B) //If they don't have breasts, give them breasts.
//If they have Acute hepatic pharmacokinesis, then route processing though liver.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
if(HAS_TRAIT(H, TRAIT_PHARMA) || !H.canbearoused)
var/obj/item/organ/liver/L = H.getorganslot(ORGAN_SLOT_LIVER)
if(L)
L.swelling+= 0.05
return..()
L.swelling += 0.05
else
M.adjustToxLoss(1)
return..()
H.adjustToxLoss(1)
return..()
//otherwise proceed as normal
var/obj/item/organ/genital/breasts/nB = new
nB.Insert(M)
if(nB)
if(M.dna.species.use_skintones && M.dna.features["genitals_use_skintone"])
nB.color = skintone2hex(H.skin_tone)
else if(M.dna.features["breasts_color"])
nB.color = "#[M.dna.features["breasts_color"]]"
else
nB.color = skintone2hex(H.skin_tone)
nB.size = "flat"
nB.cached_size = 0
nB.prev_size = 0
to_chat(M, "<span class='warning'>Your chest feels warm, tingling with newfound sensitivity.</b></span>")
M.reagents.remove_reagent(id, 5)
B = nB
B = new
if(H.dna.species.use_skintones && H.dna.features["genitals_use_skintone"])
B.color = skintone2hex(H.skin_tone)
else if(M.dna.features["breasts_color"])
B.color = "#[M.dna.features["breasts_color"]]"
else
B.color = skintone2hex(H.skin_tone)
B.size = "flat"
B.cached_size = 0
B.prev_size = 0
to_chat(H, "<span class='warning'>Your chest feels warm, tingling with newfound sensitivity.</b></span>")
H.reagents.remove_reagent(id, 5)
B.Insert(H)
//If they have them, increase size. If size is comically big, limit movement and rip clothes.
B.cached_size = B.cached_size + 0.05
if (B.cached_size >= 8.5 && B.cached_size < 9)
if(H.w_uniform || H.wear_suit)
var/target = M.get_bodypart(BODY_ZONE_CHEST)
to_chat(M, "<span class='warning'>Your breasts begin to strain against your clothes tightly!</b></span>")
M.adjustOxyLoss(5, 0)
M.apply_damage(1, BRUTE, target)
B.update()
..()
B.modify_size(0.05)
if (ISINRANGE_EX(B.cached_size, 8.5, 9) && (H.w_uniform || H.wear_suit))
var/target = H.get_bodypart(BODY_ZONE_CHEST)
if(!message_spam)
to_chat(H, "<span class='danger'>Your breasts begin to strain against your clothes tightly!</b></span>")
message_spam = TRUE
H.adjustOxyLoss(5, 0)
H.apply_damage(1, BRUTE, target)
return ..()
/datum/reagent/fermi/breast_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders.
//Acute hepatic pharmacokinesis.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused)
var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER)
L.swelling+= 0.05
return ..()
var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
var/obj/item/organ/genital/testicles/T = M.getorganslot("testicles")
var/obj/item/organ/genital/vagina/V = M.getorganslot("vagina")
var/obj/item/organ/genital/womb/W = M.getorganslot("womb")
var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS)
var/obj/item/organ/genital/testicles/T = M.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/genital/vagina/V = M.getorganslot(ORGAN_SLOT_VAGINA)
var/obj/item/organ/genital/womb/W = M.getorganslot(ORGAN_SLOT_WOMB)
if(M.gender == MALE)
M.gender = FEMALE
M.visible_message("<span class='boldnotice'>[M] suddenly looks more feminine!</span>", "<span class='boldwarning'>You suddenly feel more feminine!</span>")
if(P)
P.cached_length = P.cached_length - 0.05
P.update()
P.modify_size(-0.05)
if(T)
T.Remove(M)
qdel(T)
if(!V)
var/obj/item/organ/genital/vagina/nV = new
nV.Insert(M)
V = nV
V = new
V.Insert(M)
if(!W)
var/obj/item/organ/genital/womb/nW = new
nW.Insert(M)
W = nW
..()
W = new
W.Insert(M)
return ..()
/datum/reagent/fermi/BEsmaller
name = "Modesty milk"
@@ -147,19 +133,18 @@
can_synth = FALSE
/datum/reagent/fermi/BEsmaller/on_mob_life(mob/living/carbon/M)
var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS)
if(!B)
//Acute hepatic pharmacokinesis.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused)
var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER)
L.swelling-= 0.05
return ..()
//otherwise proceed as normal
return..()
B.cached_size = B.cached_size - 0.05
B.update()
..()
B.modify_size(-0.05)
return ..()
/datum/reagent/fermi/BEsmaller_hypo
name = "Rectify milk" //Rectify
@@ -171,31 +156,28 @@
var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5)
can_synth = TRUE
/datum/reagent/fermi/BEsmaller_hypo/on_mob_add(mob/living/carbon/M)
/datum/reagent/fermi/BEsmaller_hypo/on_mob_metabolize(mob/living/M)
. = ..()
if(!M.getorganslot("vagina"))
if(M.dna.features["has_vag"])
var/obj/item/organ/genital/vagina/nV = new
nV.Insert(M)
if(!M.getorganslot("womb"))
if(M.dna.features["has_womb"])
var/obj/item/organ/genital/womb/nW = new
nW.Insert(M)
if(!ishuman(M))
return
var/mob/living/carbon/human/H = M
if(!H.getorganslot(ORGAN_SLOT_VAGINA) && H.dna.features["has_vag"])
H.give_genital(/obj/item/organ/genital/vagina)
if(!H.getorganslot(ORGAN_SLOT_WOMB) && H.dna.features["has_womb"])
H.give_genital(/obj/item/organ/genital/womb)
/datum/reagent/fermi/BEsmaller_hypo/on_mob_life(mob/living/carbon/M)
var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS)
if(!B)
return..()
if(!M.dna.features["has_breasts"])//Fast fix for those who don't want it.
B.cached_size = B.cached_size - 0.1
B.update()
else if(B.cached_size > (sizeConv[M.dna.features["breasts_size"]]+0.1))
B.cached_size = B.cached_size - 0.05
B.update()
else if(B.cached_size < (sizeConv[M.dna.features["breasts_size"]])+0.1)
B.cached_size = B.cached_size + 0.05
B.update()
..()
var/optimal_size = B.breast_values[M.dna.features["breasts_size"]]
if(!optimal_size)//Fast fix for those who don't want it.
B.modify_size(-0.1)
else if(B.cached_size > optimal_size)
B.modify_size(-0.05, optimal_size)
else if(B.cached_size < optimal_size)
B.modify_size(0.05, 0, optimal_size)
return ..()
////////////////////////////////////////////////////////////////////////////////////////////////////
// PENIS ENLARGE
@@ -215,16 +197,15 @@
inverse_chem_val = 0.35
inverse_chem = "PEsmaller" //At really impure vols, it just becomes 100% inverse and shrinks instead.
can_synth = FALSE
var/message_spam = FALSE
/datum/reagent/fermi/penis_enlarger/on_mob_add(mob/living/carbon/M)
/datum/reagent/fermi/penis_enlarger/on_mob_metabolize(mob/living/M)
. = ..()
if(!ishuman(M)) //Just monkeying around.
if(volume >= 15) //to prevent monkey penis farms
var/turf/T = get_turf(M)
var/obj/item/organ/genital/penis/P = new /obj/item/organ/genital/penis(T)
var/list/seen = viewers(8, T)
for(var/mob/S in seen)
to_chat(S, "<span class='warning'>A penis suddenly flies out of the [M]!</b></span>")
M.visible_message("<span class='warning'>A penis suddenly flies out of the [M]!</b></span>")
var/T2 = get_random_station_turf()
M.adjustBruteLoss(25)
M.Knockdown(50)
@@ -233,80 +214,71 @@
M.reagents.remove_reagent(id, volume)
return
var/mob/living/carbon/human/H = M
H.genital_override = TRUE
var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
if(!P)
H.emergent_genital_call()
return
P.prev_length = P.length
P.cached_length = P.length
if(!H.getorganslot(ORGAN_SLOT_PENIS) && H.emergent_genital_call())
H.genital_override = TRUE
/datum/reagent/fermi/penis_enlarger/on_mob_life(mob/living/carbon/M) //Increases penis size, 5u = +1 inch.
if(!ishuman(M))
return
return ..()
var/mob/living/carbon/human/H = M
var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS)
if(!P)//They do have a preponderance for escapism, or so I've heard.
//If they have Acute hepatic pharmacokinesis, then route processing though liver.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
if(HAS_TRAIT(H, TRAIT_PHARMA) || !H.canbearoused)
var/obj/item/organ/liver/L = H.getorganslot(ORGAN_SLOT_LIVER)
if(L)
L.swelling+= 0.05
return..()
L.swelling += 0.05
else
M.adjustToxLoss(1)
return..()
H.adjustToxLoss(1)
return ..()
//otherwise proceed as normal
var/obj/item/organ/genital/penis/nP = new
nP.Insert(M)
if(nP)
nP.length = 1
to_chat(M, "<span class='warning'>Your groin feels warm, as you feel a newly forming bulge down below.</b></span>")
nP.cached_length = 1
nP.prev_length = 1
M.reagents.remove_reagent(id, 5)
P = nP
P = new
P.length = 1
to_chat(H, "<span class='warning'>Your groin feels warm, as you feel a newly forming bulge down below.</b></span>")
P.prev_length = 1
H.reagents.remove_reagent(id, 5)
P.Insert(H)
P.cached_length = P.cached_length + 0.1
if (P.cached_length >= 20.5 && P.cached_length < 21)
if(H.w_uniform || H.wear_suit)
var/target = M.get_bodypart(BODY_ZONE_CHEST)
to_chat(M, "<span class='warning'>Your cock begin to strain against your clothes tightly!</b></span>")
M.apply_damage(2.5, BRUTE, target)
P.modify_size(0.1)
if (ISINRANGE_EX(P.length, 20.5, 21) && (H.w_uniform || H.wear_suit))
var/target = H.get_bodypart(BODY_ZONE_CHEST)
if(!message_spam)
to_chat(H, "<span class='danger'>Your cock begin to strain against your clothes tightly!</b></span>")
message_spam = TRUE
H.apply_damage(2.5, BRUTE, target)
P.update()
..()
return ..()
/datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders.
/datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/human/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders.
if(!istype(M))
return ..()
//Acute hepatic pharmacokinesis.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
if(HAS_TRAIT(M, TRAIT_PHARMA) || !M.canbearoused)
var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER)
L.swelling+= 0.05
return..()
var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
var/obj/item/organ/genital/testicles/T = M.getorganslot("testicles")
var/obj/item/organ/genital/vagina/V = M.getorganslot("vagina")
var/obj/item/organ/genital/womb/W = M.getorganslot("womb")
var/obj/item/organ/genital/breasts/B = M.getorganslot(ORGAN_SLOT_BREASTS)
var/obj/item/organ/genital/testicles/T = M.getorganslot(ORGAN_SLOT_TESTICLES)
var/obj/item/organ/genital/vagina/V = M.getorganslot(ORGAN_SLOT_VAGINA)
var/obj/item/organ/genital/womb/W = M.getorganslot(ORGAN_SLOT_WOMB)
if(M.gender == FEMALE)
M.gender = MALE
M.visible_message("<span class='boldnotice'>[M] suddenly looks more masculine!</span>", "<span class='boldwarning'>You suddenly feel more masculine!</span>")
if(B)
B.cached_size = B.cached_size - 0.05
B.update()
if(V)
V.Remove(M)
B.modify_size(-0.05)
if(M.getorganslot(ORGAN_SLOT_VAGINA))
qdel(V)
if(W)
W.Remove(M)
qdel(W)
if(!T)
var/obj/item/organ/genital/testicles/nT = new
nT.Insert(M)
T = nT
..()
T = new
T.Insert(M)
return ..()
/datum/reagent/fermi/PEsmaller // Due to cozmo's request...!
name = "Chastity draft"
@@ -318,19 +290,18 @@
can_synth = FALSE
/datum/reagent/fermi/PEsmaller/on_mob_life(mob/living/carbon/M)
if(!ishuman(M))
return ..()
var/mob/living/carbon/human/H = M
var/obj/item/organ/genital/penis/P = H.getorganslot("penis")
var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS)
if(!P)
//Acute hepatic pharmacokinesis.
if(HAS_TRAIT(M, TRAIT_PHARMA))
var/obj/item/organ/liver/L = M.getorganslot("liver")
var/obj/item/organ/liver/L = M.getorganslot(ORGAN_SLOT_LIVER)
L.swelling-= 0.05
return..()
//otherwise proceed as normal
return..()
P.cached_length = P.cached_length - 0.1
P.update()
P.modify_size(-0.1)
..()
/datum/reagent/fermi/PEsmaller_hypo
@@ -342,24 +313,25 @@
metabolization_rate = 0.5
can_synth = TRUE
/datum/reagent/fermi/PEsmaller_hypo/on_mob_add(mob/living/carbon/M)
/datum/reagent/fermi/PEsmaller_hypo/on_mob_metabolize(mob/living/M)
. = ..()
if(!M.getorganslot("testicles"))
if(M.dna.features["has_balls"])
var/obj/item/organ/genital/testicles/nT = new
nT.Insert(M)
if(!ishuman(M))
return
var/mob/living/carbon/human/H = M
if(!H.getorganslot(ORGAN_SLOT_PENIS) && H.dna.features["has_cock"])
H.give_genital(/obj/item/organ/genital/penis)
if(!H.getorganslot(ORGAN_SLOT_TESTICLES) && H.dna.features["has_balls"])
H.give_genital(/obj/item/organ/genital/testicles)
/datum/reagent/fermi/PEsmaller_hypo/on_mob_life(mob/living/carbon/M)
var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
var/obj/item/organ/genital/penis/P = M.getorganslot(ORGAN_SLOT_PENIS)
if(!P)
return ..()
if(!M.dna.features["has_cock"])//Fast fix for those who don't want it.
P.cached_length = P.cached_length - 0.2
P.update()
else if(P.cached_length > (M.dna.features["cock_length"]+0.1))
P.cached_length = P.cached_length - 0.1
P.update()
else if(P.cached_length < (M.dna.features["cock_length"]+0.1))
P.cached_length = P.cached_length + 0.1
P.update()
..()
var/optimal_size = M.dna.features["cock_length"]
if(!optimal_size)//Fast fix for those who don't want it.
P.modify_size(-0.2)
else if(P.length > optimal_size)
P.modify_size(-0.1, optimal_size)
else if(P.length < optimal_size)
P.modify_size(0.1, 0, optimal_size)
return ..()
@@ -6,6 +6,7 @@
id = "fermi"
taste_description = "affection and love!"
can_synth = FALSE
value = 20
impure_chem = "fermiTox"// What chemical is metabolised with an inpure reaction
inverse_chem_val = 0.25 // If the impurity is below 0.5, replace ALL of the chem with inverse_chemupon metabolising
inverse_chem = "fermiTox"
@@ -178,18 +179,20 @@
inverse_chem = "nanite_b_goneTox" //At really impure vols, it just becomes 100% inverse
taste_description = "what can only be described as licking a battery."
pH = 9
value = 90
can_synth = FALSE
var/react_objs = list()
/datum/reagent/fermi/nanite_b_gone/on_mob_life(mob/living/carbon/C)
GET_COMPONENT_FROM(N, /datum/component/nanites, C)
var/datum/component/nanites/N = C.GetComponent(/datum/component/nanites)
if(isnull(N))
return ..()
N.nanite_volume += -cached_purity*5//0.5 seems to be the default to me, so it'll neuter them.
..()
/datum/reagent/fermi/nanite_b_gone/overdose_process(mob/living/carbon/C)
GET_COMPONENT_FROM(N, /datum/component/nanites, C)
//var/component/nanites/N = M.GetComponent(/datum/component/nanites)
var/datum/component/nanites/N = C.GetComponent(/datum/component/nanites)
if(prob(5))
to_chat(C, "<span class='warning'>The residual voltage from the nanites causes you to seize up!</b></span>")
C.electrocute_act(10, (get_turf(C)), 1, FALSE, FALSE, FALSE, TRUE)
@@ -1,11 +1,3 @@
/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/effect/decal/cleanable) || istype(O, /obj/item/projectile/bullet/reusable/foam_dart) || istype(O, /obj/item/ammo_casing/caseless/foam_dart))
qdel(O)
else
if(O)
O.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
SEND_SIGNAL(O, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
/datum/reagent/syndicateadrenals
name = "Syndicate Adrenaline"
id = "syndicateadrenals"
@@ -325,10 +325,10 @@
//So slimes can play too.
/datum/chemical_reaction/fermi/enthrall/slime
required_catalysts = list("slimejelly" = 1)
required_catalysts = list("jellyblood" = 1)
/datum/chemical_reaction/fermi/enthrall/slime/FermiFinish(datum/reagents/holder, var/atom/my_atom)
var/datum/reagent/toxin/slimejelly/B = locate(/datum/reagent/toxin/slimejelly) in my_atom.reagents.reagent_list//The one line change.
var/datum/reagent/blood/jellyblood/B = locate(/datum/reagent/blood/jellyblood) in my_atom.reagents.reagent_list//The one line change.
var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in my_atom.reagents.reagent_list
if(!B.data)
var/list/seen = viewers(5, get_turf(my_atom))
@@ -1,12 +1,12 @@
/obj/item/fermichem/pHbooklet
name = "pH indicator booklet"
desc = "A booklet containing paper soaked in universal indicator."
icon_state = "pHbooklet"
icon = 'modular_citadel/icons/obj/FermiChem.dmi'
item_flags = NOBLUDGEON
var/numberOfPages = 50
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
name = "pH indicator booklet"
desc = "A booklet containing paper soaked in universal indicator."
icon_state = "pHbooklet"
icon = 'icons/obj/chemical.dmi'
item_flags = NOBLUDGEON
var/numberOfPages = 50
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
//A little janky with pockets
/obj/item/fermichem/pHbooklet/attack_hand(mob/user)
@@ -29,7 +29,7 @@
to_chat(user, "<span class='warning'>[src] is empty!</span>")
add_fingerprint(user)
return
. = ..()
. = ..()
if(. & COMPONENT_NO_INTERACT)
return
var/I = user.get_active_held_item()
@@ -37,86 +37,86 @@
user.put_in_active_hand(src)
/obj/item/fermichem/pHbooklet/MouseDrop()
var/mob/living/user = usr
if(numberOfPages >= 1)
var/obj/item/fermichem/pHpaper/P = new /obj/item/fermichem/pHpaper
P.add_fingerprint(user)
P.forceMove(user)
user.put_in_active_hand(P)
to_chat(user, "<span class='notice'>You take [P] out of \the [src].</span>")
numberOfPages--
playsound(user.loc, 'sound/items/poster_ripped.ogg', 50, 1)
add_fingerprint(user)
if(numberOfPages == 0)
icon_state = "pHbookletEmpty"
return
else
to_chat(user, "<span class='warning'>[src] is empty!</span>")
add_fingerprint(user)
return
..()
var/mob/living/user = usr
if(numberOfPages >= 1)
var/obj/item/fermichem/pHpaper/P = new /obj/item/fermichem/pHpaper
P.add_fingerprint(user)
P.forceMove(user)
user.put_in_active_hand(P)
to_chat(user, "<span class='notice'>You take [P] out of \the [src].</span>")
numberOfPages--
playsound(user.loc, 'sound/items/poster_ripped.ogg', 50, 1)
add_fingerprint(user)
if(numberOfPages == 0)
icon_state = "pHbookletEmpty"
return
else
to_chat(user, "<span class='warning'>[src] is empty!</span>")
add_fingerprint(user)
return
..()
/obj/item/fermichem/pHpaper
name = "pH indicator strip"
desc = "A piece of paper that will change colour depending on the pH of a solution."
icon_state = "pHpaper"
icon = 'modular_citadel/icons/obj/FermiChem.dmi'
item_flags = NOBLUDGEON
color = "#f5c352"
var/used = FALSE
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
name = "pH indicator strip"
desc = "A piece of paper that will change colour depending on the pH of a solution."
icon_state = "pHpaper"
icon = 'icons/obj/chemical.dmi'
item_flags = NOBLUDGEON
color = "#f5c352"
var/used = FALSE
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
/obj/item/fermichem/pHpaper/afterattack(obj/item/reagent_containers/cont, mob/user, proximity)
if(!istype(cont))
return
if(used == TRUE)
to_chat(user, "<span class='warning'>[user] has already been used!</span>")
return
if(!LAZYLEN(cont.reagents.reagent_list))
return
switch(round(cont.reagents.pH, 1))
if(14 to INFINITY)
color = "#462c83"
if(13 to 14)
color = "#63459b"
if(12 to 13)
color = "#5a51a2"
if(11 to 12)
color = "#3853a4"
if(10 to 11)
color = "#3f93cf"
if(9 to 10)
color = "#0bb9b7"
if(8 to 9)
color = "#23b36e"
if(7 to 8)
color = "#3aa651"
if(6 to 7)
color = "#4cb849"
if(5 to 6)
color = "#b5d335"
if(4 to 5)
color = "#f7ec1e"
if(3 to 4)
color = "#fbc314"
if(2 to 3)
color = "#f26724"
if(1 to 2)
color = "#ef1d26"
if(-INFINITY to 1)
color = "#c6040c"
desc += " The paper looks to be around a pH of [round(cont.reagents.pH, 1)]"
used = TRUE
if(!istype(cont))
return
if(used == TRUE)
to_chat(user, "<span class='warning'>[user] has already been used!</span>")
return
if(!LAZYLEN(cont.reagents.reagent_list))
return
switch(round(cont.reagents.pH, 1))
if(14 to INFINITY)
color = "#462c83"
if(13 to 14)
color = "#63459b"
if(12 to 13)
color = "#5a51a2"
if(11 to 12)
color = "#3853a4"
if(10 to 11)
color = "#3f93cf"
if(9 to 10)
color = "#0bb9b7"
if(8 to 9)
color = "#23b36e"
if(7 to 8)
color = "#3aa651"
if(6 to 7)
color = "#4cb849"
if(5 to 6)
color = "#b5d335"
if(4 to 5)
color = "#f7ec1e"
if(3 to 4)
color = "#fbc314"
if(2 to 3)
color = "#f26724"
if(1 to 2)
color = "#ef1d26"
if(-INFINITY to 1)
color = "#c6040c"
desc += " The paper looks to be around a pH of [round(cont.reagents.pH, 1)]"
used = TRUE
/obj/item/fermichem/pHmeter
name = "Chemistry Analyser"
desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution. The screen currently displays nothing."
icon_state = "pHmeter"
icon = 'modular_citadel/icons/obj/FermiChem.dmi'
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
var/scanmode = 1
name = "Chemistry Analyser"
desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution. The screen currently displays nothing."
icon_state = "pHmeter"
icon = 'icons/obj/chemical.dmi'
resistance_flags = FLAMMABLE
w_class = WEIGHT_CLASS_TINY
var/scanmode = 1
/obj/item/fermichem/pHmeter/attack_self(mob/user)
if(!scanmode)
@@ -127,21 +127,21 @@
scanmode = 0
/obj/item/fermichem/pHmeter/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!istype(A, /obj/item/reagent_containers))
return
var/obj/item/reagent_containers/cont = A
if(LAZYLEN(cont.reagents.reagent_list) == null)
return
var/out_message
to_chat(user, "<i>The chemistry meter beeps and displays:</i>")
out_message += "<span class='notice'><b>Total volume: [round(cont.volume, 0.01)] Total pH: [round(cont.reagents.pH, 0.1)]\n"
if(cont.reagents.fermiIsReacting)
out_message += "<span class='warning'>A reaction appears to be occuring currently.<span class='notice'>\n"
out_message += "Chemicals found in the beaker:</b>\n"
for(var/datum/reagent/R in cont.reagents.reagent_list)
out_message += "<b>[R.volume]u of [R.name]</b>, <b>Purity:</b> [R.purity], [(scanmode?"[(R.overdose_threshold?"<b>Overdose:</b> [R.overdose_threshold]u, ":"")][(R.addiction_threshold?"<b>Addiction:</b> [R.addiction_threshold]u, ":"")]<b>Base pH:</b> [R.pH].":".")]\n"
if(scanmode)
out_message += "<b>Analysis:</b> [R.description]\n"
to_chat(user, "[out_message]</span>")
desc = "An electrode attached to a small circuit box that will analyse a beaker. It can be toggled to give a reduced or extended report. The screen currently displays [round(cont.reagents.pH, 0.1)]."
. = ..()
if(!istype(A, /obj/item/reagent_containers))
return
var/obj/item/reagent_containers/cont = A
if(LAZYLEN(cont.reagents.reagent_list) == null)
return
var/out_message
to_chat(user, "<i>The chemistry meter beeps and displays:</i>")
out_message += "<span class='notice'><b>Total volume: [round(cont.volume, 0.01)] Total pH: [round(cont.reagents.pH, 0.1)]\n"
if(cont.reagents.fermiIsReacting)
out_message += "<span class='warning'>A reaction appears to be occuring currently.<span class='notice'>\n"
out_message += "Chemicals found in the beaker:</b>\n"
for(var/datum/reagent/R in cont.reagents.reagent_list)
out_message += "<b>[R.volume]u of [R.name]</b>, <b>Purity:</b> [R.purity], [(scanmode?"[(R.overdose_threshold?"<b>Overdose:</b> [R.overdose_threshold]u, ":"")][(R.addiction_threshold?"<b>Addiction:</b> [R.addiction_threshold]u, ":"")]<b>Base pH:</b> [R.pH].":".")]\n"
if(scanmode)
out_message += "<b>Analysis:</b> [R.description]\n"
to_chat(user, "[out_message]</span>")
desc = "An electrode attached to a small circuit box that will analyse a beaker. It can be toggled to give a reduced or extended report. The screen currently displays [round(cont.reagents.pH, 0.1)]."
@@ -1,41 +0,0 @@
/obj/structure/reagent_dispensers/keg
name = "keg"
desc = "A keg."
icon = 'modular_citadel/icons/obj/objects.dmi'
icon_state = "keg"
reagent_id = "water"
/obj/structure/reagent_dispensers/keg/mead
name = "keg of mead"
desc = "A keg of mead."
icon_state = "orangekeg"
reagent_id = "mead"
/obj/structure/reagent_dispensers/keg/aphro
name = "keg of aphrodisiac"
desc = "A keg of aphrodisiac."
icon_state = "pinkkeg"
reagent_id = "aphro"
/obj/structure/reagent_dispensers/keg/aphro/strong
name = "keg of strong aphrodisiac"
desc = "A keg of strong and addictive aphrodisiac."
reagent_id = "aphro+"
/obj/structure/reagent_dispensers/keg/milk
name = "keg of milk"
desc = "It's not quite what you were hoping for."
icon_state = "whitekeg"
reagent_id = "milk"
/obj/structure/reagent_dispensers/keg/semen
name = "keg of semen"
desc = "Dear lord, where did this even come from?"
icon_state = "whitekeg"
reagent_id = "semen"
/obj/structure/reagent_dispensers/keg/gargle
name = "keg of pan galactic gargleblaster"
desc = "A keg of... wow that's a long name."
icon_state = "bluekeg"
reagent_id = "gargleblaster"
@@ -1,299 +0,0 @@
#define HYPO_SPRAY 0
#define HYPO_INJECT 1
#define WAIT_SPRAY 25
#define WAIT_INJECT 25
#define SELF_SPRAY 15
#define SELF_INJECT 15
#define DELUXE_WAIT_SPRAY 20
#define DELUXE_WAIT_INJECT 20
#define DELUXE_SELF_SPRAY 10
#define DELUXE_SELF_INJECT 10
#define COMBAT_WAIT_SPRAY 0
#define COMBAT_WAIT_INJECT 0
#define COMBAT_SELF_SPRAY 0
#define COMBAT_SELF_INJECT 0
//A vial-loaded hypospray. Cartridge-based!
/obj/item/hypospray/mkii
name = "hypospray mk.II"
icon = 'modular_citadel/icons/obj/hypospraymkii.dmi'
icon_state = "hypo2"
desc = "A new development from DeForest Medical, this hypospray takes 30-unit vials as the drug supply for easy swapping."
w_class = WEIGHT_CLASS_TINY
var/list/allowed_containers = list(/obj/item/reagent_containers/glass/bottle/vial/tiny, /obj/item/reagent_containers/glass/bottle/vial/small)
var/mode = HYPO_INJECT
var/obj/item/reagent_containers/glass/bottle/vial/vial
var/start_vial = /obj/item/reagent_containers/glass/bottle/vial/small
var/spawnwithvial = TRUE
var/inject_wait = WAIT_INJECT
var/spray_wait = WAIT_SPRAY
var/spray_self = SELF_SPRAY
var/inject_self = SELF_INJECT
var/quickload = FALSE
var/penetrates = FALSE
/obj/item/hypospray/mkii/brute
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/bicaridine
/obj/item/hypospray/mkii/toxin
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/antitoxin
/obj/item/hypospray/mkii/oxygen
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/dexalin
/obj/item/hypospray/mkii/burn
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/kelotane
/obj/item/hypospray/mkii/tricord
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/tricord
/obj/item/hypospray/mkii/enlarge
spawnwithvial = FALSE
/obj/item/hypospray/mkii/CMO
name = "hypospray mk.II deluxe"
allowed_containers = list(/obj/item/reagent_containers/glass/bottle/vial/tiny, /obj/item/reagent_containers/glass/bottle/vial/small, /obj/item/reagent_containers/glass/bottle/vial/large)
icon_state = "cmo2"
desc = "The Deluxe Hypospray can take larger-size vials. It also acts faster and delivers more reagents per spray."
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
start_vial = /obj/item/reagent_containers/glass/bottle/vial/large/preloaded/CMO
inject_wait = DELUXE_WAIT_INJECT
spray_wait = DELUXE_WAIT_SPRAY
spray_self = DELUXE_SELF_SPRAY
inject_self = DELUXE_SELF_INJECT
/obj/item/hypospray/mkii/CMO/combat
name = "combat hypospray mk.II"
desc = "A combat-ready deluxe hypospray that acts almost instantly. It can be tactically reloaded by using a vial on it."
icon_state = "combat2"
start_vial = /obj/item/reagent_containers/glass/bottle/vial/large/preloaded/combat
inject_wait = COMBAT_WAIT_INJECT
spray_wait = COMBAT_WAIT_SPRAY
spray_self = COMBAT_SELF_SPRAY
inject_self = COMBAT_SELF_INJECT
quickload = TRUE
penetrates = TRUE
/obj/item/hypospray/mkii/Initialize()
. = ..()
if(!spawnwithvial)
update_icon()
return
if(start_vial)
vial = new start_vial
update_icon()
/obj/item/hypospray/mkii/update_icon()
..()
icon_state = "[initial(icon_state)][vial ? "" : "-e"]"
if(ismob(loc))
var/mob/M = loc
M.update_inv_hands()
return
/obj/item/hypospray/mkii/examine(mob/user)
. = ..()
if(vial)
to_chat(user, "[vial] has [vial.reagents.total_volume]u remaining.")
else
to_chat(user, "It has no vial loaded in.")
to_chat(user, "[src] is set to [mode ? "Inject" : "Spray"] contents on application.")
/obj/item/hypospray/mkii/proc/unload_hypo(obj/item/I, mob/user)
if((istype(I, /obj/item/reagent_containers/glass/bottle/vial)))
var/obj/item/reagent_containers/glass/bottle/vial/V = I
V.forceMove(user.loc)
user.put_in_hands(V)
to_chat(user, "<span class='notice'>You remove [vial] from [src].</span>")
vial = null
update_icon()
playsound(loc, 'sound/weapons/empty.ogg', 50, 1)
else
to_chat(user, "<span class='notice'>This hypo isn't loaded!</span>")
return
/obj/item/hypospray/mkii/attackby(obj/item/I, mob/living/user)
if((istype(I, /obj/item/reagent_containers/glass/bottle/vial) && vial != null))
if(!quickload)
to_chat(user, "<span class='warning'>[src] can not hold more than one vial!</span>")
return FALSE
unload_hypo(vial, user)
if((istype(I, /obj/item/reagent_containers/glass/bottle/vial)))
var/obj/item/reagent_containers/glass/bottle/vial/V = I
if(!is_type_in_list(V, allowed_containers))
to_chat(user, "<span class='notice'>[src] doesn't accept this type of vial.</span>")
return FALSE
if(!user.transferItemToLoc(V,src))
return FALSE
vial = V
user.visible_message("<span class='notice'>[user] has loaded a vial into [src].</span>","<span class='notice'>You have loaded [vial] into [src].</span>")
update_icon()
playsound(loc, 'sound/weapons/autoguninsert.ogg', 35, 1)
return TRUE
else
to_chat(user, "<span class='notice'>This doesn't fit in [src].</span>")
return FALSE
return FALSE
/obj/item/hypospray/mkii/AltClick(mob/user)
if(vial)
vial.attack_self(user)
// Gunna allow this for now, still really don't approve - Pooj
/obj/item/hypospray/mkii/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
to_chat(user, "[src] happens to be already overcharged.")
return
inject_wait = COMBAT_WAIT_INJECT
spray_wait = COMBAT_WAIT_SPRAY
spray_self = COMBAT_SELF_INJECT
inject_self = COMBAT_SELF_SPRAY
penetrates = TRUE
to_chat(user, "You overcharge [src]'s control circuit.")
obj_flags |= EMAGGED
return TRUE
/obj/item/hypospray/mkii/attack_hand(mob/user)
. = ..() //Don't bother changing this or removing it from containers will break.
/obj/item/hypospray/mkii/attack(obj/item/I, mob/user, params)
return
/obj/item/hypospray/mkii/afterattack(atom/target, mob/user, proximity)
if(!vial)
return
if(!proximity)
return
if(!ismob(target))
return
var/mob/living/L
if(isliving(target))
L = target
if(!penetrates && !L.can_inject(user, 1)) //This check appears another four times, since otherwise the penetrating sprays will break in do_mob.
return
if(!L && !target.is_injectable()) //only checks on non-living mobs, due to how can_inject() handles
to_chat(user, "<span class='warning'>You cannot directly fill [target]!</span>")
return
if(target.reagents.total_volume >= target.reagents.maximum_volume)
to_chat(user, "<span class='notice'>[target] is full.</span>")
return
if(ishuman(L))
var/obj/item/bodypart/affecting = L.get_bodypart(check_zone(user.zone_selected))
if(!affecting)
to_chat(user, "<span class='warning'>The limb is missing!</span>")
return
if(affecting.status != BODYPART_ORGANIC)
to_chat(user, "<span class='notice'>Medicine won't work on a robotic limb!</span>")
return
var/contained = vial.reagents.log_list()
log_combat(user, L, "attemped to inject", src, addition="which had [contained]")
//Always log attemped injections for admins
if(vial != null)
switch(mode)
if(HYPO_INJECT)
if(L) //living mob
if(L != user)
L.visible_message("<span class='danger'>[user] is trying to inject [L] with [src]!</span>", \
"<span class='userdanger'>[user] is trying to inject [L] with [src]!</span>")
if(!do_mob(user, L, inject_wait))
return
if(!penetrates && !L.can_inject(user, 1))
return
if(!vial.reagents.total_volume)
return
if(L.reagents.total_volume >= L.reagents.maximum_volume)
return
L.visible_message("<span class='danger'>[user] uses the [src] on [L]!</span>", \
"<span class='userdanger'>[user] uses the [src] on [L]!</span>")
else
if(!do_mob(user, L, inject_self))
return
if(!penetrates && !L.can_inject(user, 1))
return
if(!vial.reagents.total_volume)
return
if(L.reagents.total_volume >= L.reagents.maximum_volume)
return
log_attack("<font color='red'>[user.name] ([user.ckey]) applied [src] to [L.name] ([L.ckey]), which had [contained] (INTENT: [uppertext(user.a_intent)]) (MODE: [src.mode])</font>")
L.log_message("<font color='orange'>applied [src] to themselves ([contained]).</font>", INDIVIDUAL_ATTACK_LOG)
var/fraction = min(vial.amount_per_transfer_from_this/vial.reagents.total_volume, 1)
vial.reagents.reaction(L, INJECT, fraction)
vial.reagents.trans_to(target, vial.amount_per_transfer_from_this)
if(vial.amount_per_transfer_from_this >= 15)
playsound(loc,'sound/items/hypospray_long.ogg',50, 1, -1)
if(vial.amount_per_transfer_from_this < 15)
playsound(loc, pick('sound/items/hypospray.ogg','sound/items/hypospray2.ogg'), 50, 1, -1)
to_chat(user, "<span class='notice'>You inject [vial.amount_per_transfer_from_this] units of the solution. The hypospray's cartridge now contains [vial.reagents.total_volume] units.</span>")
if(HYPO_SPRAY)
if(L) //living mob
if(L != user)
L.visible_message("<span class='danger'>[user] is trying to spray [L] with [src]!</span>", \
"<span class='userdanger'>[user] is trying to spray [L] with [src]!</span>")
if(!do_mob(user, L, spray_wait))
return
if(!penetrates && !L.can_inject(user, 1))
return
if(!vial.reagents.total_volume)
return
if(L.reagents.total_volume >= L.reagents.maximum_volume)
return
L.visible_message("<span class='danger'>[user] uses the [src] on [L]!</span>", \
"<span class='userdanger'>[user] uses the [src] on [L]!</span>")
else
if(!do_mob(user, L, spray_self))
return
if(!penetrates && !L.can_inject(user, 1))
return
if(!vial.reagents.total_volume)
return
if(L.reagents.total_volume >= L.reagents.maximum_volume)
return
log_attack("<font color='red'>[user.name] ([user.ckey]) applied [src] to [L.name] ([L.ckey]), which had [contained] (INTENT: [uppertext(user.a_intent)]) (MODE: [src.mode])</font>")
L.log_message("<font color='orange'>applied [src] to themselves ([contained]).</font>", INDIVIDUAL_ATTACK_LOG)
var/fraction = min(vial.amount_per_transfer_from_this/vial.reagents.total_volume, 1)
vial.reagents.reaction(L, PATCH, fraction)
vial.reagents.trans_to(target, vial.amount_per_transfer_from_this)
if(vial.amount_per_transfer_from_this >= 15)
playsound(loc,'sound/items/hypospray_long.ogg',50, 1, -1)
if(vial.amount_per_transfer_from_this < 15)
playsound(loc, pick('sound/items/hypospray.ogg','sound/items/hypospray2.ogg'), 50, 1, -1)
to_chat(user, "<span class='notice'>You spray [vial.amount_per_transfer_from_this] units of the solution. The hypospray's cartridge now contains [vial.reagents.total_volume] units.</span>")
else
to_chat(user, "<span class='notice'>[src] doesn't work here!</span>")
return
/obj/item/hypospray/mkii/attack_self(mob/living/user)
if(user)
if(user.incapacitated())
return
else if(!vial)
to_chat(user, "This Hypo needs to be loaded first!")
return
else
unload_hypo(vial,user)
/obj/item/hypospray/mkii/verb/modes()
set name = "Toggle Application Mode"
set category = "Object"
set src in usr
var/mob/M = usr
switch(mode)
if(HYPO_SPRAY)
mode = HYPO_INJECT
to_chat(M, "[src] is now set to inject contents on application.")
if(HYPO_INJECT)
mode = HYPO_SPRAY
to_chat(M, "[src] is now set to spray contents on application.")
@@ -1,198 +0,0 @@
/obj/item/reagent_containers/glass/bottle/vial
name = "broken hypovial"
desc = "A hypovial compatible with most hyposprays."
icon = 'modular_citadel/icons/obj/vial.dmi'
icon_state = "hypovial"
spillable = FALSE
var/comes_with = list() //Easy way of doing this.
volume = 10
possible_transfer_amounts = list(1,2,5,10)
obj_flags = UNIQUE_RENAME
unique_reskin = list("hypovial" = "hypovial",
"red hypovial" = "hypovial-b",
"blue hypovial" = "hypovial-d",
"green hypovial" = "hypovial-a",
"orange hypovial" = "hypovial-k",
"purple hypovial" = "hypovial-p",
"black hypovial" = "hypovial-t",
"pink hypovial" = "hypovial-pink"
)
always_reskinnable = TRUE
/obj/item/reagent_containers/glass/bottle/vial/Initialize()
. = ..()
if(!icon_state)
icon_state = "hypovial"
for(var/R in comes_with)
reagents.add_reagent(R,comes_with[R])
update_icon()
/obj/item/reagent_containers/glass/bottle/vial/on_reagent_change()
update_icon()
/obj/item/reagent_containers/glass/bottle/vial/update_icon()
cut_overlays()
if(reagents.total_volume)
var/mutable_appearance/filling = mutable_appearance('modular_citadel/icons/obj/vial.dmi', "hypovial10")
var/percent = round((reagents.total_volume / volume) * 100)
switch(percent)
if(0 to 9)
filling.icon_state = "hypovial10"
if(10 to 29)
filling.icon_state = "hypovial25"
if(30 to 49)
filling.icon_state = "hypovial50"
if(50 to 85)
filling.icon_state = "hypovial75"
if(86 to INFINITY)
filling.icon_state = "hypovial100"
filling.color = mix_color_from_reagents(reagents.reagent_list)
add_overlay(filling)
/obj/item/reagent_containers/glass/bottle/vial/tiny
name = "small hypovial"
//Shouldn't be possible to get this without adminbuse
/obj/item/reagent_containers/glass/bottle/vial/small
name = "hypovial"
volume = 60
possible_transfer_amounts = list(5,10)
/obj/item/reagent_containers/glass/bottle/vial/small/bluespace
volume = 120
possible_transfer_amounts = list(5,10)
name = "bluespace hypovial"
icon_state = "hypovialbs"
unique_reskin = null
/obj/item/reagent_containers/glass/bottle/vial/large
name = "large hypovial"
desc = "A large hypovial, for deluxe hypospray models."
icon_state = "hypoviallarge"
volume = 120
possible_transfer_amounts = list(5,10,15,20)
unique_reskin = list("large hypovial" = "hypoviallarge",
"large red hypovial" = "hypoviallarge-b",
"large blue hypovial" = "hypoviallarge-d",
"large green hypovial" = "hypoviallarge-a",
"large orange hypovial" = "hypoviallarge-k",
"large purple hypovial" = "hypoviallarge-p",
"large black hypovial" = "hypoviallarge-t"
)
/obj/item/reagent_containers/glass/bottle/vial/large/update_icon()
cut_overlays()
if(reagents.total_volume)
var/mutable_appearance/filling = mutable_appearance('modular_citadel/icons/obj/vial.dmi', "hypoviallarge10")
var/percent = round((reagents.total_volume / volume) * 100)
switch(percent)
if(0 to 9)
filling.icon_state = "hypoviallarge10"
if(10 to 29)
filling.icon_state = "hypoviallarge25"
if(30 to 49)
filling.icon_state = "hypoviallarge50"
if(50 to 85)
filling.icon_state = "hypoviallarge75"
if(86 to INFINITY)
filling.icon_state = "hypoviallarge100"
filling.color = mix_color_from_reagents(reagents.reagent_list)
add_overlay(filling)
/obj/item/reagent_containers/glass/bottle/vial/large/bluespace
possible_transfer_amounts = list(5,10,15,20)
name = "bluespace large hypovial"
volume = 240
icon_state = "hypoviallargebs"
unique_reskin = null
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/bicaridine
name = "red hypovial (bicaridine)"
icon_state = "hypovial-b"
comes_with = list("bicaridine" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/antitoxin
name = "green hypovial (Anti-Tox)"
icon_state = "hypovial-a"
comes_with = list("antitoxin" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/kelotane
name = "orange hypovial (kelotane)"
icon_state = "hypovial-k"
comes_with = list("kelotane" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/dexalin
name = "blue hypovial (dexalin)"
icon_state = "hypovial-d"
comes_with = list("dexalin" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/tricord
name = "hypovial (tricordrazine)"
icon_state = "hypovial"
comes_with = list("tricordrazine" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/breastreduction
name = "pink hypovial (breast treatment)"
icon_state = "hypovial-pink"
comes_with = list("BEsmaller_hypo" = 30)
/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/penisreduction
name = "pink hypovial (penis treatment)"
icon_state = "hypovial-pink"
comes_with = list("PEsmaller_hypo" = 30)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/CMO
name = "deluxe hypovial"
icon_state = "hypoviallarge-cmos"
comes_with = list("omnizine" = 20, "leporazine" = 20, "atropine" = 20)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/bicaridine
name = "large red hypovial (bicaridine)"
icon_state = "hypoviallarge-b"
comes_with = list("bicaridine" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/antitoxin
name = "large green hypovial (anti-tox)"
icon_state = "hypoviallarge-a"
comes_with = list("antitoxin" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/kelotane
name = "large orange hypovial (kelotane)"
icon_state = "hypoviallarge-k"
comes_with = list("kelotane" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/dexalin
name = "large blue hypovial (dexalin)"
icon_state = "hypoviallarge-d"
comes_with = list("dexalin" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/charcoal
name = "large black hypovial (charcoal)"
icon_state = "hypoviallarge-t"
comes_with = list("charcoal" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/tricord
name = "large hypovial (tricord)"
icon_state = "hypoviallarge"
comes_with = list("tricordrazine" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/salglu
name = "large green hypovial (salglu)"
icon_state = "hypoviallarge-a"
comes_with = list("salglu_solution" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/synthflesh
name = "large orange hypovial (synthflesh)"
icon_state = "hypoviallarge-k"
comes_with = list("synthflesh" = 60)
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/combat
name = "combat hypovial"
icon_state = "hypoviallarge-t"
comes_with = list("epinephrine" = 3, "omnizine" = 19, "leporazine" = 19, "atropine" = 19) //Epinephrine's main effect here is to kill suff damage, so we don't need much given atropine
@@ -2,7 +2,7 @@
/datum/reagent/consumable/semen
name = "Semen"
id = "semen"
description = "Sperm from some animal. Useless for anything but insemination, really."
description = "Sperm from some animal. I bet you'll drink this out of a bucket someday."
taste_description = "something salty"
taste_mult = 2 //Not very overpowering flavor
data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null)
@@ -39,7 +39,9 @@
add_blood_DNA(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/semen/replace_decal(obj/effect/decal/cleanable/semen/S)
S.add_blood_DNA(return_blood_DNA())
if(S.blood_DNA)
blood_DNA |= S.blood_DNA.Copy()
..()
/datum/reagent/consumable/femcum
name = "Female Ejaculate"
@@ -71,7 +73,8 @@
add_blood_DNA(list("Non-human DNA" = "A+"))
/obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F)
F.add_blood_DNA(return_blood_DNA())
if(F.blood_DNA)
blood_DNA |= F.blood_DNA.Copy()
..()
/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume)
@@ -111,8 +114,8 @@
name = "Hexacrocin"
id = "aphro+"
description = "Chemically condensed form of basic crocin. This aphrodisiac is extremely powerful and addictive in most animals.\
Addiction withdrawals can cause brain damage and shortness of breath. Overdosage can lead to brain damage and a\
permanent increase in libido (commonly referred to as 'bimbofication')."
Addiction withdrawals can cause brain damage and shortness of breath. Overdosage can lead to brain damage and a \
permanent increase in libido (commonly referred to as 'bimbofication')."
taste_description = "liquid desire"
color = "#FF2BFF"//dark pink
addiction_threshold = 20
@@ -1,6 +0,0 @@
/obj/machinery/disposal/bin/alt_attack_hand(mob/user)
if(can_interact(usr))
flush = !flush
update_icon()
return TRUE
return FALSE
@@ -1,63 +1,63 @@
/datum/design/autoylathe
build_type = AUTOYLATHE
build_type = AUTOYLATHE
/datum/design/autoylathe/mech
category = list("initial", "Figurines")
category = list("initial", "Figurines")
/datum/design/autoylathe/mech/contraband
category = list("hacked", "Figurines")
category = list("hacked", "Figurines")
/datum/design/autoylathe/figure
category = list("initial", "Figurines")
category = list("initial", "Figurines")
/datum/design/autoylathe/balloon
name = "Empty Water balloon"
id = "waterballoon"
materials = list(MAT_PLASTIC = 50)
build_path = /obj/item/toy/balloon
category = list("initial", "Toys")
name = "Empty Water balloon"
id = "waterballoon"
materials = list(MAT_PLASTIC = 50)
build_path = /obj/item/toy/balloon
category = list("initial", "Toys")
/datum/design/autoylathe/spinningtoy
name = "Toy Singularity"
id = "singuloutoy"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/spinningtoy
category = list("initial", "Toys")
name = "Toy Singularity"
id = "singuloutoy"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/spinningtoy
category = list("initial", "Toys")
/datum/design/autoylathe/capgun
name = "Cap Gun"
id = "capgun"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/gun
category = list("initial", "Pistols")
name = "Cap Gun"
id = "capgun"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/gun
category = list("initial", "Pistols")
/datum/design/autoylathe/capgunammo
name = "Capgun Ammo"
id = "capgunammo"
materials = list(MAT_PLASTIC = 50)
build_path = /obj/item/toy/ammo/gun
category = list("initial", "misc")
name = "Capgun Ammo"
id = "capgunammo"
materials = list(MAT_PLASTIC = 50)
build_path = /obj/item/toy/ammo/gun
category = list("initial", "misc")
/datum/design/autoylathe/toysword
name = "Toy Sword"
id = "toysword"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/sword
category = list("initial", "Melee")
name = "Toy Sword"
id = "toysword"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/sword
category = list("initial", "Melee")
/datum/design/autoylathe/foamblade
name = "Foam Armblade"
id = "foamblade"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/foamblade
category = list("initial", "Melee")
name = "Foam Armblade"
id = "foamblade"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/foamblade
category = list("initial", "Melee")
/datum/design/autoylathe/windupbox
name = "Wind Up Toolbox"
id = "windupbox"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/windupToolbox
category = list("initial", "Toys")
name = "Wind Up Toolbox"
id = "windupbox"
materials = list(MAT_PLASTIC = 500)
build_path = /obj/item/toy/windupToolbox
category = list("initial", "Toys")
/datum/design/autoylathe/toydualsword
name = "Double-Bladed Toy Sword"
@@ -456,11 +456,11 @@
category = list("hacked", "Figurines")
/datum/design/autoylathe/figure/wizard
name = "Wizard"
id = "wizfigure"
materials = list(MAT_PLASTIC = 500, MAT_METAL = 50)
build_path = /obj/item/toy/figure/wizard
category = list("hacked", "Figurines")
name = "Wizard"
id = "wizfigure"
materials = list(MAT_PLASTIC = 500, MAT_METAL = 50)
build_path = /obj/item/toy/figure/wizard
category = list("hacked", "Figurines")
/datum/design/autoylathe/dildo
name = "Customizable Dildo"
@@ -521,23 +521,25 @@
//because why not make a boxed kit with all of the lastag shit?
/obj/item/storage/box/blueteam
name = "Blue Team Kit"
/obj/item/storage/box/blueteam/PopulateContents()
new /obj/item/clothing/head/helmet/bluetaghelm(src)
new /obj/item/clothing/suit/bluetag(src)
new /obj/item/gun/energy/laser/bluetag(src)
new /obj/item/clothing/gloves/color/blue(src)
new /obj/item/clothing/shoes/sneakers/blue(src)
new /obj/item/clothing/under/color/blue(src)
new /obj/item/clothing/head/helmet/bluetaghelm(src)
new /obj/item/clothing/suit/bluetag(src)
new /obj/item/gun/energy/laser/bluetag(src)
new /obj/item/clothing/gloves/color/blue(src)
new /obj/item/clothing/shoes/sneakers/blue(src)
new /obj/item/clothing/under/color/blue(src)
/obj/item/storage/box/redteam
name = "Red Team Kit"
/obj/item/storage/box/redteam/PopulateContents()
new /obj/item/clothing/head/helmet/redtaghelm(src)
new /obj/item/clothing/suit/redtag(src)
new /obj/item/gun/energy/laser/redtag(src)
new /obj/item/clothing/gloves/color/red(src)
new /obj/item/clothing/shoes/sneakers/red(src)
new /obj/item/clothing/under/color/red(src)
new /obj/item/clothing/head/helmet/redtaghelm(src)
new /obj/item/clothing/suit/redtag(src)
new /obj/item/gun/energy/laser/redtag(src)
new /obj/item/clothing/gloves/color/red(src)
new /obj/item/clothing/shoes/sneakers/red(src)
new /obj/item/clothing/under/color/red(src)
/datum/design/autoylathe/lastag/blue
name = "Blue Lasertag Kit"
@@ -1,6 +0,0 @@
/datum/design/board/autoylathe
name = "Machine Design (Autoylathe)"
desc = "The circuit board for an autoylathe."
id = "autoylathe"
build_path = /obj/item/circuitboard/machine/autoylathe
category = list("Misc. Machinery")
@@ -1,7 +0,0 @@
/datum/design/mag_oldsmg/rubber_mag
name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)"
desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG"
id = "mag_oldsmg_rubber"
materials = list(MAT_METAL = 6000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
@@ -1,7 +0,0 @@
/datum/design/mag_oldsmg/tx_mag
name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)"
desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_tx"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wttx
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
@@ -1,25 +0,0 @@
/datum/design/xenobio_upgrade
name = "owo"
desc = "someone's bussin"
build_type = PROTOLATHE
materials = list(MAT_METAL = 300, MAT_GLASS = 100)
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/xenobio_upgrade/xenobiomonkeys
name = "Xenobiology console monkey upgrade disk"
desc = "This disk will add the ability to remotely recycle monkeys via the Xenobiology console."
id = "xenobio_monkeys"
build_path = /obj/item/disk/xenobio_console_upgrade/monkey
/datum/design/xenobio_upgrade/xenobioslimebasic
name = "Xenobiology console basic slime upgrade disk"
desc = "This disk will add the ability to remotely manipulate slimes via the Xenobiology console."
id = "xenobio_slimebasic"
build_path = /obj/item/disk/xenobio_console_upgrade/slimebasic
/datum/design/xenobio_upgrade/xenobioslimeadv
name = "Xenobiology console advanced slime upgrade disk"
desc = "This disk will add the ability to remotely feed slimes potions via the Xenobiology console, and lift the restrictions on the number of slimes that can be stored inside the Xenobiology console. This includes the contents of the basic slime upgrade disk."
id = "xenobio_slimeadv"
build_path = /obj/item/disk/xenobio_console_upgrade/slimeadv
@@ -1,3 +0,0 @@
/datum/techweb/specialized/autounlocking/autoylathe
design_autounlock_buildtypes = AUTOYLATHE
allowed_buildtypes = AUTOYLATHE
@@ -1,48 +0,0 @@
/obj/machinery/computer/camera_advanced/xenobio
max_slimes = 1
var/upgradetier = 0
/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/disk/xenobio_console_upgrade))
var/obj/item/disk/xenobio_console_upgrade/diskthing = O
var/successfulupgrade = FALSE
for(var/I in diskthing.upgradetypes)
if(upgradetier & I)
continue
else
upgradetier |= I
successfulupgrade = TRUE
if(I == XENOBIO_UPGRADE_SLIMEADV)
max_slimes = 10
if(successfulupgrade)
to_chat(user, "<span class='notice'>You have successfully upgraded [src] with [O].</span>")
else
to_chat(user, "<span class='warning'>[src] already has the contents of [O] installed!</span>")
return
. = ..()
/obj/item/disk/xenobio_console_upgrade
name = "Xenobiology console upgrade disk"
desc = "Allan please add detail."
icon_state = "datadisk5"
var/list/upgradetypes = list()
/obj/item/disk/xenobio_console_upgrade/admin
name = "Xenobio all access thing"
desc = "'the consoles are literally useless!!!!!!!!!!!!!!!'"
upgradetypes = list(XENOBIO_UPGRADE_SLIMEBASIC, XENOBIO_UPGRADE_SLIMEADV, XENOBIO_UPGRADE_MONKEYS)
/obj/item/disk/xenobio_console_upgrade/monkey
name = "Xenobiology console monkey upgrade disk"
desc = "This disk will add the ability to remotely recycle monkeys via the Xenobiology console."
upgradetypes = list(XENOBIO_UPGRADE_MONKEYS)
/obj/item/disk/xenobio_console_upgrade/slimebasic
name = "Xenobiology console basic slime upgrade disk"
desc = "This disk will add the ability to remotely manipulate slimes via the Xenobiology console."
upgradetypes = list(XENOBIO_UPGRADE_SLIMEBASIC)
/obj/item/disk/xenobio_console_upgrade/slimeadv
name = "Xenobiology console advanced slime upgrade disk"
desc = "This disk will add the ability to remotely feed slimes potions via the Xenobiology console, and lift the restrictions on the number of slimes that can be stored inside the Xenobiology console. This includes the contents of the basic slime upgrade disk."
upgradetypes = list(XENOBIO_UPGRADE_SLIMEBASIC, XENOBIO_UPGRADE_SLIMEADV)
@@ -1,54 +0,0 @@
/obj/vehicle/ridden/secway
var/chargemax = 150
var/chargerate = 0.35
var/charge = 150
var/chargespeed = 1
var/normalspeed = 2
var/last_tick = 0
var/list/progressbars_by_rider = list()
/obj/vehicle/ridden/secway/Initialize()
. = ..()
START_PROCESSING(SSfastprocess, src)
/obj/vehicle/ridden/secway/process()
var/diff = world.time - last_tick
var/regen = chargerate * diff
charge = CLAMP(charge + regen, 0, chargemax)
last_tick = world.time
/obj/vehicle/ridden/secway/relaymove(mob/user, direction)
var/new_speed = normalspeed
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.sprinting && charge)
charge--
new_speed = chargespeed
GET_COMPONENT(D, /datum/component/riding)
D.vehicle_move_delay = new_speed
for(var/i in progressbars_by_rider)
var/datum/progressbar/B = progressbars_by_rider[i]
B.update(charge)
return ..()
/obj/vehicle/ridden/secway/buckle_mob(mob/living/M, force, check_loc)
. = ..(M, force, check_loc)
if(.)
if(progressbars_by_rider[M])
qdel(progressbars_by_rider[M])
var/datum/progressbar/D = new(M, chargemax, src)
D.update(charge)
progressbars_by_rider[M] = D
/obj/vehicle/ridden/secway/unbuckle_mob(mob/living/M, force)
. = ..(M, force)
if(.)
qdel(progressbars_by_rider[M])
progressbars_by_rider -= M
/obj/vehicle/ridden/secway/Destroy()
for(var/i in progressbars_by_rider)
qdel(progressbars_by_rider[i])
progressbars_by_rider.Cut()
STOP_PROCESSING(SSfastprocess, src)
return ..()
@@ -1,162 +0,0 @@
// THIS IS NOW MERELY LEGACY, because memes. hopefully it won't be dumb.
//
// The belly object is what holds onto a mob while they're inside a predator.
// It takes care of altering the pred's decription, digesting the prey, relaying struggles etc.
//
// If you change what variables are on this, then you need to update the copy() proc.
//
// Parent type of all the various "belly" varieties.
//
/datum/belly
var/name // Name of this location
var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone
var/vore_verb = "ingest" // Verb for eating with this in messages
var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human
var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else
var/emoteTime = 30 SECONDS // How long between stomach emotes at prey
var/digest_brute = 0 // Brute damage per tick in digestion mode
var/digest_burn = 1 // Burn damage per tick in digestion mode
var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on
var/immutable = FALSE // Prevents this belly from being deleted
var/escapable = FALSE // Belly can be resisted out of at any time
var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play?
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
var/autotransferwait = 10 // Time between trying to transfer.
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
var/tmp/mob/living/owner // The mob whose belly this is.
var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
var/swallow_time = 10 SECONDS // for mob transfering automation
var/vore_capacity = 1 // The capacity (in people) this person can hold
// Don't forget to watch your commas at the end of each line if you change these.
var/list/struggle_messages_outside = list(
"%pred's %belly wobbles with a squirming meal.",
"%pred's %belly jostles with movement.",
"%pred's %belly briefly swells outward as someone pushes from inside.",
"%pred's %belly fidgets with a trapped victim.",
"%pred's %belly jiggles with motion from inside.",
"%pred's %belly sloshes around.",
"%pred's %belly gushes softly.",
"%pred's %belly lets out a wet squelch.")
var/list/struggle_messages_inside = list(
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
"Your struggles only cause %pred's %belly to gush softly around you.",
"Your movement only causes %pred's %belly to slosh around you.",
"Your motion causes %pred's %belly to jiggle.",
"You fidget around inside of %pred's %belly.",
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
"You jostle %pred's %belly with movement.",
"You squirm inside of %pred's %belly, making it wobble around.")
var/list/digest_messages_owner = list(
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
"Your %belly lets out a rumble as it melts %prey into sludge.",
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
var/list/digest_messages_prey = list(
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
"%pred's %belly lets out a rumble as it melts you into sludge.",
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
var/list/examine_messages = list(
"They have something solid in their %belly!",
"It looks like they have something in their %belly!")
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
var/list/emote_lists = list()
//OLD: This only exists for legacy conversion purposes
//It's called whenever an old datum-style belly is loaded
/datum/belly/proc/copy(obj/belly/new_belly)
//// Non-object variables
new_belly.name = name
new_belly.desc = inside_flavor
new_belly.vore_sound = vore_sound
new_belly.vore_verb = vore_verb
new_belly.human_prey_swallow_time = human_prey_swallow_time
new_belly.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
new_belly.emote_time = emoteTime
new_belly.digest_brute = digest_brute
new_belly.digest_burn = digest_burn
new_belly.immutable = immutable
new_belly.can_taste = can_taste
new_belly.escapable = escapable
new_belly.escapetime = escapetime
new_belly.digestchance = digestchance
new_belly.escapechance = escapechance
new_belly.transferchance = transferchance
new_belly.transferlocation = transferlocation
//// Object-holding variables
//struggle_messages_outside - strings
new_belly.struggle_messages_outside.Cut()
for(var/I in struggle_messages_outside)
new_belly.struggle_messages_outside += I
//struggle_messages_inside - strings
new_belly.struggle_messages_inside.Cut()
for(var/I in struggle_messages_inside)
new_belly.struggle_messages_inside += I
//digest_messages_owner - strings
new_belly.digest_messages_owner.Cut()
for(var/I in digest_messages_owner)
new_belly.digest_messages_owner += I
//digest_messages_prey - strings
new_belly.digest_messages_prey.Cut()
for(var/I in digest_messages_prey)
new_belly.digest_messages_prey += I
//examine_messages - strings
new_belly.examine_messages.Cut()
for(var/I in examine_messages)
new_belly.examine_messages += I
//emote_lists - index: digest mode, key: list of strings
new_belly.emote_lists.Cut()
for(var/K in emote_lists)
new_belly.emote_lists[K] = list()
for(var/I in emote_lists[K])
new_belly.emote_lists[K] += I
return new_belly
// // // // // // // // // // // //
// // // LEGACY USE ONLY!! // // //
// // // // // // // // // // // //
// See top of file! //
// // // // // // // // // // // //
@@ -1,677 +0,0 @@
//#define VORE_SOUND_FALLOFF 0.05
//
// Belly system 2.0, now using objects instead of datums because EH at datums.
// How many times have I rewritten bellies and vore now? -Aro
//
// If you change what variables are on this, then you need to update the copy() proc.
//
// Parent type of all the various "belly" varieties.
//
/obj/belly
name = "belly" // Name of this location
desc = "It's a belly! You're in it!" // Flavor text description of inside sight/sound/smells/feels.
var/vore_sound = "Gulp" // Sound when ingesting someone
var/vore_verb = "ingest" // Verb for eating with this in messages
var/release_sound = "Splatter" // Sound for letting someone out.
var/human_prey_swallow_time = 100 // Time in deciseconds to swallow /mob/living/carbon/human
var/nonhuman_prey_swallow_time = 30 // Time in deciseconds to swallow anything else
var/emote_time = 60 SECONDS // How long between stomach emotes at prey
var/digest_brute = 2 // Brute damage per tick in digestion mode
var/digest_burn = 2 // Burn damage per tick in digestion mode
var/immutable = FALSE // Prevents this belly from being deleted
var/escapable = TRUE // Belly can be resisted out of at any time
var/escapetime = 20 SECONDS // Deciseconds, how long to escape this belly
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
var/absorbchance = 0 // % Chance of stomach beginning to absorb if prey struggles
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
var/bulge_size = 0.25 // The minimum size the prey has to be in order to show up on examine.
// var/shrink_grow_size = 1 // This horribly named variable determines the minimum/maximum size it will shrink/grow prey to.
var/transferlocation // Location that the prey is released if they struggle and get dropped off.
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
var/autotransferwait = 10 // Time between trying to transfer.
var/swallow_time = 10 SECONDS // for mob transfering automation
var/vore_capacity = 1 // simple animal nom capacity
var/is_wet = TRUE // Is this belly inside slimy parts?
//I don't think we've ever altered these lists. making them static until someone actually overrides them somewhere.
var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY,DM_ABSORB,DM_UNABSORB) // Possible digest modes
var/tmp/mob/living/owner // The mob whose belly this is.
var/tmp/digest_mode = DM_HOLD // Current mode the belly is set to from digest_modes (+transform_modes if human)
var/tmp/next_process = 0 // Waiting for this SSbellies times_fired to process again.
var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again.
var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick #
var/tmp/recent_sound // Prevent audio spam
var/tmp/last_hearcheck = 0
var/tmp/list/hearing_mobs
// Don't forget to watch your commas at the end of each line if you change these.
var/list/struggle_messages_outside = list(
"%pred's %belly wobbles with a squirming meal.",
"%pred's %belly jostles with movement.",
"%pred's %belly briefly swells outward as someone pushes from inside.",
"%pred's %belly fidgets with a trapped victim.",
"%pred's %belly jiggles with motion from inside.",
"%pred's %belly sloshes around.",
"%pred's %belly gushes softly.",
"%pred's %belly lets out a wet squelch.")
var/list/struggle_messages_inside = list(
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
"Your struggles only cause %pred's %belly to gush softly around you.",
"Your movement only causes %pred's %belly to slosh around you.",
"Your motion causes %pred's %belly to jiggle.",
"You fidget around inside of %pred's %belly.",
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
"You jostle %pred's %belly with movement.",
"You squirm inside of %pred's %belly, making it wobble around.")
var/list/digest_messages_owner = list(
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
"Your %belly lets out a rumble as it melts %prey into sludge.",
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
var/list/digest_messages_prey = list(
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
"%pred's %belly lets out a rumble as it melts you into sludge.",
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
var/list/examine_messages = list(
"They have something solid in their %belly!",
"It looks like they have something in their %belly!")
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
var/tmp/list/emote_lists = list()
//For serialization, keep this updated AND IN ORDER OF VARS LISTED ABOVE AND IN DUPE AT THE BOTTOM!!, required for bellies to save correctly.
/obj/belly/vars_to_save()
return ..() + list(
"name",
"desc",
"vore_sound",
"vore_verb",
"release_sound",
"human_prey_swallow_time",
"nonhuman_prey_swallow_time",
"emote_time",
"digest_brute",
"digest_burn",
"immutable",
"escapable",
"escapetime",
"digestchance",
"absorbchance",
"escapechance",
"can_taste",
"bulge_size",
"transferlocation",
"transferchance",
"autotransferchance",
"autotransferwait",
"swallow_time",
"vore_capacity",
"struggle_messages_outside",
"struggle_messages_inside",
"digest_messages_owner",
"digest_messages_prey",
"examine_messages",
"emote_lists",
"is_wet"
)
//ommitted list
// "shrink_grow_size",
/obj/belly/New(var/newloc)
. = ..(newloc)
//If not, we're probably just in a prefs list or something.
if(isliving(newloc))
owner = loc
owner.vore_organs |= src
SSbellies.belly_list += src
/obj/belly/Destroy()
if(owner)
Remove(owner)
return ..()
/obj/belly/proc/Remove(mob/living/owner)
owner.vore_organs -= src
owner = null
// Called whenever an atom enters this belly
/obj/belly/Entered(var/atom/movable/thing,var/atom/OldLoc)
if(OldLoc in contents)
return //Someone dropping something (or being stripdigested)
//Generic entered message
to_chat(owner,"<span class='notice'>[thing] slides into your [lowertext(name)].</span>")
//Sound w/ antispam flag setting
if(is_wet && (world.time > recent_sound))
var/turf/source = get_turf(owner)
var/sound/eating = GLOB.vore_sounds[vore_sound]
for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
SEND_SOUND(M, eating)
recent_sound = (world.time + 20 SECONDS)
//Messages if it's a mob
if(isliving(thing))
var/mob/living/M = thing
if(desc)
to_chat(M, "<span class='notice'><B>[desc]</B></span>")
// Release all contents of this belly into the owning mob's location.
// If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in.
// Returns the number of mobs so released.
/obj/belly/proc/release_all_contents(var/include_absorbed = FALSE, var/silent = FALSE)
var/atom/destination = drop_location()
//Don't bother if we don't have contents
if(!contents.len)
return FALSE
var/count = 0
for(var/thing in contents)
var/atom/movable/AM = thing
if(isliving(AM))
var/mob/living/L = AM
var/mob/living/OW = owner
if(L.absorbed && !include_absorbed)
continue
L.absorbed = FALSE
L.stop_sound_channel(CHANNEL_PREYLOOP)
L.cure_blind("belly_[REF(src)]")
SEND_SIGNAL(OW, COMSIG_CLEAR_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
SEND_SIGNAL(OW, COMSIG_ADD_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
AM.forceMove(destination) // Move the belly contents into the same location as belly's owner.
count++
for(var/mob/living/M in get_hearers_in_view(2, get_turf(owner)))
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
var/sound/releasement = GLOB.release_sounds[release_sound]
SEND_SOUND(M, releasement)
//Clean up our own business
items_preserved.Cut()
if(isanimal(owner))
owner.update_icons()
if(!silent)
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
items_preserved.Cut()
owner.update_icons()
return count
// Release a specific atom from the contents of this belly into the owning mob's location.
// If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in.
// Returns the number of atoms so released.
/obj/belly/proc/release_specific_contents(var/atom/movable/M, var/silent = FALSE)
if (!(M in contents))
return FALSE // They weren't in this belly anyway
M.forceMove(drop_location()) // Move the belly contents into the same location as belly's owner.
items_preserved -= M
if(!silent)
for(var/mob/living/H in get_hearers_in_view(2, get_turf(owner)))
if(H.client && (H.client.prefs.cit_toggles & EATING_NOISES))
var/sound/releasement = GLOB.release_sounds[release_sound]
SEND_SOUND(H, releasement)
if(istype(M,/mob/living))
var/mob/living/ML = M
var/mob/living/OW = owner
ML.stop_sound_channel(CHANNEL_PREYLOOP)
ML.cure_blind("belly_[REF(src)]")
SEND_SIGNAL(OW, COMSIG_CLEAR_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
SEND_SIGNAL(ML, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
SEND_SIGNAL(OW, COMSIG_ADD_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
SEND_SIGNAL(ML, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
if(ML.absorbed)
ML.absorbed = FALSE
if(ishuman(M) && ishuman(OW))
var/mob/living/carbon/human/Prey = M
var/mob/living/carbon/human/Pred = OW
var/absorbed_count = 2 //Prey that we were, plus the pred gets a portion
for(var/mob/living/P in contents)
if(P.absorbed)
absorbed_count++
Pred.reagents.trans_to(Prey, Pred.reagents.total_volume / absorbed_count)
//Clean up our own business
if(isanimal(owner))
owner.update_icons()
if(!silent)
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
owner.update_icons()
return TRUE
// Actually perform the mechanics of devouring the tasty prey.
// The purpose of this method is to avoid duplicate code, and ensure that all necessary
// steps are taken.
/obj/belly/proc/nom_mob(var/mob/prey, var/mob/user)
if(owner.stat == DEAD)
return
if (prey.buckled)
prey.buckled.unbuckle_mob(prey,TRUE)
if(!isbelly(prey.loc))
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "fedpred", /datum/mood_event/fedpred)
SEND_SIGNAL(prey, COMSIG_ADD_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
else
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "emptypred", /datum/mood_event/emptypred)
SEND_SIGNAL(prey, COMSIG_CLEAR_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
prey.forceMove(src)
owner.updateVRPanel()
for(var/mob/living/M in contents)
M.updateVRPanel()
M.become_blind("belly_[REF(src)]")
// Setup the autotransfer checks if needed
if(transferlocation != null && autotransferchance > 0)
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
/obj/belly/proc/check_autotransfer(var/mob/prey, var/obj/belly/target)
// Some sanity checks
if(transferlocation && (autotransferchance > 0) && (prey in contents))
if(prob(autotransferchance))
transfer_contents(prey, transferlocation)
else
// Didn't transfer, so wait before retrying
addtimer(CALLBACK(src, /obj/belly/.proc/check_autotransfer, prey), autotransferwait)
//Transfers contents from one belly to another
/obj/belly/proc/transfer_contents(var/atom/movable/content, var/obj/belly/target, silent = FALSE)
if(!(content in src) || !istype(target))
return
for(var/mob/living/M in contents)
M.cure_blind("belly_[REF(src)]")
target.nom_mob(content, target.owner)
if(!silent)
var/turf/source = get_turf(owner)
var/sound/eating = GLOB.vore_sounds[vore_sound]
for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
SEND_SOUND(M, eating)
owner.updateVRPanel()
for(var/mob/living/M in contents)
M.updateVRPanel()
// Get the line that should show up in Examine message if the owner of this belly
// is examined. By making this a proc, we not only take advantage of polymorphism,
// but can easily make the message vary based on how many people are inside, etc.
// Returns a string which shoul be appended to the Examine output.
/obj/belly/proc/get_examine_msg()
if(contents.len && examine_messages.len)
var/formatted_message
var/raw_message = pick(examine_messages)
var/total_bulge = 0
formatted_message = replacetext(raw_message,"%belly",lowertext(name))
formatted_message = replacetext(formatted_message,"%pred",owner)
formatted_message = replacetext(formatted_message,"%prey",english_list(contents))
for(var/mob/living/P in contents)
if(!P.absorbed) //This is required first, in case there's a person absorbed and not absorbed in a stomach.
total_bulge += P.mob_size
if(total_bulge >= bulge_size && bulge_size != 0)
return("<span class='warning'>[formatted_message]</span><BR>")
else
return ""
// The next function gets the messages set on the belly, in human-readable format.
// This is useful in customization boxes and such. The delimiter right now is \n\n so
// in message boxes, this looks nice and is easily delimited.
/obj/belly/proc/get_messages(var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_messages
switch(type)
if("smo")
raw_messages = struggle_messages_outside
if("smi")
raw_messages = struggle_messages_inside
if("dmo")
raw_messages = digest_messages_owner
if("dmp")
raw_messages = digest_messages_prey
if("em")
raw_messages = examine_messages
var/messages = list2text(raw_messages,delim)
return messages
// The next function sets the messages on the belly, from human-readable var
// replacement strings and linebreaks as delimiters (two \n\n by default).
// They also sanitize the messages.
/obj/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_list = text2list(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
testing("[owner] tried to set [lowertext(name)] with 11+ messages")
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
raw_list.Cut(i,i)
testing("[owner] tried to set [lowertext(name)] with >121 or <10 char message")
else
raw_list[i] = readd_quotes(raw_list[i])
//Also fix % sign for var replacement
raw_list[i] = replacetext(raw_list[i],"&#37;","%")
ASSERT(raw_list.len <= 10) //Sanity
switch(type)
if("smo")
struggle_messages_outside = raw_list
if("smi")
struggle_messages_inside = raw_list
if("dmo")
digest_messages_owner = raw_list
if("dmp")
digest_messages_prey = raw_list
if("em")
examine_messages = raw_list
return
// Handle the death of a mob via digestion.
// Called from the process_Life() methods of bellies that digest prey.
// Default implementation calls M.death() and removes from internal contents.
// Indigestable items are removed, and M is deleted.
/obj/belly/proc/digestion_death(var/mob/living/M)
//M.death(1) // "Stop it he's already dead..." Basically redundant and the reason behind screaming mouse carcasses.
if(M.ckey)
message_admins("[key_name(owner)] has digested [key_name(M)] in their [lowertext(name)] ([owner ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[owner.x];Y=[owner.y];Z=[owner.z]'>JMP</a>" : "null"])")
log_attack("[key_name(owner)] digested [key_name(M)].")
// If digested prey is also a pred... anyone inside their bellies gets moved up.
if(is_vore_predator(M))
M.release_vore_contents(include_absorbed = TRUE, silent = TRUE)
//Drop all items into the belly
for(var/obj/item/W in M)
if(!M.dropItemToGround(W))
qdel(W)
// Delete the digested mob
qdel(M)
M.stop_sound_channel(CHANNEL_PREYLOOP)
//Update owner
owner.updateVRPanel()
// Handle a mob being absorbed
/obj/belly/proc/absorb_living(var/mob/living/M)
M.absorbed = TRUE
to_chat(M,"<span class='notice'>[owner]'s [lowertext(name)] absorbs your body, making you part of them.</span>")
to_chat(owner,"<span class='notice'>Your [lowertext(name)] absorbs [M]'s body, making them part of you.</span>")
if(M.loc != src)
M.forceMove(src)
//Seek out absorbed prey of the prey, absorb them too.
//This in particular will recurse oddly because if there is absorbed prey of prey of prey...
//it will just move them up one belly. This should never happen though since... when they were
//absobred, they should have been absorbed as well!
for(var/belly in M.vore_organs)
var/obj/belly/B = belly
for(var/mob/living/Mm in B)
if(Mm.absorbed)
absorb_living(Mm)
//Update owner
owner.updateVRPanel()
//Digest a single item
//Receives a return value from digest_act that's how much nutrition
//the item should be worth
/obj/belly/proc/digest_item(var/obj/item/item)
var/digested = item.digest_act(src, owner)
if(!digested)
items_preserved |= item
else
// owner.nutrition += (5 * digested) // haha no.
if(iscyborg(owner))
var/mob/living/silicon/robot/R = owner
R.cell.charge += (50 * digested)
//Determine where items should fall out of us into.
//Typically just to the owner's location.
/obj/belly/drop_location()
//Should be the case 99.99% of the time
if(owner)
return owner.loc
//Sketchy fallback for safety, put them somewhere safe.
else if(ismob(src))
testing("[src] (\ref[src]) doesn't have an owner, and dropped someone at a latespawn point!")
SSjob.SendToLateJoin(src)
// wew lad. let's see if this never gets used, hopefully
else
qdel(src) //final option, I guess.
testing("[src] (\ref[src]) was QDEL'd for not having a drop_location!")
//Yes, it's ""safe"" to drop items here
/obj/belly/AllowDrop()
return TRUE
/*
/obj/belly/onDropInto(var/atom/movable/AM)
return null */
//Handle a mob struggling
// Called from /mob/living/carbon/relaymove()
/obj/belly/proc/relay_resist(var/mob/living/R)
if (!(R in contents))
return // User is not in this belly
R.setClickCooldown(50)
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
to_chat(R,"<span class='warning'>You attempt to climb out of \the [lowertext(name)]. (This will take around [escapetime/10] seconds.)</span>")
to_chat(owner,"<span class='warning'>Someone is attempting to climb out of your [lowertext(name)]!</span>")
if(do_after(R, owner, escapetime))
if((owner.stat || escapable) && (R.loc == src)) //Can still escape?
release_specific_contents(R)
return
else if(R.loc != src) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable or mob revived
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed!</span>")
to_chat(owner,"<span class='notice'>The attempt to escape from your [lowertext(name)] has failed!</span>")
return
return
var/struggle_outer_message = pick(struggle_messages_outside)
var/struggle_user_message = pick(struggle_messages_inside)
struggle_outer_message = replacetext(struggle_outer_message,"%pred",owner)
struggle_outer_message = replacetext(struggle_outer_message,"%prey",R)
struggle_outer_message = replacetext(struggle_outer_message,"%belly",lowertext(name))
struggle_user_message = replacetext(struggle_user_message,"%pred",owner)
struggle_user_message = replacetext(struggle_user_message,"%prey",R)
struggle_user_message = replacetext(struggle_user_message,"%belly",lowertext(name))
struggle_outer_message = "<span class='alert'>" + struggle_outer_message + "</span>"
struggle_user_message = "<span class='alert'>" + struggle_user_message + "</span>"
var/turf/source = get_turf(owner)
var/sound/struggle_snuggle = sound(get_sfx("struggle_sound"))
var/sound/struggle_rustle = sound(get_sfx("rustle"))
if(is_wet)
for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
SEND_SOUND(M, struggle_snuggle)
else
for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
SEND_SOUND(M, struggle_rustle)
var/list/watching = hearers(3, owner)
for(var/mob/living/M in watching)
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) //Might as well censor the normies here too.
M.show_message(struggle_outer_message, 1) // visible
to_chat(R,struggle_user_message)
if(escapable) //If the stomach has escapable enabled.
if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
to_chat(R,"<span class='warning'>You start to climb out of \the [lowertext(name)].</span>")
to_chat(owner,"<span class='warning'>Someone is attempting to climb out of your [lowertext(name)]!</span>")
if(do_after(R, escapetime))
if((owner.stat || escapable) && (R.loc == src)) //Can still escape?
release_specific_contents(R)
return
else if(R.loc != src) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable or mob revived
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed!</span>")
to_chat(owner,"<span class='notice'>The attempt to escape from your [lowertext(name)] has failed!</span>")
return
else if(prob(transferchance) && transferlocation) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
var/obj/belly/dest_belly
for(var/belly in owner.vore_organs)
var/obj/belly/B = belly
if(B.name == transferlocation)
dest_belly = B
break
if(!dest_belly)
to_chat(owner, "<span class='warning'>Something went wrong with your belly transfer settings. Your <b>[lowertext(name)]</b> has had it's transfer chance and transfer location cleared as a precaution.</span>")
transferchance = 0
transferlocation = null
return
to_chat(R,"<span class='warning'>Your attempt to escape [lowertext(name)] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!</span>")
to_chat(owner,"<span class='warning'>Someone slid into your [transferlocation] due to their struggling inside your [lowertext(name)]!</span>")
transfer_contents(R, dest_belly)
return
else if(prob(absorbchance) && digest_mode != DM_ABSORB) //After that, let's have it run the absorb chance.
to_chat(R,"<span class='warning'>In response to your struggling, \the [lowertext(name)] begins to cling more tightly...</span>")
to_chat(owner,"<span class='warning'>You feel your [lowertext(name)] start to cling onto its contents...</span>")
digest_mode = DM_ABSORB
return
else if(prob(digestchance) && digest_mode != DM_DIGEST) //Finally, let's see if it should run the digest chance.
to_chat(R,"<span class='warning'>In response to your struggling, \the [lowertext(name)] begins to get more active...</span>")
to_chat(owner,"<span class='warning'>You feel your [lowertext(name)] beginning to become active!</span>")
digest_mode = DM_DIGEST
return
else //Nothing interesting happened.
to_chat(R,"<span class='warning'>You make no progress in escaping [owner]'s [lowertext(name)].</span>")
to_chat(owner,"<span class='warning'>Your prey appears to be unable to make any progress in escaping your [lowertext(name)].</span>")
return
/obj/belly/proc/get_mobs_and_objs_in_belly()
var/list/see = list()
var/list/belly_mobs = list()
see["mobs"] = belly_mobs
var/list/belly_objs = list()
see["objs"] = belly_objs
for(var/mob/living/L in loc.contents)
belly_mobs |= L
for(var/obj/O in loc.contents)
belly_objs |= O
return see
// Belly copies and then returns the copy
// Needs to be updated for any var changes AND KEPT IN ORDER OF THE VARS ABOVE AS WELL!
/obj/belly/proc/copy(mob/new_owner)
var/obj/belly/dupe = new /obj/belly(new_owner)
//// Non-object variables
dupe.name = name
dupe.desc = desc
dupe.vore_sound = vore_sound
dupe.vore_verb = vore_verb
dupe.release_sound = release_sound
dupe.human_prey_swallow_time = human_prey_swallow_time
dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
dupe.emote_time = emote_time
dupe.digest_brute = digest_brute
dupe.digest_burn = digest_burn
dupe.immutable = immutable
dupe.escapable = escapable
dupe.escapetime = escapetime
dupe.digestchance = digestchance
dupe.absorbchance = absorbchance
dupe.escapechance = escapechance
dupe.can_taste = can_taste
dupe.bulge_size = bulge_size
dupe.transferlocation = transferlocation
dupe.transferchance = transferchance
dupe.autotransferchance = autotransferchance
dupe.autotransferwait = autotransferwait
dupe.swallow_time = swallow_time
dupe.vore_capacity = vore_capacity
dupe.is_wet = is_wet
//// Object-holding variables
//struggle_messages_outside - strings
dupe.struggle_messages_outside.Cut()
for(var/I in struggle_messages_outside)
dupe.struggle_messages_outside += I
//struggle_messages_inside - strings
dupe.struggle_messages_inside.Cut()
for(var/I in struggle_messages_inside)
dupe.struggle_messages_inside += I
//digest_messages_owner - strings
dupe.digest_messages_owner.Cut()
for(var/I in digest_messages_owner)
dupe.digest_messages_owner += I
//digest_messages_prey - strings
dupe.digest_messages_prey.Cut()
for(var/I in digest_messages_prey)
dupe.digest_messages_prey += I
//examine_messages - strings
dupe.examine_messages.Cut()
for(var/I in examine_messages)
dupe.examine_messages += I
//emote_lists - index: digest mode, key: list of strings
dupe.emote_lists.Cut()
for(var/K in emote_lists)
dupe.emote_lists[K] = list()
for(var/I in emote_lists[K])
dupe.emote_lists[K] += I
return dupe
@@ -1,294 +0,0 @@
// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
/obj/belly/proc/process_belly(var/times_fired,var/wait) //Passed by controller
if((times_fired < next_process) || !contents.len)
recent_sound = FALSE
return SSBELLIES_IGNORED
if(!owner)
qdel(src)
SSbellies.belly_list -= src
return SSBELLIES_PROCESSED
if(loc != owner)
if(isliving(owner)) //we don't have machine based bellies. (yet :honk:)
forceMove(owner)
else
SSbellies.belly_list -= src
qdel(src)
return SSBELLIES_PROCESSED
next_process = times_fired + (6 SECONDS/wait) //Set up our next process time.
/////////////////////////// Auto-Emotes ///////////////////////////
if(contents.len && next_emote <= times_fired)
next_emote = times_fired + round(emote_time/wait,1)
var/list/EL = emote_lists[digest_mode]
for(var/mob/living/M in contents)
if(M.digestable || !(digest_mode == DM_DIGEST)) // don't give digesty messages to indigestible people
to_chat(M,"<span class='notice'>[pick(EL)]</span>")
///////////////////// Prey Loop Refresh/hack //////////////////////
for(var/mob/living/M in contents)
if(isbelly(M.loc))
if(world.time > M.next_preyloop)
if(is_wet)
if(!M.client)
continue
M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
if(M.client.prefs.cit_toggles & DIGESTION_NOISES)
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
M.playsound_local(get_turf(src),preyloop, 80,0, channel = CHANNEL_PREYLOOP)
M.next_preyloop = (world.time + 52 SECONDS)
/////////////////////////// Exit Early ////////////////////////////
var/list/touchable_items = contents - items_preserved
if(!length(touchable_items))
return SSBELLIES_PROCESSED
//////////////////////// Absorbed Handling ////////////////////////
for(var/mob/living/M in contents)
if(M.absorbed)
M.Stun(5)
////////////////////////// Sound vars /////////////////////////////
var/sound/prey_digest = sound(get_sfx("digest_prey"))
var/sound/prey_death = sound(get_sfx("death_prey"))
var/sound/pred_digest = sound(get_sfx("digest_pred"))
var/sound/pred_death = sound(get_sfx("death_pred"))
var/turf/source = get_turf(owner)
///////////////////////////// DM_HOLD /////////////////////////////
if(digest_mode == DM_HOLD)
return SSBELLIES_PROCESSED
//////////////////////////// DM_DIGEST ////////////////////////////
else if(digest_mode == DM_DIGEST)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //obvious.
digest_mode = DM_NOISY
return
for (var/mob/living/M in contents)
if(prob(25))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//Pref protection!
if (!M.digestable || M.absorbed)
continue
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s form loses its additions.</span>")
owner.nutrition += 400 // so eating dead mobs gives you *something*.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
owner.nutrition += 1
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
owner.updateVRPanel()
///////////////////////////// DM_HEAL /////////////////////////////
if(digest_mode == DM_HEAL)
for (var/mob/living/M in contents)
if(prob(25))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
if(M.stat != DEAD)
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
M.adjustBruteLoss(-3)
M.adjustFireLoss(-3)
owner.nutrition -= 5
return
////////////////////////// DM_NOISY /////////////////////////////////
//for when you just want people to squelch around
if(digest_mode == DM_NOISY)
if(prob(35))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//////////////////////////// DM_ABSORB ////////////////////////////
else if(digest_mode == DM_ABSORB)
for (var/mob/living/M in contents)
if(prob(10))//Less often than gurgles. People might leave this on forever.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
if(M.absorbed)
continue
if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them.
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
else if(M.nutrition < 100) //When they're finally drained.
absorb_living(M)
//////////////////////////// DM_UNABSORB ////////////////////////////
else if(digest_mode == DM_UNABSORB)
for (var/mob/living/M in contents)
if(M.absorbed && owner.nutrition >= 100)
M.absorbed = 0
to_chat(M,"<span class='notice'>You suddenly feel solid again </span>")
to_chat(owner,"<span class='notice'>You feel like a part of you is missing.</span>")
owner.nutrition -= 100
//////////////////////////DM_DRAGON /////////////////////////////////////
//because dragons need snowflake guts
if(digest_mode == DM_DRAGON)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //imagine var editing this when you're a pacifist. smh
digest_mode = DM_NOISY
return
for (var/mob/living/M in contents)
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//No digestion protection for megafauna.
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
else if(H in contents)
H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
M.spill_organs(FALSE,TRUE,TRUE)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
M.adjustToxLoss(2) // something something plasma based acids
M.adjustCloneLoss(1) // eventually this'll kill you if you're healing everything else, you nerds.
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
owner.updateVRPanel()
@@ -1,119 +0,0 @@
//Please make sure to:
//return FALSE: You are not going away, stop asking me to digest.
//return non-negative integer: Amount of nutrition/charge gained (scaled to nutrition, other end can multiply for charge scale).
// Ye default implementation.
/obj/item/proc/digest_act(var/atom/movable/item_storage = null)
for(var/obj/item/O in contents)
if(istype(O,/obj/item/storage)) //Dump contents from dummy pockets.
for(var/obj/item/SO in O)
if(item_storage)
SO.forceMove(item_storage)
qdel(O)
else if(item_storage)
O.forceMove(item_storage)
qdel(src)
return w_class
/////////////
// Some indigestible stuff
/////////////
/obj/item/hand_tele/digest_act(...)
return FALSE
/obj/item/card/id/digest_act(...)
return FALSE
/obj/item/aicard/digest_act(...)
return FALSE
/obj/item/paicard/digest_act(...)
return FALSE
/obj/item/pinpointer/digest_act(...)
return FALSE
/obj/item/disk/nuclear/digest_act(...)
return FALSE
/obj/item/perfect_tele_beacon/digest_act(...)
return FALSE //Sorta important to not digest your own beacons.
/obj/item/pda/digest_act(...)
return FALSE
/obj/item/gun/digest_act(...)
return FALSE
/obj/item/clothing/shoes/magboots/digest_act(...)
return FALSE
/obj/item/clothing/head/helmet/space/digest_act(...)
return FALSE
/obj/item/clothing/suit/space/digest_act(...)
return FALSE
/obj/item/reagent_containers/hypospray/CMO/digest_act(...)
return FALSE
/obj/item/tank/jetpack/oxygen/captain/digest_act(...)
return FALSE
/obj/item/clothing/accessory/medal/gold/captain/digest_act(...)
return FALSE
/obj/item/clothing/suit/armor/digest_act(...)
return FALSE
/obj/item/documents/digest_act(...)
return FALSE
/obj/item/nuke_core/digest_act(...)
return FALSE
/obj/item/nuke_core_container/digest_act(...)
return FALSE
/obj/item/areaeditor/blueprints/digest_act(...)
return FALSE
/obj/item/documents/syndicate/digest_act(...)
return FALSE
/obj/item/bombcore/digest_act(...)
return FALSE
/obj/item/grenade/digest_act(...)
return FALSE
/obj/item/storage/digest_act(...)
return FALSE
/////////////
// Some special treatment
/////////////
/*
//PDAs need to lose their ID to not take it with them, so we can get a digested ID
/obj/item/pda/digest_act(var/atom/movable/item_storage = null)
if(id)
id = null
. = ..()
*/
/obj/item/reagent_containers/food/digest_act(var/atom/movable/item_storage = null)
if(isbelly(item_storage))
var/obj/belly/B = item_storage
if(ishuman(B.owner))
var/mob/living/carbon/human/H = B.owner
reagents.trans_to(H, (reagents.total_volume * 0.3), 1, 0)
else if(iscyborg(B.owner))
var/mob/living/silicon/robot/R = B.owner
R.cell.charge += 150
. = ..()
/*
/obj/item/holder/digest_act(var/atom/movable/item_storage = null)
for(var/mob/living/M in contents)
if(item_storage)
M.forceMove(item_storage)
held_mob = null
. = ..() */
/obj/item/organ/digest_act(var/atom/movable/item_storage = null)
if((. = ..()))
. += 70 //Organs give a little more
/obj/item/storage/digest_act(var/atom/movable/item_storage = null)
for(var/obj/item/I in contents)
I.screen_loc = null
. = ..()
/////////////
// Some more complicated stuff
/////////////
/obj/item/mmi/digital/posibrain/digest_act(var/atom/movable/item_storage = null)
//Replace this with a VORE setting so all types of posibrains can/can't be digested on a whim
return FALSE
@@ -1,411 +0,0 @@
///////////////////// Mob Living /////////////////////
/mob/living
var/digestable = FALSE // Can the mob be digested inside a belly?
var/showvoreprefs = TRUE // Determines if the mechanical vore preferences button will be displayed on the mob or not.
var/obj/belly/vore_selected // Default to no vore capability.
var/list/vore_organs = list() // List of vore containers inside a mob
var/devourable = FALSE // Can the mob be vored at all?
var/feeding = FALSE // Are we going to feed someone else?
var/vore_taste = null // What the character tastes like
var/no_vore = FALSE // If the character/mob can vore.
var/openpanel = 0 // Is the vore panel open?
var/absorbed = FALSE //are we absorbed?
var/next_preyloop
var/vore_init = FALSE //Has this mob's vore been initialized yet?
var/vorepref_init = FALSE //Has this mob's voreprefs been initialized?
//
// Hook for generic creation of stuff on new creatures
//
/hook/living_new/proc/vore_setup(mob/living/M)
M.verbs += /mob/living/proc/preyloop_refresh
M.verbs += /mob/living/proc/lick
M.verbs += /mob/living/proc/escapeOOC
if(M.no_vore) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
return 1
M.verbs += /mob/living/proc/insidePanel
//Tries to load prefs if a client is present otherwise gives freebie stomach
spawn(10 SECONDS) // long delay because the server delays in its startup. just on the safe side.
if(M)
M.init_vore()
//Return 1 to hook-caller
return 1
/mob/living/proc/init_vore()
vore_init = TRUE
//Something else made organs, meanwhile.
if(LAZYLEN(vore_organs))
return TRUE
//We'll load our client's organs if we have one
if(client && client.prefs_vr)
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
if(LAZYLEN(vore_organs))
vore_selected = vore_organs[1]
return TRUE
//Or, we can create a basic one for them
if(!LAZYLEN(vore_organs))
LAZYINITLIST(vore_organs)
var/obj/belly/B = new /obj/belly(src)
vore_selected = B
B.immutable = 1
B.name = "Stomach"
B.desc = "It appears to be rather warm and wet. Makes sense, considering it's inside [name]."
B.can_taste = 1
return TRUE
// Handle being clicked, perhaps with something to devour
//
// Refactored to use centralized vore code system - Leshana
// Critical adjustments due to TG grab changes - Poojawa
/mob/living/proc/vore_attack(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
if(!user || !prey || !pred)
return
if(!isliving(pred)) //no badmin, you can't feed people to ghosts or objects.
return
if(pred == prey) //you click your target
if(!pred.feeding)
to_chat(user, "<span class='notice'>They aren't able to be fed.</span>")
to_chat(pred, "<span class='notice'>[user] tried to feed you themselves, but you aren't voracious enough to be fed.</span>")
return
if(!is_vore_predator(pred))
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
return
feed_self_to_grabbed(user, pred)
if(pred == user) //you click yourself
if(!is_vore_predator(src))
to_chat(user, "<span class='notice'>You aren't voracious enough.</span>")
return
feed_grabbed_to_self(user, prey)
else // click someone other than you/prey
if(!pred.feeding)
to_chat(user, "<span class='notice'>They aren't voracious enough to be fed.</span>")
to_chat(pred, "<span class='notice'>[user] tried to feed you [prey], but you aren't voracious enough to be fed.</span>")
return
if(!prey.feeding)
to_chat(user, "<span class='notice'>They aren't able to be fed to someone.</span>")
to_chat(prey, "<span class='notice'>[user] tried to feed you to [pred], but you aren't able to be fed to them.</span>")
return
if(!is_vore_predator(pred))
to_chat(user, "<span class='notice'>They aren't voracious enough.</span>")
return
feed_grabbed_to_other(user, prey, pred)
//
// Eating procs depending on who clicked what
//
/mob/living/proc/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey)
var/belly = user.vore_selected
return perform_the_nom(user, prey, user, belly)
/mob/living/proc/feed_self_to_grabbed(var/mob/living/user, var/mob/living/pred)
var/belly = input("Choose Belly") in pred.vore_organs
return perform_the_nom(user, user, pred, belly)
/mob/living/proc/feed_grabbed_to_other(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
var/belly = input("Choose Belly") in pred.vore_organs
return perform_the_nom(user, prey, pred, belly)
//
// Master vore proc that actually does vore procedures
//
/mob/living/proc/perform_the_nom(var/mob/living/user, var/mob/living/prey, var/mob/living/pred, var/obj/belly/belly, var/delay)
//Sanity
if(!user || !prey || !pred || !istype(belly) || !(belly in pred.vore_organs))
testing("[user] attempted to feed [prey] to [pred], via [lowertext(belly.name)] but it went wrong.")
return FALSE
if (!prey.devourable)
to_chat(user, "This can't be eaten!")
return FALSE
// The belly selected at the time of noms
var/attempt_msg = "ERROR: Vore message couldn't be created. Notify a dev. (at)"
var/success_msg = "ERROR: Vore message couldn't be created. Notify a dev. (sc)"
// Prepare messages
if(user == pred) //Feeding someone to yourself
attempt_msg = text("<span class='warning'>[] is attemping to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
success_msg = text("<span class='warning'>[] manages to [] [] into their []!</span>",pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
else //Feeding someone to another person
attempt_msg = text("<span class='warning'>[] is attempting to make [] [] [] into their []!</span>",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
success_msg = text("<span class='warning'>[] manages to make [] [] [] into their []!</span>",user,pred,lowertext(belly.vore_verb),prey,lowertext(belly.name))
if(!prey.Adjacent(user)) // let's not even bother attempting it yet if they aren't next to us.
return FALSE
// Announce that we start the attempt!
user.visible_message(attempt_msg)
// Now give the prey time to escape... return if they did
var/swallow_time = delay || ishuman(prey) ? belly.human_prey_swallow_time : belly.nonhuman_prey_swallow_time
if(!do_mob(src, user, swallow_time))
return FALSE // Prey escaped (or user disabled) before timer expired.
if(!prey.Adjacent(user)) //double check'd just in case they moved during the timer and the do_mob didn't fail for whatever reason
return FALSE
// If we got this far, nom successful! Announce it!
user.visible_message(success_msg)
// incredibly contentious eating noises time
var/turf/source = get_turf(user)
var/sound/eating = GLOB.vore_sounds[belly.vore_sound]
for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
SEND_SOUND(M, eating)
// Actually shove prey into the belly.
belly.nom_mob(prey, user)
stop_pulling()
// Flavor handling
if(belly.can_taste && prey.get_taste_message(FALSE))
to_chat(belly.owner, "<span class='notice'>[prey] tastes of [prey.get_taste_message(FALSE)].</span>")
// Inform Admins
var/prey_braindead
var/prey_stat
if(prey.ckey)
prey_stat = prey.stat//only return this if they're not an unmonkey or whatever
if(!prey.client)//if they disconnected, tell us
prey_braindead = 1
if (pred == user)
message_admins("[ADMIN_LOOKUPFLW(pred)] ate [ADMIN_LOOKUPFLW(prey)][!prey_braindead ? "" : " (BRAINDEAD)"][prey_stat ? " (DEAD/UNCONSCIOUS)" : ""].")
pred.log_message("[key_name(pred)] ate [key_name(prey)].", LOG_ATTACK)
prey.log_message("[key_name(prey)] was eaten by [key_name(pred)].", LOG_ATTACK)
else
message_admins("[ADMIN_LOOKUPFLW(user)] forced [ADMIN_LOOKUPFLW(pred)] to eat [ADMIN_LOOKUPFLW(prey)].")
user.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
pred.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
prey.log_message("[key_name(user)] forced [key_name(pred)] to eat [key_name(prey)].", LOG_ATTACK)
return TRUE
//
//End vore code.
//
// Our custom resist catches for /mob/living
//
/mob/living/proc/vore_process_resist()
//Are we resisting from inside a belly?
if(isbelly(loc))
var/obj/belly/B = loc
B.relay_resist(src)
return TRUE //resist() on living does this TRUE thing.
//Other overridden resists go here
return 0
// internal slimy button in case the loop stops playing but the player wants to hear it
/mob/living/proc/preyloop_refresh()
set name = "Internal loop refresh"
set category = "Vore"
if(isbelly(loc))
src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
SEND_SOUND(src, preyloop)
else
to_chat(src, "<span class='alert'>You aren't inside anything, you clod.</span>")
// OOC Escape code for pref-breaking or AFK preds
//
/mob/living/proc/escapeOOC()
set name = "OOC Escape"
set category = "Vore"
//You're in a belly!
if(isbelly(loc))
var/obj/belly/B = loc
var/confirm = alert(src, "You're in a mob. If you're otherwise unable to escape from a pred AFK for a long time, use this.", "Confirmation", "Okay", "Cancel")
if(!confirm == "Okay" || loc != B)
return
//Actual escaping
B.release_specific_contents(src,TRUE) //we might as well take advantage of that specific belly's handling. Else we stay blinded forever.
src.stop_sound_channel(CHANNEL_PREYLOOP)
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "fedprey", /datum/mood_event/fedprey)
for(var/mob/living/simple_animal/SA in range(10))
SA.prey_excludes[src] = world.time
if(isanimal(B.owner))
var/mob/living/simple_animal/SA = B.owner
SA.update_icons()
//You're in a dogborg!
else if(istype(loc, /obj/item/dogborg/sleeper))
var/obj/item/dogborg/sleeper/belly = loc //The belly!
var/confirm = alert(src, "You're in a dogborg sleeper. This is for escaping from preference-breaking or if your predator disconnects/AFKs. You can also resist out naturally too.", "Confirmation", "Okay", "Cancel")
if(!confirm == "Okay" || loc != belly)
return
//Actual escaping
belly.go_out(src) //Just force-ejects from the borg as if they'd clicked the eject button.
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 0
if(!copy_to_prefs_vr())
return 0
if(!client.prefs_vr.save_vore())
return 0
return 1
/mob/living/proc/apply_vore_prefs()
if(!client || !client.prefs_vr)
return 0
if(!client.prefs_vr.load_vore())
return 0
if(!copy_from_prefs_vr())
return 0
return 1
/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>")
return 0
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
var/list/serialized = list()
for(var/belly in src.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
return 1
//
// 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>")
return 0
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
release_vore_contents(silent = TRUE)
vore_organs.Cut()
for(var/entry in P.belly_prefs)
list_to_object(entry,src)
return 1
//
// Release everything in every vore organ
//
/mob/living/proc/release_vore_contents(var/include_absorbed = TRUE, var/silent = FALSE)
for(var/belly in vore_organs)
var/obj/belly/B = belly
B.release_all_contents(include_absorbed, silent)
//
// Returns examine messages for bellies
//
/mob/living/proc/examine_bellies()
if(!show_pudge()) //Some clothing or equipment can hide this.
return ""
var/message = ""
for (var/belly in vore_organs)
var/obj/belly/B = belly
message += B.get_examine_msg()
return message
//
// Whether or not people can see our belly messages
//
/mob/living/proc/show_pudge()
return TRUE //Can override if you want.
/mob/living/carbon/human/show_pudge()
//A uniform could hide it.
if(istype(w_uniform,/obj/item/clothing))
var/obj/item/clothing/under = w_uniform
if(under.hides_bulges)
return FALSE
//We return as soon as we find one, no need for 'else' really.
if(istype(wear_suit,/obj/item/clothing))
var/obj/item/clothing/suit = wear_suit
if(suit.hides_bulges)
return FALSE
return ..()
//
// Clearly super important. Obviously.
//
/mob/living/proc/lick(var/mob/living/tasted in oview(1))
set name = "Lick Someone"
set category = "Vore"
set desc = "Lick someone nearby!"
if(!istype(tasted))
return
if(src == stat)
return
src.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>")
/mob/living/proc/get_taste_message(allow_generic = TRUE, datum/species/mrace)
if(!vore_taste && !allow_generic)
return FALSE
var/taste_message = ""
if(vore_taste && (vore_taste != ""))
taste_message += "[vore_taste]"
else
if(ishuman(src))
taste_message += "they haven't bothered to set their flavor text"
else
taste_message += "a plain old normal [src]"
/* if(ishuman(src))
var/mob/living/carbon/human/H = src
if(H.touching.reagent_list.len) //Just the first one otherwise I'll go insane.
var/datum/reagent/R = H.touching.reagent_list[1]
taste_message += " You also get the flavor of [R.taste_description] from something on them"*/
return taste_message
@@ -1,169 +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/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/[copytext(ckey,1,2)]/[ckey]/vore/[filename][slot].[ext]"
/datum/vore_preferences/proc/load_vore()
if(!client || !client_ckey)
return 0 //No client, how can we save?
if(!client.prefs || !client.prefs.default_slot)
return 0 //Need to know what character to load!
slot = client.prefs.default_slot
load_path(client_ckey,slot)
if(!path) return 0 //Path couldn't be set?
if(!fexists(path)) //Never saved before
save_vore() //Make the file first
return 1
var/list/json_from_file = json_decode(file2text(path))
if(!json_from_file)
return 0 //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"]
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(belly_prefs))
belly_prefs = list()
return 1
/datum/vore_preferences/proc/save_vore()
if(!path)
return 0
var/version = VORE_VERSION //For "good times" use in the future
var/list/settings_list = list(
"version" = version,
"digestable" = digestable,
"devourable" = devourable,
"feeding" = feeding,
"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 0
//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 0
return 1
/* 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
@@ -1,62 +0,0 @@
// -------------- Sickshot -------------
/obj/item/gun/energy/sickshot
name = "\improper MPA6 \'Sickshot\'"
desc = "A device that can trigger convusions in specific areas to eject foreign material from a host. Must be used very close to a target. Not for Combat usage."
icon_state = "dragnet"
item_state = "dragnet"
ammo_x_offset = 1
ammo_type = list(/obj/item/ammo_casing/energy/sickshot)
/obj/item/ammo_casing/energy/sickshot
projectile_type = /obj/item/projectile/sickshot
e_cost = 100
//Projectile
/obj/item/projectile/sickshot
name = "sickshot pulse"
icon_state = "e_netting"
damage = 0
damage_type = STAMINA
range = 2
/obj/item/projectile/sickshot/on_hit(var/atom/movable/target, var/blocked = 0)
if(iscarbon(target))
var/mob/living/carbon/H = target
if(prob(5))
for(var/X in H.vore_organs)
H.release_vore_contents()
H.visible_message("<span class='danger'>[H] contracts strangely, spewing out contents on the floor!</span>", \
"<span class='userdanger'>You spew out everything inside you on the floor!</span>")
return
////////////////////////// Anti-Noms Drugs //////////////////////////
/*
/datum/reagent/medicine/ickypak
name = "Ickypak"
id = "ickypak"
description = "A foul-smelling green liquid, for inducing muscle contractions to expel accidentally ingested things."
reagent_state = LIQUID
color = "#0E900E"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
/datum/reagent/medicine/ickypak/on_mob_life(var/mob/living/M, method=INGEST)
if(prob(10))
M.visible_message("<span class='danger'>[M] retches!</span>", \
"<span class='userdanger'>You don't feel good...</span>")
for(var/I in M.vore_organs)
var/datum/belly/B = M.vore_organs[I]
for(var/atom/movable/A in B.internal_contents)
if(prob(55))
playsound(M, 'sound/effects/splat.ogg', 50, 1)
B.release_specific_contents(A)
M.visible_message("<span class='danger'>[M] contracts strangely, spewing out something!</span>", \
"<span class='userdanger'>You spew out something from inside you!</span>")
return ..()
/datum/chemical_reaction/ickypak
name = "Ickypak"
id = "ickypak"
results = list("ickypak" = 2)
required_reagents = list("chlorine" = 2 , "oil" = 1) */
@@ -1,734 +0,0 @@
//
// Vore management panel for players
//
#define BELLIES_MAX 20
#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"
set category = "Vore"
var/datum/vore_look/picker_holder = new()
picker_holder.loop = picker_holder
picker_holder.selected = vore_selected
var/dat = picker_holder.gen_vui(src)
picker_holder.popup = new(src, "insidePanel","Vore Panel", 450, 700, picker_holder)
picker_holder.popup.set_content(dat)
picker_holder.popup.open()
src.openpanel = 1
/mob/living/proc/updateVRPanel() //Panel popup update call from belly events.
if(src.openpanel == 1)
var/datum/vore_look/picker_holder = new()
picker_holder.loop = picker_holder
picker_holder.selected = vore_selected
var/dat = picker_holder.gen_vui(src)
picker_holder.popup = new(src, "insidePanel","Vore Panel", 450, 700, picker_holder)
picker_holder.popup.set_content(dat)
picker_holder.popup.open()
//
// Callback Handler for the Inside form
//
/datum/vore_look
var/obj/belly/selected
var/show_interacts = 0
var/datum/browser/popup
var/loop = null; // Magic self-reference to stop the handler from being GC'd before user takes action.
/datum/vore_look/Destroy()
loop = null
selected = null
return QDEL_HINT_HARDDEL
/datum/vore_look/Topic(href,href_list[])
if (vp_interact(href, href_list))
popup.set_content(gen_vui(usr))
usr << output(popup.get_content(), "insidePanel.browser")
/datum/vore_look/proc/gen_vui(var/mob/living/user)
var/dat
dat += "Remember to toggle the vore mode, it's to the left of your combat toggle. Open mouth means you're voracious!<br>"
dat += "Remember that the prey is blind, use audible mode subtle messages to communicate to them with posts!<br>"
dat += "<HR>"
var/atom/userloc = user.loc
if (isbelly(userloc))
var/obj/belly/inside_belly = userloc
var/mob/living/eater = inside_belly.owner
//Don't display this part if we couldn't find the belly since could be held in hand.
if(inside_belly)
dat += "<font color = 'green'>You are currently [user.absorbed ? "absorbed into " : "inside "]</font> <font color = 'yellow'>[eater]'s</font> <font color = 'red'>[inside_belly]</font>!<br><br>"
if(inside_belly.desc)
dat += "[inside_belly.desc]<br><br>"
if (inside_belly.contents.len > 1)
dat += "You can see the following around you:<br>"
for (var/atom/movable/O in inside_belly)
if(istype(O,/mob/living))
var/mob/living/M = O
//That's just you
if(M == user)
continue
//That's an absorbed person you're checking
if(M.absorbed)
if(user.absorbed)
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'><span style='color:purple;'>[O]</span></a>"
continue
else
continue
//Anything else
dat += "<a href='?src=\ref[src];outsidepick=\ref[O];outsidebelly=\ref[inside_belly]'>[O]&#8203;</a>"
//Zero-width space, for wrapping
dat += "&#8203;"
else
dat += "You aren't inside anyone."
dat += "<HR>"
dat += "<ol style='list-style: none; padding: 0; overflow: auto;'>"
for(var/belly in user.vore_organs)
var/obj/belly/B = belly
if(B == selected)
dat += "<li style='float: left'><a href='?src=\ref[src];bellypick=\ref[B]'><b>[B.name]</b>"
else
dat += "<li style='float: left'><a href='?src=\ref[src];bellypick=\ref[B]'>[B.name]"
var/spanstyle
switch(B.digest_mode)
if(DM_HOLD)
spanstyle = ""
if(DM_DIGEST)
spanstyle = "color:red;"
if(DM_HEAL)
spanstyle = "color:darkgreen;"
if(DM_NOISY)
spanstyle = "color:purple;"
if(DM_ABSORB)
spanstyle = "color:purple;"
if(DM_DRAGON)
spanstyle = "color:blue;"
dat += "<span style='[spanstyle]'> ([B.contents.len])</span></a></li>"
if(user.vore_organs.len < BELLIES_MAX)
dat += "<li style='float: left'><a href='?src=\ref[src];newbelly=1'>New+</a></li>"
dat += "</ol>"
dat += "<HR>"
// Selected Belly (contents, configuration)
if(!selected)
dat += "No belly selected. Click one to select it."
else
if(selected.contents.len)
dat += "<b>Contents:</b> "
for(var/O in selected)
//Mobs can be absorbed, so treat them separately from everything else
if(istype(O,/mob/living))
var/mob/living/M = O
//Absorbed gets special color OOoOOOOoooo
if(M.absorbed)
dat += "<a href='?src=\ref[src];insidepick=\ref[O]'><span style='color:purple;'>[O]</span></a>"
continue
//Anything else
dat += "<a href='?src=\ref[src];insidepick=\ref[O]'>[O]</a>"
//Zero-width space, for wrapping
dat += "&#8203;"
//If there's more than one thing, add an [All] button
if(selected.contents.len > 1)
dat += "<a href='?src=\ref[src];insidepick=1;pickall=1'>\[All\]</a>"
dat += "<HR>"
//Belly Name Button
dat += "<a href='?src=\ref[src];b_name=\ref[selected]'>Name:</a>"
dat += " '[selected.name]'"
//Belly Type button
dat += "<br><a href='?src=\ref[src];b_wetness=\ref[selected]'>Is Fleshy:</a>"
dat += "[selected.is_wet ? "Yes" : "No"]"
//Digest Mode Button
dat += "<br><a href='?src=\ref[src];b_mode=\ref[selected]'>Belly Mode:</a>"
dat += " [selected.digest_mode]"
//Belly verb
dat += "<br><a href='?src=\ref[src];b_verb=\ref[selected]'>Vore Verb:</a>"
dat += " '[selected.vore_verb]'"
//Inside flavortext
dat += "<br><a href='?src=\ref[src];b_desc=\ref[selected]'>Flavor Text:</a>"
dat += " '[selected.desc]'"
//Belly sound
dat += "<br><a href='?src=\ref[src];b_sound=\ref[selected]'>Vore Sound: [selected.vore_sound]</a>"
dat += "<a href='?src=\ref[src];b_soundtest=\ref[selected]'>Test</a>"
//Release sound
dat += "<br><a href='?src=\ref[src];b_release=\ref[selected]'>Release Sound: [selected.release_sound]</a>"
dat += "<a href='?src=\ref[src];b_releasesoundtest=\ref[selected]'>Test</a>"
//Belly messages
dat += "<br><a href='?src=\ref[src];b_msgs=\ref[selected]'>Belly Messages</a>"
//Can belly taste?
dat += "<br><a href='?src=\ref[src];b_tastes=\ref[selected]'>Can Taste:</a>"
dat += " [selected.can_taste ? "Yes" : "No"]"
//Minimum size prey must be to show up.
dat += "<br><a href='?src=\ref[src];b_bulge_size=\ref[selected]'>Required examine size:</a>"
dat += " [selected.bulge_size*100]%"
//Belly escapability
dat += "<br><a href='?src=\ref[src];b_escapable=\ref[selected]'>Belly Interactions ([selected.escapable ? "On" : "Off"])</a>"
if(selected.escapable)
dat += "<a href='?src=\ref[src];show_int=\ref[selected]'>[show_interacts ? "Hide" : "Show"]</a>"
if(show_interacts && selected.escapable)
dat += "<HR>"
dat += "Interaction Settings <a href='?src=\ref[src];int_help=\ref[selected]'>?</a>"
dat += "<br><a href='?src=\ref[src];b_escapechance=\ref[selected]'>Set Belly Escape Chance</a>"
dat += " [selected.escapechance]%"
dat += "<br><a href='?src=\ref[src];b_escapetime=\ref[selected]'>Set Belly Escape Time</a>"
dat += " [selected.escapetime/10]s"
//Special <br> here to add a gap
dat += "<br style='line-height:5px;'>"
dat += "<br><a href='?src=\ref[src];b_transferchance=\ref[selected]'>Set Belly Transfer Chance</a>"
dat += " [selected.transferchance]%"
dat += "<br><a href='?src=\ref[src];b_transferlocation=\ref[selected]'>Set Belly Transfer Location</a>"
dat += " [selected.transferlocation ? selected.transferlocation : "Disabled"]"
//Special <br> here to add a gap
dat += "<br style='line-height:5px;'>"
dat += "<br><a href='?src=\ref[src];b_absorbchance=\ref[selected]'>Set Belly Absorb Chance</a>"
dat += " [selected.absorbchance]%"
dat += "<br><a href='?src=\ref[src];b_digestchance=\ref[selected]'>Set Belly Digest Chance</a>"
dat += " [selected.digestchance]%"
dat += "<HR>"
//Delete button
dat += "<br><a style='background:#990000;' href='?src=\ref[src];b_del=\ref[selected]'>Delete Belly</a>"
dat += "<a href='?src=\ref[src];setflavor=1'>Set Flavor</a>"
dat += "<HR>"
//Under the last HR, save and stuff.
dat += "<a href='?src=\ref[src];saveprefs=1'>Save Prefs</a>"
dat += "<a href='?src=\ref[src];refresh=1'>Refresh</a>"
dat += "<a href='?src=\ref[src];applyprefs=1'>Reload Slot Prefs</a>"
dat += "<HR>"
switch(user.digestable)
if(TRUE)
dat += "<a href='?src=\ref[src];toggledg=1'>Toggle Digestable <font color='darkgreen'>(Currently: ON)</font></a>"
if(FALSE)
dat += "<a href='?src=\ref[src];toggledg=1'>Toggle Digestable <font color='red'>(Currently: OFF)</font></a>"
switch(user.devourable)
if(TRUE)
dat += "<br><a href='?src=\ref[src];toggledvor=1'>Toggle Devourable <font color='darkgreen'>(Currently: ON)</font></a>"
if(FALSE)
dat += "<br><a href='?src=\ref[src];toggledvor=1'>Toggle Devourable <font color='red'>(Currently: OFF)</font></a>"
switch(user.feeding)
if(TRUE)
dat += "<br><a href='?src=\ref[src];toggledfeed=1'>Toggle Feeding <font color='darkgreen'>(Currently: ON)</font></a>"
if(FALSE)
dat += "<br><a href='?src=\ref[src];toggledfeed=1'>Toggle Feeding <font color='red'>(Currently: OFF)</font></a>"
//Returns the dat html to the vore_look
return dat
/datum/vore_look/proc/vp_interact(href, href_list)
var/mob/living/user = usr
for(var/H in href_list)
if(href_list["close"])
qdel(src) // Cleanup
user.openpanel = 0
return
if(href_list["show_int"])
show_interacts = !show_interacts
return 1 //Force update
if(href_list["int_help"])
alert("These control how your belly responds to someone using 'resist' while inside you. The percent chance to trigger each is listed below, \
and you can change them to whatever you see fit. Setting them to 0% will disable the possibility of that interaction. \
These only function as long as interactions are turned on in general. Keep in mind, the 'belly mode' interactions (digest/absorb) \
will affect all prey in that belly, if one resists and triggers digestion/absorption. If multiple trigger at the same time, \
only the first in the order of 'Escape > Transfer > Absorb > Digest' will occur.","Interactions Help")
return 0 //Force update
if(href_list["outsidepick"])
var/atom/movable/tgt = locate(href_list["outsidepick"])
var/obj/belly/OB = locate(href_list["outsidebelly"])
if(!(tgt in OB)) //Aren't here anymore, need to update menu.
return 1
var/intent = "Examine"
if(istype(tgt,/mob/living))
var/mob/living/M = tgt
intent = alert("What do you want to do to them?","Query","Examine","Help Out","Devour")
switch(intent)
if("Examine") //Examine a mob inside another mob
M.examine(user)
if("Help Out") //Help the inside-mob out
if(user.stat || user.absorbed || M.absorbed)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 1
to_chat(user,"<font color='green'>You begin to push [M] to freedom!</font>")
to_chat(M,"[usr] begins to push you to freedom!")
to_chat(M.loc,"<span class='warning'>Someone is trying to escape from inside you!</span>")
sleep(50)
if(prob(33))
OB.release_specific_contents(M)
to_chat(usr,"<font color='green'>You manage to help [M] to safety!</font>")
to_chat(M,"<font color='green'>[user] pushes you free!</font>")
to_chat(OB.owner,"<span class='alert'>[M] forces free of the confines of your body!</span>")
else
to_chat(user,"<span class='alert'>[M] slips back down inside despite your efforts.</span>")
to_chat(M,"<span class='alert'> Even with [user]'s help, you slip back inside again.</span>")
to_chat(OB.owner,"<font color='green'>Your body efficiently shoves [M] back where they belong.</font>")
if("Devour") //Eat the inside mob
if(user.absorbed || user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 1
if(!user.vore_selected)
to_chat(user,"<span class='warning'>Pick a belly on yourself first!</span>")
return 1
var/obj/belly/TB = user.vore_selected
to_chat(user,"<span class='warning'>You begin to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
to_chat(M,"<span class='warning'>[user] begins to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
to_chat(OB.owner,"<span class='warning'>Someone inside you is eating someone else!</span>")
sleep(TB.nonhuman_prey_swallow_time) //Can't do after, in a stomach, weird things abound.
if((user in OB) && (M in OB)) //Make sure they're still here.
to_chat(user,"<span class='warning'>You manage to [lowertext(TB.vore_verb)] [M] into your [lowertext(TB.name)]!</span>")
to_chat(M,"<span class='warning'>[user] manages to [lowertext(TB.vore_verb)] you into their [lowertext(TB.name)]!</span>")
to_chat(OB.owner,"<span class='warning'>Someone inside you has eaten someone else!</span>")
TB.nom_mob(M)
else if(istype(tgt,/obj/item))
var/obj/item/T = tgt
if(!(tgt in OB))
//Doesn't exist anymore, update.
return 1
intent = alert("What do you want to do to that?","Query","Examine","Use Hand")
switch(intent)
if("Examine")
T.examine(user)
if("Use Hand")
if(user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 1
user.ClickOn(T)
sleep(5) //Seems to exit too fast for the panel to update
if(href_list["insidepick"])
var/intent
//Handle the [All] choice. Ugh inelegant. Someone make this pretty.
if(href_list["pickall"])
intent = alert("Eject all, Move all?","Query","Eject all","Cancel","Move all")
switch(intent)
if("Cancel")
return 0
if("Eject all")
if(user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 0
selected.release_all_contents()
if("Move all")
if(user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 0
var/obj/belly/choice = input("Move all where?","Select Belly") as null|anything in user.vore_organs
if(!choice)
return 0
for(var/atom/movable/tgt in selected)
to_chat(tgt,"<span class='warning'>You're squished from [user]'s [lowertext(selected)] to their [lowertext(choice.name)]!</span>")
selected.transfer_contents(tgt, choice, 1)
var/atom/movable/tgt = locate(href_list["insidepick"])
if(!(tgt in selected)) //Old menu, needs updating because they aren't really there.
return 1 //Forces update
intent = "Examine"
intent = alert("Examine, Eject, Move? Examine if you want to leave this box.","Query","Examine","Eject","Move")
switch(intent)
if("Examine")
tgt.examine(user)
if("Eject")
if(user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 0
selected.release_specific_contents(tgt)
if("Move")
if(user.stat)
to_chat(user,"<span class='warning'>You can't do that in your state!</span>")
return 0
var/obj/belly/choice = input("Move [tgt] where?","Select Belly") as null|anything in user.vore_organs
if(!choice || !(tgt in selected))
return 0
to_chat(tgt,"<span class='warning'>You're squished from [user]'s [lowertext(selected.name)] to their [lowertext(choice.name)]!</span>")
selected.transfer_contents(tgt, choice)
if(href_list["newbelly"])
if(user.vore_organs.len >= BELLIES_MAX)
return 0
var/new_name = html_encode(input(usr,"New belly's name:","New Belly") as text|null)
var/failure_msg
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
// else if(whatever) //Next test here.
else
for(var/belly in user.vore_organs)
var/obj/belly/B = belly
if(lowertext(new_name) == lowertext(B.name))
failure_msg = "No duplicate belly names, please."
break
if(failure_msg) //Something went wrong.
alert(user,failure_msg,"Error!")
return 0
var/obj/belly/NB = new(user)
NB.name = new_name
selected = NB
if(href_list["bellypick"])
selected = locate(href_list["bellypick"])
user.vore_selected = selected
////
//Please keep these the same order they are on the panel UI for ease of coding
////
if(href_list["b_name"])
var/new_name = html_encode(input(usr,"Belly's new name:","New Name") as text|null)
var/failure_msg
if(length(new_name) > BELLIES_NAME_MAX || length(new_name) < BELLIES_NAME_MIN)
failure_msg = "Entered belly name length invalid (must be longer than [BELLIES_NAME_MIN], no more than than [BELLIES_NAME_MAX])."
// else if(whatever) //Next test here.
else
for(var/belly in user.vore_organs)
var/obj/belly/B = belly
if(lowertext(new_name) == lowertext(B.name))
failure_msg = "No duplicate belly names, please."
break
if(failure_msg) //Something went wrong.
alert(user,failure_msg,"Error!")
return 0
selected.name = new_name
if(href_list["b_wetness"])
selected.is_wet = !selected.is_wet
if(href_list["b_mode"])
var/list/menu_list = selected.digest_modes
var/new_mode = input("Choose Mode (currently [selected.digest_mode])") as null|anything in menu_list
if(!new_mode)
return 0
selected.digest_mode = new_mode
if(href_list["b_desc"])
var/new_desc = html_encode(input(usr,"Belly Description ([BELLIES_DESC_MAX] char limit):","New Description",selected.desc) as message|null)
if(new_desc)
new_desc = readd_quotes(new_desc)
if(length(new_desc) > BELLIES_DESC_MAX)
alert("Entered belly desc too long. [BELLIES_DESC_MAX] character limit.","Error")
return FALSE
selected.desc = new_desc
else //Returned null
return FALSE
if(href_list["b_msgs"])
var/list/messages = list(
"Digest Message (to prey)",
"Digest Message (to you)",
"Struggle Message (outside)",
"Struggle Message (inside)",
"Examine Message (when full)",
"Reset All To Default"
)
alert(user,"Setting abusive or deceptive messages will result in a ban. Consider this your warning. Max 150 characters per message, max 10 messages per topic.","Really, don't.")
var/choice = input(user,"Select a type to modify. Messages from each topic are pulled at random when needed.","Pick Type") as null|anything in messages
var/help = " Press enter twice to separate messages. '%pred' will be replaced with your name. '%prey' will be replaced with the prey's name. '%belly' will be replaced with your belly's name."
switch(choice)
if("Digest Message (to prey)")
var/new_message = input(user,"These are sent to prey when they expire. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Digest Message (to prey)",selected.get_messages("dmp")) as message
if(new_message)
selected.set_messages(new_message,"dmp")
if("Digest Message (to you)")
var/new_message = input(user,"These are sent to you when prey expires in you. Write them in 2nd person ('you feel X'). Avoid using %pred in this type."+help,"Digest Message (to you)",selected.get_messages("dmo")) as message
if(new_message)
selected.set_messages(new_message,"dmo")
if("Struggle Message (outside)")
var/new_message = input(user,"These are sent to those nearby when prey struggles. Write them in 3rd person ('X's Y bulges')."+help,"Struggle Message (outside)",selected.get_messages("smo")) as message
if(new_message)
selected.set_messages(new_message,"smo")
if("Struggle Message (inside)")
var/new_message = input(user,"These are sent to prey when they struggle. Write them in 2nd person ('you feel X'). Avoid using %prey in this type."+help,"Struggle Message (inside)",selected.get_messages("smi")) as message
if(new_message)
selected.set_messages(new_message,"smi")
if("Examine Message (when full)")
var/new_message = input(user,"These are sent to people who examine you when this belly has contents. Write them in 3rd person ('Their %belly is bulging')."+help,"Examine Message (when full)",selected.get_messages("em")) as message
if(new_message)
selected.set_messages(new_message,"em")
if("Reset All To Default")
var/confirm = alert(user,"This will delete any custom messages. Are you sure?","Confirmation","DELETE","Cancel")
if(confirm == "DELETE")
selected.digest_messages_prey = initial(selected.digest_messages_prey)
selected.digest_messages_owner = initial(selected.digest_messages_owner)
selected.struggle_messages_outside = initial(selected.struggle_messages_outside)
selected.struggle_messages_inside = initial(selected.struggle_messages_inside)
if(href_list["b_verb"])
var/new_verb = html_encode(input(usr,"New verb when eating (infinitive tense, e.g. nom or swallow):","New Verb") as text|null)
if(length(new_verb) > BELLIES_NAME_MAX || length(new_verb) < BELLIES_NAME_MIN)
alert("Entered verb length invalid (must be longer than [BELLIES_NAME_MIN], no longer than [BELLIES_NAME_MAX]).","Error")
return 0
selected.vore_verb = new_verb
if(href_list["b_release"])
var/choice = input(user,"Currently set to [selected.release_sound]","Select Sound") as null|anything in GLOB.release_sounds
if(!choice)
return
selected.release_sound = choice
if(href_list["b_releasesoundtest"])
var/sound/releasetest = GLOB.release_sounds[selected.release_sound]
if(releasetest)
SEND_SOUND(user, releasetest)
if(href_list["b_sound"])
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.vore_sounds
if(!choice)
return
selected.vore_sound = choice
if(href_list["b_soundtest"])
var/sound/voretest = GLOB.vore_sounds[selected.vore_sound]
if(voretest)
SEND_SOUND(user, voretest)
if(href_list["b_tastes"])
selected.can_taste = !selected.can_taste
if(href_list["b_bulge_size"])
var/new_bulge = input(user, "Choose the required size prey must be to show up on examine, ranging from 25% to 200% Set this to 0 for no text on examine.", "Set Belly Examine Size.") as num|null
if(new_bulge == null)
return
if(new_bulge == 0) //Disable.
selected.bulge_size = 0
to_chat(user,"<span class='notice'>Your stomach will not be seen on examine.</span>")
else if (!IsInRange(new_bulge,25,200))
selected.bulge_size = 0.25 //Set it to the default.
to_chat(user,"<span class='notice'>Invalid size.</span>")
else if(new_bulge)
selected.bulge_size = (new_bulge/100)
if(href_list["b_escapable"])
if(selected.escapable == 0) //Possibly escapable and special interactions.
selected.escapable = 1
to_chat(usr,"<span class='warning'>Prey now have special interactions with your [lowertext(selected.name)] depending on your settings.</span>")
else if(selected.escapable == 1) //Never escapable.
selected.escapable = 0
to_chat(usr,"<span class='warning'>Prey will not be able to have special interactions with your [lowertext(selected.name)].</span>")
show_interacts = 0 //Force the hiding of the panel
else
alert("Something went wrong. Your stomach will now not have special interactions. Press the button enable them again and tell a dev.","Error") //If they somehow have a varable that's not 0 or 1
selected.escapable = 0
show_interacts = 0 //Force the hiding of the panel
if(href_list["b_escapechance"])
var/escape_chance_input = input(user, "Set prey escape chance on resist (as %)", "Prey Escape Chance") as num|null
if(!isnull(escape_chance_input)) //These have to be 'null' because both cancel and 0 are valid, separate options
selected.escapechance = sanitize_integer(escape_chance_input, 0, 100, initial(selected.escapechance))
if(href_list["b_escapetime"])
var/escape_time_input = input(user, "Set number of seconds for prey to escape on resist (1-60)", "Prey Escape Time") as num|null
if(!isnull(escape_time_input))
selected.escapetime = sanitize_integer(escape_time_input*10, 10, 600, initial(selected.escapetime))
if(href_list["b_transferchance"])
var/transfer_chance_input = input(user, "Set belly transfer chance on resist (as %). You must also set the location for this to have any effect.", "Prey Escape Time") as num|null
if(!isnull(transfer_chance_input))
selected.transferchance = sanitize_integer(transfer_chance_input, 0, 100, initial(selected.transferchance))
if(href_list["b_transferlocation"])
var/obj/belly/choice = input("Where do you want your [lowertext(selected.name)] to lead if prey resists?","Select Belly") as null|anything in (user.vore_organs + "None - Remove" - selected)
if(!choice) //They cancelled, no changes
return 0
else if(choice == "None - Remove")
selected.transferlocation = null
else
selected.transferlocation = choice.name
if(href_list["b_absorbchance"])
var/absorb_chance_input = input(user, "Set belly absorb mode chance on resist (as %)", "Prey Absorb Chance") as num|null
if(!isnull(absorb_chance_input))
selected.absorbchance = sanitize_integer(absorb_chance_input, 0, 100, initial(selected.absorbchance))
if(href_list["b_digestchance"])
var/digest_chance_input = input(user, "Set belly digest mode chance on resist (as %)", "Prey Digest Chance") as num|null
if(!isnull(digest_chance_input))
selected.digestchance = sanitize_integer(digest_chance_input, 0, 100, initial(selected.digestchance))
if(href_list["b_del"])
var/alert = alert("Are you sure you want to delete your [lowertext(selected.name)]?","Confirmation","Delete","Cancel")
if(!alert == "Delete")
return 0
var/failure_msg = ""
var/dest_for //Check to see if it's the destination of another vore organ.
for(var/belly in user.vore_organs)
var/obj/belly/B = belly
if(B.transferlocation == selected)
dest_for = B.name
failure_msg += "This is the destiantion for at least '[dest_for]' belly transfers. Remove it as the destination from any bellies before deleting it. "
break
if(selected.contents.len)
failure_msg += "You cannot delete bellies with contents! " //These end with spaces, to be nice looking. Make sure you do the same.
if(selected.immutable)
failure_msg += "This belly is marked as undeletable. "
if(user.vore_organs.len == 1)
failure_msg += "You must have at least one belly. "
if(failure_msg)
alert(user,failure_msg,"Error!")
return 0
qdel(selected)
selected = user.vore_organs[1]
user.vore_selected = user.vore_organs[1]
if(href_list["saveprefs"])
if(!user.save_vore_prefs())
to_chat(user, "<span class='warning'>Belly Preferences not saved!</span>")
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")
if(!alert == "Reload")
return 0
if(!user.apply_vore_prefs())
alert("ERROR: Vore preferences failed to apply!","Error")
else
to_chat(user,"<span class='notice'>Vore preferences applied from active slot!</span>")
if(href_list["setflavor"])
var/new_flavor = html_encode(input(usr,"What your character tastes like (40ch limit). This text will be printed to the pred after 'X tastes of...' so just put something like 'strawberries and cream':","Character Flavor",user.vore_taste) as text|null)
if(!new_flavor)
return 0
new_flavor = readd_quotes(new_flavor)
if(length(new_flavor) > FLAVOR_MAX)
alert("Entered flavor/taste text too long. [FLAVOR_MAX] character limit.","Error!")
return 0
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")
switch(choice)
if("Cancel")
return 0
if("Allow Digestion")
user.digestable = TRUE
if("Prevent Digestion")
user.digestable = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.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")
switch(choice)
if("Cancel")
return 0
if("Allow Devourment")
user.devourable = TRUE
if("Prevent Devourment")
user.devourable = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.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")
switch(choice)
if("Cancel")
return 0
if("Allow Feeding")
user.feeding = TRUE
if("Prevent Feeding")
user.feeding = FALSE
if(user.client.prefs_vr)
user.client.prefs_vr.feeding = user.feeding
//Refresh when interacted with, returning 1 makes vore_look.Topic update
return 1
@@ -1,37 +0,0 @@
//The base hooks themselves
//New() hooks
/hook/client_new
/hook/mob_new
/hook/living_new
/hook/carbon_new
/hook/human_new
/hook/simple_animal_new
//Hooks for interactions
/hook/living_attackby
//
//Hook helpers to expand hooks to others
//
/hook/mob_new/proc/chain_hooks(mob/M)
var/result = 1
if(isliving(M))
if(!hook_vr("living_new",args))
result = 0
if(iscarbon(M))
if(!hook_vr("carbon_new",args))
result = 0
if(ishuman(M))
if(!hook_vr("human_new",args))
result = 0
//Return 1 to superhook
return result
@@ -1,90 +0,0 @@
/*
* Returns a byond list that can be passed to the "deserialize" proc
* to bring a new instance of this atom to its original state
*
* If we want to store this info, we can pass it to `json_encode` or some other
* interface that suits our fancy, to make it into an easily-handled string
*/
/datum/proc/serialize()
var/data = list("type" = "[type]")
return data
/*
* This is given the byond list from above, to bring this atom to the state
* described in the list.
* This will be called after `New` but before `initialize`, so linking and stuff
* would probably be handled in `initialize`
*
* Also, this should only be called by `list_to_object` in persistence.dm - at least
* with current plans - that way it can actually initialize the type from the list
*/
/datum/proc/deserialize(var/list/data)
return
/atom
// This var isn't actually used for anything, but is present so that
// DM's map reader doesn't forfeit on reading a JSON-serialized map
var/map_json_data
// This is so specific atoms can override these, and ignore certain ones
/atom/proc/vars_to_save()
return list("color","dir","icon","icon_state","name","pixel_x","pixel_y")
/atom/proc/map_important_vars()
// A list of important things to save in the map editor
return list("color","dir","icon","icon_state","layer","name","pixel_x","pixel_y")
/area/map_important_vars()
// Keep the area default icons, to keep things nice and legible
return list("name")
// No need to save any state of an area by default
/area/vars_to_save()
return list("name")
/atom/serialize()
var/list/data = ..()
for(var/thing in vars_to_save())
if(vars[thing] != initial(vars[thing]))
data[thing] = vars[thing]
return data
/atom/deserialize(var/list/data)
for(var/thing in vars_to_save())
if(thing in data)
vars[thing] = data[thing]
..()
/*
Whoops, forgot to put documentation here.
What this does, is take a JSON string produced by running
BYOND's native `json_encode` on a list from `serialize` above, and
turns that string into a new instance of that object.
You can also easily get an instance of this string by calling "Serialize Marked Datum"
in the "Debug" tab.
If you're clever, you can do neat things with SDQL and this, though be careful -
some objects, like humans, are dependent that certain extra things are defined
in their list
*/
/proc/object_to_json(var/atom/movable/thing)
return json_encode(thing.serialize())
/proc/json_to_object(var/json_data, var/loc)
return list_to_object(json_decode(json_data), loc)
/proc/list_to_object(var/list/data, var/loc)
if(!islist(data))
throw EXCEPTION("You didn't give me a list, bucko")
if(!("type" in data))
throw EXCEPTION("No 'type' field in the data")
var/path = text2path(data["type"])
if(!path)
throw EXCEPTION("Path not found: [path]")
var/atom/movable/thing = new path(loc)
thing.deserialize(data)
return thing
@@ -1,63 +0,0 @@
//
// Gravity Pull effect which draws in movable objects to its center.
// In this case, "number" refers to the range. directions is ignored.
//
/datum/effect/effect/system/grav_pull
var/pull_radius = 3
var/pull_anchored = 0
var/break_windows = 0
/datum/effect/effect/system/grav_pull/set_up(range, num, loca)
pull_radius = range
number = num
if(istype(loca, /turf/))
location = loca
else
location = get_turf(loca)
/datum/effect/effect/system/grav_pull/start()
spawn(0)
if(holder)
src.location = get_turf(holder)
for(var/i=0, i < number, i++)
do_pull()
sleep(25)
/datum/effect/effect/system/grav_pull/proc/do_pull()
//following is adapted from supermatter and singulo code
if(defer_powernet_rebuild != 2)
defer_powernet_rebuild = 1
// Let's just make this one loop.
for(var/atom/X in orange(pull_radius, location))
// Movable atoms only
if(istype(X, /atom/movable))
if(istype(X, /obj/effect/overlay)) continue
if(X && !istype(X, /mob/living/carbon/human))
if(break_windows && istype(X, /obj/structure/window)) //shatter windows
var/obj/structure/window/W = X
W.ex_act(2.0)
if(istype(X, /obj))
var/obj/O = X
if(O.anchored)
if (!pull_anchored) continue // Don't pull anchored stuff unless configured
step_towards(X, location) // step just once if anchored
continue
step_towards(X, location) // Step twice
step_towards(X, location)
else if(istype(X,/mob/living/carbon/human))
var/mob/living/carbon/human/H = X
if(istype(H.shoes,/obj/item/clothing/shoes/magboots))
var/obj/item/clothing/shoes/magboots/M = H.shoes
if(M.magpulse)
step_towards(H, location) //step just once with magboots
continue
step_towards(H, location) //step twice
step_towards(H, location)
if(defer_powernet_rebuild != 2)
defer_powernet_rebuild = 0
return
@@ -1,33 +0,0 @@
// Micro Holders - Extends /obj/item/holder
/obj/item/holder/micro
name = "micro"
desc = "Another crewmember, small enough to fit in your hand."
icon_state = "micro"
slot_flags = SLOT_FEET | SLOT_HEAD | SLOT_ID
w_class = 2
item_icons = null // Override value from parent. We don't have magic sprites.
pixel_y = 0 // Override value from parent.
/obj/item/holder/micro/examine(var/mob/user)
for(var/mob/living/M in contents)
M.examine(user)
/obj/item/holder/MouseDrop(mob/M as mob)
..()
if(M != usr) return
if(usr == src) return
if(!Adjacent(usr)) return
if(istype(M,/mob/living/silicon/ai)) return
for(var/mob/living/carbon/human/O in contents)
O.show_inv(usr)
/obj/item/holder/micro/attack_self(var/mob/living/user)
for(var/mob/living/carbon/human/M in contents)
M.help_shake_act(user)
/obj/item/holder/micro/update_state()
// If any items have been dropped by contained mob, drop them to floor.
for(var/obj/O in contents)
O.forceMove(get_turf(src))
..()
@@ -1,207 +0,0 @@
/*
//these aren't defines so they can stay in this file
GLOBAL_VAR_CONST(SIZESCALE_HUGE, 2)
GLOBAL_VAR_CONST(SIZESCALE_BIG, 1.5)
GLOBAL_VAR_CONST(SIZESCALE_NORMAL, 1)
GLOBAL_VAR_CONST(SIZESCALE_SMALL, 0.85)
GLOBAL_VAR_CONST(SIZESCALE_TINY, 0.60)
GLOBAL_VAR_CONST(SIZESCALE_A_HUGEBIG, (GLOB.SIZESCALE_HUGE + GLOB.SIZESCALE_BIG) / 2)
GLOBAL_VAR_CONST(SIZESCALE_A_BIGNORMAL, (GLOB.SIZESCALE_BIG + GLOB.SIZESCALE_NORMAL) / 2)
GLOBAL_VAR_CONST(SIZESCALE_A_NORMALSMALL,(GLOB.SIZESCALE_NORMAL + GLOB.SIZESCALE_SMALL) / 2)
GLOBAL_VAR_CONST(SIZESCALE_A_SMALLTINY,(GLOB.SIZESCALE_SMALL + GLOB.SIZESCALE_TINY) / 2)
*/
// Adding needed defines to /mob/living
// Note: Polaris had this on /mob/living/carbon/human We need it higher up for animals and stuff.
/mob/living
var/size_multiplier = 1 //multiplier for the mob's icon size
// Define holder_type on types we want to be scoop-able
//mob/living/carbon/human
// holder_type = /obj/item/holder/micro
/**
* Scale up the size of a mob's icon by the size_multiplier.
* NOTE: mob/living/carbon/human/update_transform() has a more complicated system and
* is already applying this transform. BUT, it does not call ..()
* as long as that is true, we should be fine. If that changes we need to
* re-evaluate.
*/
/mob/living/update_transform()
ASSERT(!iscarbon(src))
var/matrix/M = matrix()
M.Scale(size_multiplier)
M.Translate(0, 16*(size_multiplier-1))
src.transform = M
/**
* Get the effective size of a mob.
* Currently this is based only on size_multiplier for micro/macro stuff,
* but in the future we may also incorporate the "mob_size", so that
* a macro mouse is still only effectively "normal" or a micro dragon is still large etc.
*/
/mob/living/proc/get_effective_size()
return src.size_multiplier
/**
* Resizes the mob immediately to the desired mod, animating it growing/shrinking.
* It can be used by anything that calls it.
*/
/mob/living/proc/sizescale(var/new_size)
var/matrix/sizescale = matrix() // Defines the matrix to change the player's size
sizescale.Scale(new_size) //Change the size of the matrix
if(new_size >= SIZESCALE_NORMAL)
sizescale.Translate(0, -1 * (1 - new_size) * 16) //Move the player up in the tile so their feet align with the bottom
animate(src, transform = sizescale, time = 5) //Animate the player resizing
size_multiplier = new_size //Change size_multiplier so that other items can interact with them
/*
* Verb proc for a command that lets players change their size OOCly.
* Ace was here! Redid this a little so we'd use math for shrinking characters. This is the old code.
/mob/living/proc/set_size()
set name = "Set Character Size"
set category = "Vore"
var/nagmessage = "DO NOT ABUSE THESE COMMANDS. They are not here for you to play with. \
We were originally going to remove them but kept them for popular demand. \
Do not abuse their existence outside of ERP scenes where they apply, \
or reverting OOCly unwanted changes like someone lolshooting the crew with a shrink ray. -Ace"
var/size_name = input(nagmessage, "Pick a Size") in player_sizes_list
if (size_name && player_sizes_list[size_name])
src.sizescale(player_sizes_list[size_name])
message_admins("[key_name(src)] used the sizescale command in-game to be [size_name]. \
([src ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>" : "null"])")
/** Add the set_size() proc to usable verbs. */
/hook/living_new/proc/sizescale_setup(mob/living/M)
M.verbs += /mob/living/proc/set_size
return 1
* Attempt to scoop up this mob up into M's hands, if the size difference is large enough.
* @return false if normal code should continue, 1 to prevent normal code.
/mob/living/proc/attempt_to_scoop(var/mob/living/carbon/human/M)
if(!istype(M))
return 0;
if(M.buckled)
usr << "<span class='notice'>You have to unbuckle \the [M] before you pick them up.</span>"
return 0
if(M.get_effective_size() - src.get_effective_size() >= 0.75)
var/obj/item/holder/m_holder = get_scooped(M)
if (m_holder)
return 1
else
return 0; // Unable to scoop, let other code run
*/
/*
* Handle bumping into someone with helping intent.
* Called from /mob/living/Bump() in the 'brohugs all around' section.
* @return false if normal code should continue, 1 to prevent normal code.
* // TODO - can the now_pushing = 0 be moved up? What does it do anyway?
*/
/mob/living/proc/handle_micro_bump_helping(var/mob/living/tmob)
if(src.get_effective_size() <= SIZESCALE_A_SMALLTINY && tmob.get_effective_size() <= SIZESCALE_A_SMALLTINY)
// Both small! Go ahead and
now_pushing = 0
src.forceMove(tmob.loc)
return 1
if(abs(src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
now_pushing = 0
src.forceMove(tmob.loc)
if(src.get_effective_size() > tmob.get_effective_size())
/* var/mob/living/carbon/human/tmob = src
if(istype(tmob) && istype(tmob.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You carefully slither around [tmob]."
M << "[src]'s huge tail slithers past beside you!"
else
*/
src.forceMove(tmob.loc)
src << "You carefully step over [tmob]."
tmob << "[src] steps over you carefully!"
if(tmob.get_effective_size() > src.get_effective_size())
/* var/mob/living/carbon/human/M = M
if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You jump over [M]'s thick tail."
M << "[src] bounds over your tail."
else
*/
src.forceMove(tmob.loc)
src << "You run between [tmob]'s legs."
tmob << "[src] runs between your legs."
return 1
/**
* Handle bumping into someone without mutual help intent.
* Called from /mob/living/Bump()
* NW was here, adding even more options for stomping!
*
* @return false if normal code should continue, 1 to prevent normal code.
*/
/mob/living/proc/handle_micro_bump_other(var/mob/living/tmob)
ASSERT(isliving(tmob)) // Baby don't hurt me
if(src.a_intent == "disarm" && src.canmove && !src.buckled)
// If bigger than them by at least 0.75, move onto them and print message.
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
now_pushing = 0
src.forceMove(tmob.loc)
tmob.Stun(4)
/*
var/mob/living/carbon/human/H = src
if(istype(H) && istype(H.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You carefully squish [tmob] under your tail!"
tmob << "[src] pins you under their tail!"
else
*/
src << "You pin [tmob] beneath your foot!"
tmob << "[src] pins you beneath their foot!"
return 1
if(src.a_intent == "harm" && src.canmove && !src.buckled)
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
now_pushing = 0
src.forceMove(tmob.loc)
tmob.adjustStaminaLoss(35)
tmob.adjustBruteLoss(5)
/* var/mob/living/carbon/human/M = src
if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You steamroller over [tmob] with your heavy tail!"
tmob << "[src] ploughs you down mercilessly with their heavy tail!"
else
*/
src << "You bring your foot down heavily upon [tmob]!"
tmob << "[src] steps carelessly on your body!"
return 1
// until I figure out grabbing micros with the godawful pull code...
if(src.a_intent == "grab" && src.canmove && !src.buckled)
if((src.get_effective_size() - tmob.get_effective_size()) >= 0.20)
now_pushing = 0
tmob.adjustStaminaLoss(15)
src.forceMove(tmob.loc)
src << "You press [tmob] beneath your foot!"
tmob << "[src] presses you beneath their foot!"
/*
var/mob/living/carbon/human/M = src
if(istype(M) && !M.shoes)
// User is a human (capable of scooping) and not wearing shoes! Scoop into foot slot!
equip_to_slot_if_possible(tmob.get_scooped(M), slot_shoes, 0, 1)
if(istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You wrap up [tmob] with your powerful tail!"
tmob << "[src] binds you with their powerful tail!"
else
src << "You clench your toes around [tmob]'s body!"
tmob << "[src] grabs your body with their toes!"
else if(istype(M) && istype(M.tail_style, /datum/sprite_accessory/tail/taur/naga))
src << "You carefully squish [tmob] under your tail!"
tmob << "[src] pins you under their tail!"
else
src << "You pin [tmob] beneath your foot!"
tmob << "[src] pins you beneath their foot!"
return 1
*/
@@ -1,115 +0,0 @@
////////////////////////////
/// shrinking serum ///
////////////////////////////
/datum/reagent/medicine/macrocillin
name = "Macrocillin"
id = "macrocillin"
description = "Glowing yellow liquid."
reagent_state = LIQUID
color = "#FFFF00" // rgb: 255, 255, 0
overdose_threshold = 20
/datum/reagent/medicine/macrocillin/on_mob_life(mob/living/M, method=INGEST)
for(var/size in list(SIZESCALE_SMALL, SIZESCALE_NORMAL, SIZESCALE_BIG, SIZESCALE_HUGE))
if(M.size_multiplier < size)
M.sizescale(size)
M << "<font color='green'>You grow!</font>"
break
if(M.reagents.has_reagent("macrocillin"))
M.reagents.remove_reagent("macrocillin", 20)
..()
/datum/reagent/medicine/microcillin
name = "Microcillin"
id = "microcillin"
description = "Murky purple liquid."
reagent_state = LIQUID
color = "#800080"
overdose_threshold = 20
/datum/reagent/microcillin/on_mob_life(mob/living/M, method=INGEST)
for(var/size in list(SIZESCALE_BIG, SIZESCALE_NORMAL, SIZESCALE_SMALL, SIZESCALE_TINY))
if(M.size_multiplier > size)
M.sizescale(size)
M << "<span class='alert'>You shrink!</span>"
break;
if(M.reagents.has_reagent("microcillin"))
M.reagents.remove_reagent("microcillin", 20)
..()
/datum/reagent/medicine/normalcillin
name = "Normalcillin"
id = "normalcillin"
description = "Translucent cyan liquid."
reagent_state = LIQUID
color = "#00FFFF"
overdose_threshold = 20
/datum/reagent/medicine/normalcillin/on_mob_life(mob/living/M, method=INGEST)
if(M.size_multiplier > SIZESCALE_BIG)
M.sizescale(SIZESCALE_BIG)
M << "<span class='alert'>You shrink!</span>"
else if(M.size_multiplier > SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_NORMAL)
M << "<span class='alert'>You shrink!</span>"
else if(M.size_multiplier < SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_NORMAL)
M << "<font color='green'>You grow!</font>"
else if(M.size_multiplier < SIZESCALE_SMALL)
M.sizescale(SIZESCALE_SMALL)
M << "<font color='green'>You grow!</font>"
if(M.reagents.has_reagent("normalcillin"))
M.reagents.remove_reagent("normalcillin", 20)
..()
/datum/reagent/medicine/sizeoxadone
name = "Sizeoxadone"
id = "sizeoxadone"
description = "A volatile liquid used as a precursor to size-altering chemicals. Causes dizziness if taken unprocessed."
reagent_state = LIQUID
color = "#1E90FF"
overdose_threshold = 30
metabolization_rate = 0.8 * REAGENTS_METABOLISM
/datum/reagent/sizeoxadone/on_mob_life(var/mob/living/carbon/M, var/removed)
if(M.hallucination < volume && prob(20))
M.hallucination += 5
if(!M.confused) M.confused = 1
M.confused = max(M.confused, 20)
return
/datum/reagent/medicine/sizeoxadone/overdose_process(mob/living/M)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1)
M.adjustToxLoss(1)
..()
. = 1
////////////////////////// Anti-Noms Drugs //////////////////////////
/datum/reagent/medicine/ickypak
name = "Ickypak"
id = "ickypak"
description = "A foul-smelling green liquid, for inducing muscle contractions to expel accidentally ingested things."
reagent_state = LIQUID
color = "#0E900E"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
/datum/reagent/medicine/ickypak/on_mob_life(var/mob/living/M, method=INGEST)
..()
if(M.hallucination < volume && prob(20))
M.hallucination += 5
M.adjustToxLoss(-5)
for(var/I in M.vore_organs)
var/datum/belly/B = M.vore_organs[I]
for(var/atom/movable/A in B.internal_contents)
if(prob(55))
playsound(M, 'sound/effects/splat.ogg', 50, 1)
B.release_vore_contents(A)
..()
. = 1
@@ -1,169 +0,0 @@
//
// Size Gun
//
/*
/obj/item/gun/energy/sizegun
name = "shrink ray"
desc = "A highly advanced ray gun with two settings: Shrink and Grow. Warning: Do not insert into mouth."
icon = 'icons/obj/gun_vr.dmi'
icon_state = "sizegun-shrink100" // Someone can probably do better. -Ace
item_state = null //so the human update icon uses the icon_state instead
fire_sound = 'sound/weapons/wave.ogg'
charge_cost = 100
projectile_type = /obj/item/projectile/beam/shrinklaser
modifystate = "sizegun-shrink"
selfcharge = EGUN_SELFCHARGE
firemodes = list(
list(mode_name = "grow",
projectile_type = /obj/item/projectile/beam/growlaser,
modifystate = "sizegun-grow",
fire_sound = 'sound/weapons/pulse3.ogg'
),
list(mode_name = "shrink",
projectile_type = /obj/item/projectile/beam/shrinklaser,
modifystate = "sizegun-shrink",
fire_sound = 'sound/weapons/wave.ogg'
))
//
// Beams for size gun
//
// tracers TBD
/obj/item/projectile/beam/shrinklaser
name = "shrink beam"
icon_state = "xray"
nodamage = 1
damage = 0
check_armour = "laser"
muzzle_type = /obj/effect/projectile/xray/muzzle
tracer_type = /obj/effect/projectile/xray/tracer
impact_type = /obj/effect/projectile/xray/impact
/obj/item/projectile/beam/shrinklaser/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
M.sizescale(SIZESCALE_BIG)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
M.sizescale(SIZESCALE_NORMAL)
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
M.sizescale(SIZESCALE_SMALL)
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
return 1
/obj/item/projectile/beam/growlaser
name = "growth beam"
icon_state = "bluelaser"
nodamage = 1
damage = 0
check_armour = "laser"
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
tracer_type = /obj/effect/projectile/laser_blue/tracer
impact_type = /obj/effect/projectile/laser_blue/impact
/obj/item/projectile/beam/growlaser/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
M.sizescale(SIZESCALE_HUGE)
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
M.sizescale(SIZESCALE_BIG)
if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_NORMAL)
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
return 1
*/
datum/design/sizeray
name = "Size Ray"
desc = "Abuse bluespace tech to alter living matter scale."
id = "sizeray"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 1000, MAT_DIAMOND = 2500, MAT_URANIUM = 2500, MAT_TITANIUM = 1000)
build_path = /obj/item/gun/energy/laser/sizeray
category = list("Weapons")
/obj/item/projectile/sizeray
name = "sizeray beam"
icon_state = "omnilaser"
hitsound = null
damage = 0
damage_type = STAMINA
flag = "laser"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
/obj/item/projectile/sizeray/shrinkray
icon_state="bluelaser"
/obj/item/projectile/sizeray/growthray
icon_state="laser"
/obj/item/projectile/sizeray/shrinkray/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
M.sizescale(SIZESCALE_BIG)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
M.sizescale(SIZESCALE_NORMAL)
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
M.sizescale(SIZESCALE_SMALL)
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
return 1
/obj/item/projectile/sizeray/growthray/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
M.sizescale(SIZESCALE_HUGE)
if(SIZESCALE_NORMAL to SIZESCALE_BIG)
M.sizescale(SIZESCALE_BIG)
if(SIZESCALE_SMALL to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_NORMAL)
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
return 1
/obj/item/ammo_casing/energy/laser/growthray
projectile_type = /obj/item/projectile/sizeray/growthray
select_name = "Growth"
/obj/item/ammo_casing/energy/laser/shrinkray
projectile_type = /obj/item/projectile/sizeray/shrinkray
select_name = "Shrink"
//Gun here
/obj/item/gun/energy/laser/sizeray
name = "size ray"
icon_state = "bluetag"
desc = "Size manipulator using bluespace breakthroughs."
item_state = null //so the human update icon uses the icon_state instead.
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray, /obj/item/ammo_casing/energy/laser/growthray)
selfcharge = EGUN_SELFCHARGE
charge_delay = 5
ammo_x_offset = 2
clumsy_check = 1
attackby(obj/item/W, mob/user)
if(W==src)
if(icon_state=="bluetag")
icon_state="redtag"
ammo_type = list(/obj/item/ammo_casing/energy/laser/growthray)
else
icon_state="bluetag"
ammo_type = list(/obj/item/ammo_casing/energy/laser/shrinkray)
return ..()
@@ -1,62 +0,0 @@
/*
This file is for jamming single-line procs into Polaris procs.
It will prevent runtimes and allow their code to run if these fail.
It will also log when we mess up our code rather than making it vague.
Call it at the top of a stock proc with...
if(attempt_vr(object,proc to call,args)) return
...if you are replacing an entire proc.
The proc you're attemping should return nonzero values on success.
*/
/proc/attempt_vr(callon, procname, list/args=null)
try
if(!callon || !procname)
CRASH("attempt_vr: Invalid obj/proc: [callon]/[procname]")
return 0
var/result = call(callon,procname)(arglist(args))
return result
catch(var/exception/e)
CRASH("attempt_vr runtimed when calling [procname] on [callon].")
CRASH("attempt_vr catch: [e] on [e.file]:[e.line]")
return 0
/*
This is the _vr version of calling hooks.
It's meant to have different messages, and also the try/catch block.
For when you want hooks and want to know when you ruin everything,
vs when Polaris ruins everything.
Call it at the top of a stock proc with...
if(hook_vr(proc,args)) return
...if you are replacing an entire proc.
The hooks you're calling should return nonzero values on success.
*/
/proc/hook_vr(hook, list/args=null)
try
var/hook_path = text2path("/hook/[hook]")
if(!hook_path)
CRASH("hook_vr: Invalid hook '/hook/[hook]' called.")
return 0
var/caller = new hook_path
var/status = 1
for(var/P in typesof("[hook_path]/proc"))
if(!call(caller, P)(arglist(args)))
CRASH("hook_vr: Hook '[P]' failed or runtimed.")
status = 0
return status
catch(var/exception/e)
CRASH("hook_vr itself failed or runtimed. Exception below.")
CRASH("hook_vr catch: [e] on [e.file]:[e.line]")