Merge remote-tracking branch 'upstream/master' into markings-and-more

This commit is contained in:
Dahlular
2022-05-14 22:07:39 -06:00
143 changed files with 4694 additions and 2627 deletions
+71 -103
View File
@@ -11,7 +11,15 @@
for(var/obj/item/organ/genital/G in U.internal_organs)
if(!G.nochange)
if(!G.dontlist)
dat += "<a href='byond://?src=[REF(src)];hide[G.name]=1'>[G.mode == "hidden" ? "[G.name] <font color='red'>(Hidden)</font>" : (G.mode == "clothes" ? "[G.name] <font color='yellow'>(Hidden by Clothes)</font>" : (G.mode == "visable" ? "[G.name] <font color='green'>(Visable)</font>" : "[G.name] <font color='green'>(Visable)</font>"))]</a><BR>"
var/genital_visibility = "[G.name] <font color='green'>(Visible)</font>"
switch(G.mode)
if(GENITALS_HIDDEN)
genital_visibility = "[G.name] <font color='red'>(Hidden)</font>"
if(GENITALS_CLOTHES)
genital_visibility = "[G.name] <font color='yellow'>(Hidden by Clothes)</font>"
if(GENITALS_VISIBLE)
genital_visibility = "[G.name] <font color='green'>(Visible)</font>"
dat += "<a href='byond://?src=[REF(src)];hide[G.name]=1'>[genital_visibility]</a><BR>"
dat += {"<BR><B>Contexual Options</B><BR><HR>"}
var/obj/item/organ/genital/penis/P = user.getorganslot("penis")
@@ -45,20 +53,17 @@
if(Belly.inflatable)
dat += "<a href='byond://?src=[REF(src)];shrink_belly=1'>Deflate belly</A>"
dat += "(Shrink your belly down a size)<BR>"
if(user.pulling)
if(user.pulling && !isnoncarbon(user.pulling)) // do not fuck animals
dat += "<a href='byond://?src=[REF(src)];climaxover=1'>Climax over [user.pulling]</A>" //you can cum on objects if you really want...
dat += "(Orgasm over a person or object.)<BR>"
if(isliving(user.pulling))
if(iscarbon(user.pulling))
dat += "<a href='byond://?src=[REF(src)];climaxwith=1'>Climax with [user.pulling]</A>"
dat += {"(Orgasm with another person.)<BR>"}
var/mob/living/carbon/human/H = user.pulling
if(H.breedable && P && H)
dat += "<a href='byond://?src=[REF(src)];impreg=1'>Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)</A>"
dat += "(Climax inside another person, and attempt to knock them up.)<BR>"
if(iscarbon(user.pulling))
dat += "<a href='byond://?src=[REF(src)];climaxwith=1'>Climax with [user.pulling]</A>"
dat += {"(Orgasm with another person.)<BR>"}
var/mob/living/carbon/human/H = user.pulling
if(H && H.breedable && P)
dat += "<a href='byond://?src=[REF(src)];impreg=1'>Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)</A>"
dat += "(Climax inside another person, and attempt to knock them up.)<BR>"
else
dat += "<span class='linkOff'>Climax over</span></A>"
dat += "(Requires a partner)<BR>"
@@ -81,11 +86,9 @@
dat += "<a href='byond://?src=[REF(src)];omenu=1'>Old Menu</A>"
dat += "<a href='byond://?src=[REF(src)];underwear=1'>Toggle Undergarments </A>"
dat += "<BR>"
var/datum/browser/popup = new(user, "arousal", "Arousal Panel")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state), 500,600)
popup.open()
@@ -140,7 +143,7 @@
T.toggle_visibility(picked_visibility)
if(href_list["masturbate"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.solomasturbate()
return
else
@@ -148,7 +151,7 @@
return
if(href_list["container"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.cumcontainer()
return
else
@@ -156,7 +159,7 @@
return
if(href_list["clothesplosion"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //Requires 33% arousal.
if (H.isPercentAroused(33)) //Requires 33% arousal.
H.clothesplosion()
return
else
@@ -164,7 +167,7 @@
return
if(href_list["climaxself"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.climaxself()
return
else
@@ -172,7 +175,7 @@
return
if(href_list["climax"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.climaxalone(FALSE)
return
else
@@ -180,7 +183,7 @@
return
if(href_list["climaxover"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.climaxover(usr.pulling)
return
else
@@ -188,7 +191,7 @@
return
if(href_list["climaxwith"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.climaxwith(usr.pulling)
return
else
@@ -196,7 +199,7 @@
return
if(href_list["impreg"])
if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal.
if (H.isPercentAroused(33)) //requires 33% arousal.
H.impregwith(usr.pulling)
return
else
@@ -211,13 +214,7 @@
return
if(href_list["shrink_belly"])
var/obj/item/organ/genital/belly/E = usr.getorganslot("belly")
if(E.size > 0)
to_chat(usr, "<span class='userlove'>You feel your belly diminish.</span>")
E.size -= 1
H.update_genitals()
else
to_chat(usr, "<span class='warning'>Your belly is already at the minimum size! </span>")
H.shrink_belly(1)
if(href_list["removecondom"])
H.menuremovecondom()
@@ -337,7 +334,7 @@ obj/screen/arousal/proc/kiss()
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
picked_organ = pick_masturbate_genitals()
picked_organ = pick_climax_genitals(masturbation=TRUE, title="Masturbation")
if(picked_organ)
src << browse(null, "window=arousal") //closes the window
mob_masturbate(picked_organ)
@@ -371,55 +368,31 @@ obj/screen/arousal/proc/kiss()
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
/mob/living/carbon/human/proc/climaxwith(mob/living/T)
var/mob/living/carbon/human/L = pick_partner()
/mob/living/carbon/human/proc/climaxwith(mob/living/carbon/human/partner)
if(!partner)
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals()
if(picked_organ)
var/mob/living/partner = L
if(partner)
src << browse(null, "window=arousal") //alls fine, we can close the window now.
var/obj/item/organ/genital/penis/P = picked_organ
var/spillage = "No" //default to no, just incase player has items on to prevent climax
if(!P.condom == 1&&!P.sounding == 1) //you cant climax with a condom on or sounding in.
spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No")
if(spillage == "Yes")
mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE)
else
mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //They either lack organs that can masturbate, or they didn't pick one.
if(!picked_organ)
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
src << browse(null, "window=arousal") // close arousal window
mob_climax_inside_spillage(picked_organ, partner, impreg=FALSE)
/mob/living/carbon/human/proc/climaxover(mob/living/T)
var/mob/living/carbon/human/L = T
/mob/living/carbon/human/proc/climaxover(atom/partner)
var/obj/item/organ/genital/picked_organ
picked_organ = pick_climax_genitals()
if(picked_organ)
src << browse(null, "window=arousal") //alls fine, we can close the window now.
var/mob/living/partner = L
if(partner)
var/obj/item/organ/genital/penis/P = picked_organ
if(P.condom == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a condom on.</span>")
return
if(P.sounding == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a sounding in.</span>")
return
mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //They either lack organs that can masturbate, or they didn't pick one.
if(!picked_organ)
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
return
src << browse(null, "window=arousal") //alls fine, we can close the window now.
if(!partner || isnoncarbon(partner))
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
mob_climax_cover(picked_organ, partner)
/mob/living/carbon/human/proc/clothesplosion()
if(usr.restrained(TRUE))
@@ -434,39 +407,29 @@ obj/screen/arousal/proc/kiss()
H.visible_message("<span class='boldnotice'>[H] explodes out of their clothes!'</span>")
/mob/living/carbon/human/proc/impregwith(mob/living/T)
var/mob/living/carbon/human/L = pick_partner()
var/obj/item/organ/genital/picked_organ
picked_organ = src.getorganslot("penis") //Impregnation must be done with a penis.
if(picked_organ)
var/mob/living/partner = L
if(partner)
if(!partner.breedable)//check if impregable.
to_chat(src, "<span class='warning'>Your partner cannot be impregnated.</span>")//some fuckary happening, you shouldnt even get to this point tbh.
return
var/obj/item/organ/genital/penis/P = picked_organ
//you cant impreg with a condom on or sounding in.
if(P.condom == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a condom on.</span>")
return
if(P.sounding == 1)
to_chat(src, "<span class='warning'>You cannot do this action with a sounding in.</span>")
return
src << browse(null, "window=arousal") //alls fine, we can close the window now.
//Keeping this for messy fun
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No")
if(spillage == "Yes")
mob_climax_partner(picked_organ, partner, TRUE, TRUE, FALSE)
else
mob_climax_partner(picked_organ, partner, FALSE, TRUE, FALSE)
else
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
else //no penis :(
to_chat(src, "<span class='warning'>You cannot impregnate without a penis.</span>")
/mob/living/carbon/human/proc/impregwith(mob/living/carbon/T)
var/mob/living/carbon/human/partner = pick_partner()
var/obj/item/organ/genital/penis/picked_organ = src.getorganslot("penis")
// wow that is a lot of conditionals huh
if(!picked_organ) // no penis :(
to_chat(src, "<span class='warning'>You cannot impregnate someone without a penis.</span>")
return
if(!partner)
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
return
if(!partner.breedable) //check if impregable.
to_chat(src, "<span class='warning'>Your partner cannot be impregnated.</span>")
//some fuckery happening, you shouldnt even get to this point tbh.
return
if(picked_organ.condom)
to_chat(src, "<span class='warning'>You cannot impregnate someone with a condom on.</span>")
return
if(picked_organ.sounding)
to_chat(src, "<span class='warning'>You cannot impregnate someone with a sounding rod in.</span>")
return
src << browse(null, "window=arousal") //alls fine, we can close the window now.
mob_climax_inside_spillage(picked_organ, partner, impreg=TRUE)
/mob/living/carbon/human/proc/cumcontainer(mob/living/T)
//We'll need hands and no restraints.
@@ -506,6 +469,11 @@ obj/screen/arousal/proc/kiss()
cum_splatter_icon.Blend(icon('hyperstation/icons/effects/cumoverlay.dmi', "cum_obj"), ICON_MULTIPLY)
add_overlay(cum_splatter_icon)
/mob/living/carbon/add_cum_overlay(type="normal")
var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi')
cumoverlay.icon_state = "cum_[type]"
add_overlay(cumoverlay)
/atom/proc/wash_cum()
cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_normal"))
cut_overlay(mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi', "cum_large"))
@@ -529,7 +497,7 @@ obj/screen/arousal/proc/kiss()
return
//We got hands, let's pick an organ
var/obj/item/organ/genital/picked_organ
picked_organ = pick_masturbate_genitals()
picked_organ = pick_climax_genitals(masturbation=TRUE, title="Masturbation")
if(picked_organ)
src << browse(null, "window=arousal") //closes the window
mob_masturbate(picked_organ, cover = TRUE)
@@ -0,0 +1,35 @@
/mob/living/carbon/proc/expand_belly(expansion = 1)
var/obj/item/organ/genital/belly/_belly = getorganslot("belly")
if(!expansion || !_belly || !_belly.inflatable)
return
var/original_size = _belly.size
_belly.size = clamp(_belly.size + expansion, BELLY_MIN_SIZE, BELLY_MAX_SIZE)
if(_belly.size == original_size)
return
var/_verb = "expand"
switch(_belly.size)
if(BELLY_MAX_SIZE to INFINITY)
_verb = "stretch to its limit"
if(BELLY_STRETCH_SIZE to BELLY_MAX_SIZE)
_verb = "stretch"
if(BELLY_STRAIN_SIZE to BELLY_STRETCH_SIZE)
_verb = "strain"
to_chat(src, "<span class='userlove'>You feel your belly [_verb].</span>")
_belly.update()
/mob/living/carbon/proc/shrink_belly(shrinkage = 1)
var/obj/item/organ/genital/belly/_belly = getorganslot("belly")
if(!shrinkage ||!_belly || !_belly.inflatable)
return
var/original_size = _belly.size
_belly.size = clamp(_belly.size - shrinkage, BELLY_MIN_SIZE, BELLY_MAX_SIZE)
if(_belly.size == original_size)
return
var/_verb = "diminish"
var/_class = "userlove"
if(_belly.size == BELLY_MIN_SIZE)
_verb = "can't shrink anymore"
_class = "warning"
to_chat(src, "<span class='[_class]'>You feel your belly [_verb].</span>")
_belly.update()
@@ -0,0 +1,6 @@
/obj/item/organ/genital/proc/get_fluid_source()
if(producing)
return src.reagents
if(linked_organ && linked_organ.producing)
return linked_organ.reagents
return null
@@ -0,0 +1,36 @@
/datum/preferences/proc/hyper_character_pref_load(savefile/S)
S["feature_cosmetic_head"] >> features["cosmetic_head"]
S["feature_cosmetic_chest"] >> features["cosmetic_chest"]
S["feature_cosmetic_l_arm"] >> features["cosmetic_l_arm"]
S["feature_cosmetic_r_arm"] >> features["cosmetic_r_arm"]
S["feature_cosmetic_l_leg"] >> features["cosmetic_l_leg"]
S["feature_cosmetic_r_leg"] >> features["cosmetic_r_leg"]
S["cosmetic_markings"] >> features["cosmetic_markings"]
var/cosmetic_head = sanitize_inlist(features["cosmetic_head"], GLOB.cosmetic_heads, "default")
var/cosmetic_chest = sanitize_inlist(features["cosmetic_chest"], GLOB.cosmetic_chests, "default")
var/cosmetic_l_arm = sanitize_inlist(features["cosmetic_l_arm"], GLOB.cosmetic_arms, "default")
var/cosmetic_r_arm = sanitize_inlist(features["cosmetic_r_arm"], GLOB.cosmetic_arms, "default")
var/cosmetic_l_leg = sanitize_inlist(features["cosmetic_l_leg"], GLOB.cosmetic_legs, "default")
var/cosmetic_r_leg = sanitize_inlist(features["cosmetic_r_leg"], GLOB.cosmetic_legs, "default")
features["cosmetic_head"] = GLOB.cosmetic_heads[cosmetic_head]
features["cosmetic_chest"] = GLOB.cosmetic_chests[cosmetic_chest]
features["cosmetic_l_arm"] = GLOB.cosmetic_arms[cosmetic_l_arm]
features["cosmetic_r_arm"] = GLOB.cosmetic_arms[cosmetic_r_arm]
features["cosmetic_l_leg"] = GLOB.cosmetic_legs[cosmetic_l_leg]
features["cosmetic_r_leg"] = GLOB.cosmetic_legs[cosmetic_r_leg]
/datum/preferences/proc/hyper_character_pref_save(savefile/S)
var/datum/cosmetic_part/head = features["cosmetic_head"]
var/datum/cosmetic_part/chest = features["cosmetic_chest"]
var/datum/cosmetic_part/l_arm = features["cosmetic_l_arm"]
var/datum/cosmetic_part/r_arm = features["cosmetic_r_arm"]
var/datum/cosmetic_part/l_leg = features["cosmetic_l_leg"]
var/datum/cosmetic_part/r_leg = features["cosmetic_r_leg"]
WRITE_FILE(S["feature_cosmetic_head"], head.id)
WRITE_FILE(S["feature_cosmetic_chest"], chest.id)
WRITE_FILE(S["feature_cosmetic_l_arm"], l_arm.id)
WRITE_FILE(S["feature_cosmetic_r_arm"], r_arm.id)
WRITE_FILE(S["feature_cosmetic_l_leg"], l_leg.id)
WRITE_FILE(S["feature_cosmetic_r_leg"], r_leg.id)
WRITE_FILE(S["cosmetic_markings"], features["cosmetic_markings"])
@@ -0,0 +1,5 @@
/datum/gear/gasmask
name = "gas mask"
category = SLOT_WEAR_MASK
path = /obj/item/clothing/mask/gas
cost = 3
@@ -3,3 +3,9 @@
id = /datum/reagent/consumable/pilk
results = list(/datum/reagent/consumable/pilk = 2)
required_reagents = list(/datum/reagent/consumable/milk = 1, /datum/reagent/consumable/space_cola = 1)
/datum/chemical_reaction/javelin
name = "Javelin"
id = /datum/reagent/consumable/ethanol/javelin
results = list(/datum/reagent/consumable/ethanol/javelin = 5)
required_reagents = list(/datum/reagent/consumable/kalynajuice = 1, /datum/reagent/consumable/ethanol/whiskey = 2, /datum/reagent/consumable/ethanol/vodka = 2)
@@ -0,0 +1,40 @@
// Kalyna Berries
/obj/item/seeds/kalyna
name = "pack of kalyna berry seeds"
desc = "Seeds that grow into Kalyna plants. Take that Red Kalyna and rise it up."
icon = 'hyperstation/icons/obj/hydroponics/seeds.dmi'
icon_state = "seed-kalyna"
species = "kalyna"
plantname = "Kalyna Shrub Tree"
product = /obj/item/reagent_containers/food/snacks/grown/kalyna
lifespan = 20
maturation = 5
production = 5
growthstages = 5
yield = 4
growing_icon = 'hyperstation/icons/obj/hydroponics/growing_fruits.dmi'
icon_grow = "kalyna-grow"
icon_dead = "kalyna-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/kalyna
seed = /obj/item/seeds/kalyna
name = "branch of kalyna"
desc = "Red berries, attached to a branch. Just looking at it makes you feel an aura of unity."
icon = 'hyperstation/icons/obj/hydroponics/harvest.dmi'
icon_state = "kalynaberries"
gender = PLURAL
filling_color = "#FF0000"
bitesize_mod = 2
foodtype = FRUIT
juice_results = list(/datum/reagent/consumable/kalynajuice = 1)
tastes = list("sweet cranberries" = 1)
distill_reagent = /datum/reagent/consumable/ethanol/gin
//For those of you wondering, yes, this is very much an addition in support of Ukraine. I decided to make these after a distant Ukranian relative of mine sent me Go_A's 'Kalyna' song.
//Our future as a free world could very well depend on the heroism of the people of glorious Ukraine. We owe our freedom to them.
//I know that this game should be for escapism, but there's only so much we should escape from. When people's lives are being upturned-- Or taken by a brutal invasive reigime, perhaps then it's when we should take a stand.
//And for those that oppose the freedom of the people of Ukraine, Russia, and Belarus; Prykhyl'nyk Putina, idy na khuy. And show some basic empathy for once, it's not that hard.
//Glory to Ukraine, Glory to the Heroes!
// - Arctaisia, Hyperstation developer and spriter, 23/04/2022 #StandWithUkraine
@@ -0,0 +1,154 @@
/*
COSMETIC PARTS
this system allows you to change the _base_ appearance of a limb independent
of species or markings. this, for example, allows us to create "hybrids" like a
mammal with avian legs.
keep in mind that this does not change the species of a leg! in the above example,
the mammal's bird-legs are still mammal legs. this matters in some places, like
body part transplants; mis-matched species will cause extra damage if the surgery
fails and the part is rejected. so you can't attach mammal-bird legs to avians
safely.
*/
/datum/cosmetic_part
/** A unique string that is used to identify this part for save files. Allows name changes without breaking saves */
var/id
/** The name of the cosmetic part. This shows up in the preferences dropdown. */
var/name
var/icon = 'hyperstation/icons/mob/char_parts.dmi'
var/icon_state
/** How colors are determined for this part. MUTCOLORS for base color, MATRIXED to allow multiple channels. */
var/color_src = MUTCOLORS
/** Whether or not this cosmetic part has an alternate form for digitigrade legs. */
var/support_digitigrade = TRUE
/** Species IDs that support this cosmetic part. Bypassed with "show mismatched markings" option. */
var/list/supported_species
/datum/cosmetic_part/head
/datum/cosmetic_part/chest
/datum/cosmetic_part/arms
/datum/cosmetic_part/legs
// HEADS
// =========================================
/datum/cosmetic_part/head/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/head/ipc_round
id = "ipc_round"
name = "round ipc head"
icon_state = "ipc_round"
supported_species = list("ipc")
// CHESTS
// =========================================
/datum/cosmetic_part/chest/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/chest/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc chest"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
/datum/cosmetic_part/chest/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc chest"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
// ARMS
// =========================================
/datum/cosmetic_part/arms/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/arms/avian_alt
id = "avian_alt"
name = "avian claws"
icon_state = "avian_alt"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
/datum/cosmetic_part/arms/insect
id = "insect"
name = "insect arms"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "insect"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
/datum/cosmetic_part/arms/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc arms"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
/datum/cosmetic_part/arms/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc arms"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
// LEGS
// =========================================
/datum/cosmetic_part/legs/default
id = "default"
name = "default"
icon = null
/datum/cosmetic_part/legs/avian
id = "avian"
name = "avian legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "avian"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = FALSE
/datum/cosmetic_part/legs/mammal
id = "mammal"
name = "mammal legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "mammal"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = TRUE
/datum/cosmetic_part/legs/insect
id = "insect"
name = "insect legs"
icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi'
icon_state = "insect"
supported_species = list("mammal", "avian", "aquatic", "insect", "xeno", "synthliz")
support_digitigrade = TRUE
/datum/cosmetic_part/legs/ipc_sleek
id = "ipc_sleek"
name = "sleek ipc legs"
icon_state = "ipc_sleek"
supported_species = list("ipc")
color_src = MATRIXED
support_digitigrade = FALSE
/datum/cosmetic_part/legs/ipc_jointed
id = "ipc_jointed"
name = "jointed ipc legs"
icon_state = "ipc_jointed"
supported_species = list("ipc")
color_src = MATRIXED
support_digitigrade = FALSE
@@ -437,6 +437,12 @@ from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
name = "RadDog (Hyper)"
icon_state = "chemlight"
icon = 'hyperstation/icons/mob/char_markings.dmi'
//racc do a code maybe it won't explode
/datum/sprite_accessory/mam_body_markings/raccalt
name = "RaccAlt (Hyper)"
icon_state = "raccalt"
icon = 'hyperstation/icons/mob/char_markings.dmi'
/*
TAUR BODIES
@@ -469,6 +475,92 @@ from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
taur_mode = PAW_TAURIC
ckeys_allowed = list("chemlight")
/*
IPCS
==========================================================
*/
/*
from modular_citadel/code/modules/mob/dead/new_player/sprite_accessories.dm:
/datum/sprite_accessory/antenna
icon = 'modular_citadel/icons/mob/ipc_antennas.dmi'
color_src = MUTCOLORS3
recommended_species = list("ipc")
/datum/sprite_accessory/screen
icon = 'modular_citadel/icons/mob/ipc_screens.dmi'
color_src = null
*/
/datum/sprite_accessory/antenna/idog_down
name = "Dog, down (Hyper)"
icon_state = "idog_down"
color_src = MATRIXED
/datum/sprite_accessory/antenna/idog_up
name = "Dog, up (Hyper)"
icon_state = "idog_up"
color_src = MATRIXED
/datum/sprite_accessory/antenna/headset
name = "Headphones (Hyper)"
icon_state = "headset"
color_src = MATRIXED
/datum/sprite_accessory/antenna/aquatic
name = "Fins (Hyper)"
icon_state = "aquatic"
color_src = MATRIXED
/datum/sprite_accessory/screen/ghost
name = "Ghost (Hyper)"
icon_state = "ghost"
/datum/sprite_accessory/screen/heartbeat
name = "Heartbeat (Hyper)"
icon_state = "heartbeat"
/datum/sprite_accessory/screen/ocean
name = "Ocean (Hyper)"
icon_state = "ocean"
/datum/sprite_accessory/antenna/catears
name = "Pointy Ears (Hyper)"
icon_state = "catears"
color_src = MATRIXED
/datum/sprite_accessory/screen/valley
name = "Valley (Hyper)"
icon_state = "valley"
/datum/sprite_accessory/screen/visor
name = "Black Visor (Hyper)"
icon = 'hyperstation/icons/mob/ipc_screen_visor.dmi'
icon_state = "visor_black"
/datum/sprite_accessory/screen/visor/blue
name = "Blue Visor (Hyper)"
icon_state = "visor_blue"
/datum/sprite_accessory/screen/visor/green
name = "Green Visor (Hyper)"
icon_state = "visor_green"
/datum/sprite_accessory/screen/visor/red
name = "Red Visor (Hyper)"
icon_state = "visor_red"
/datum/sprite_accessory/screen/visor/white
name = "White Visor (Hyper)"
icon_state = "visor_white"
/datum/sprite_accessory/screen/visor/yellow
name = "Yellow Visor (Hyper)"
icon_state = "visor_yellow"
/*
HAIRSTYLES
==========================================================
@@ -13,6 +13,11 @@
/mob/living/carbon/handle_status_effects()
..()
handle_pain()
/mob/living/carbon/has_mouth()
var/obj/item/bodypart/head/head = get_bodypart(BODY_ZONE_HEAD)
if(head && head.mouth)
return TRUE
/mob/living/carbon/proc/handle_pain()
var/pain_amount = 0
@@ -97,7 +102,7 @@
stuttering += 3 //stutter words
//if they are asleep, this wont trigger.
if (total_pain > 110 && stat == 0) //taking 77 all damage at once from full health, will put you into shock and kill you. This cant be achived with chip damage (or fist fights), because youll die before you reach this pain level.
if (total_pain > 120 && stat == 0) //taking 130 all damage at once from full health, will put you into shock and kill you. This cant be achived with chip damage (or fist fights), because youll die before you reach this pain level.
if(prob(50))
emote("scream")//scream
to_chat(src, "<span class='big warning'>You give into the pain...</span>")
@@ -0,0 +1,17 @@
/obj/item/bodypart/proc/apply_cosmetic(datum/cosmetic_part/part)
if(!is_organic_limb() || animal_origin || !part)
return
cosmetic_icon = part
/mob/living/carbon/human/proc/handle_cosmetic_parts()
var/features = dna.features
var/list/body_zones = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
for(var/zone in body_zones)
var/datum/cosmetic_part/cosmetic_pref = features["cosmetic_" + zone]
if(!istype(cosmetic_pref, /datum/cosmetic_part))
continue
var/datum/cosmetic_part/part = cosmetic_pref
var/obj/item/bodypart/body_part = get_bodypart(zone)
if(body_part && part)
body_part.apply_cosmetic(part)
@@ -0,0 +1,58 @@
// APC powercord: oracle port
/obj/item/apc_powercord
name = "power cord"
desc = "An internal power cord hooked up to a battery. Useful if you run on electricity. Not so much otherwise."
icon = 'icons/obj/power.dmi'
icon_state = "wire1"
/obj/item/apc_powercord/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
if(!istype(target, /obj/machinery/power/apc) || !ishuman(user) || !proximity_flag)
return ..()
user.changeNext_move(CLICK_CD_MELEE)
var/mob/living/carbon/human/H = user
var/obj/item/organ/stomach/cell/battery = H.getorganslot(ORGAN_SLOT_STOMACH)
if(!battery)
to_chat(H, "<span class='warning'>You try to siphon energy from \the [target], but your power cell is gone!</span>")
return
if(istype(H) && H.nutrition >= NUTRITION_LEVEL_ALMOST_FULL)
to_chat(user, "<span class='warning'>You are already fully charged!</span>")
return
if(istype(target, /obj/machinery/power/apc))
var/obj/machinery/power/apc/A = target
if(A.cell && A.cell.charge > A.cell.maxcharge*0.25)
powerdraw_loop(A, H)
return
else
to_chat(user, "<span class='warning'>There is not enough charge to draw from that APC.</span>")
return
/obj/item/apc_powercord/proc/powerdraw_loop(obj/machinery/power/apc/A, mob/living/carbon/human/H)
H.visible_message("<span class='notice'>[H] inserts a power connector into the [A].</span>", "<span class='notice'>You begin to draw power from the [A].</span>")
while(do_after(H, 10, target = A))
if(!istype(A))
return
if(loc != H)
to_chat(H, "<span class='warning'>You must keep your connector out while charging!</span>")
break
if(A.cell.charge == 0)
to_chat(H, "<span class='warning'>The [A] doesn't have enough charge to spare.</span>")
break
A.charging = 1
if(A.cell.charge >= 500)
H.nutrition += 50
A.cell.charge -= 250
to_chat(H, "<span class='notice'>You siphon off some of the stored charge for your own use.</span>")
else
H.nutrition += A.cell.charge/10
A.cell.charge = 0
to_chat(H, "<span class='notice'>You siphon off as much as the [A] can spare.</span>")
break
if(H.nutrition > NUTRITION_LEVEL_WELL_FED)
to_chat(H, "<span class='notice'>You are now fully charged.</span>")
break
H.visible_message("<span class='notice'>[H] unplugs from the [A].</span>", "<span class='notice'>You unplug from the [A].</span>")
@@ -0,0 +1,246 @@
/mob/living/simple_animal/
var/happiness = 50 //how happy they are.
/////////////
//////////////// CHICKEN /////////////////
/////////////
/mob/living/simple_animal/chick
icon = 'hyperstation/icons/mob/chickens.dmi'
name = "\improper chick"
desc = "Adorable! They make such a racket though."
icon_state = "chick"
icon_living = "chick"
icon_dead = "chick_dead"
icon_gib = "chick_gib"
gender = FEMALE
mob_biotypes = MOB_ORGANIC|MOB_BEAST
speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
speak_emote = list("cheeps")
emote_hear = list("cheeps.")
emote_see = list("pecks at the ground.","flaps its tiny wings.")
density = FALSE
speak_chance = 2
turns_per_move = 2
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
attacktext = "kicks"
health = 3
maxHealth = 3
ventcrawler = VENTCRAWLER_ALWAYS
var/amount_grown = 0
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
mob_size = MOB_SIZE_TINY
gold_core_spawnable = FRIENDLY_SPAWN
do_footstep = TRUE
/mob/living/simple_animal/chick/Initialize()
. = ..()
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
/mob/living/simple_animal/chick/Life()
. =..()
if(!.)
return
if(!stat && !ckey)
amount_grown += rand(1,2)
if(amount_grown >= 100)
new /mob/living/simple_animal/chicken(src.loc)
qdel(src)
/mob/living/simple_animal/chick/holo/Life()
..()
amount_grown = 0
/mob/living/simple_animal/chicken
icon = 'hyperstation/icons/mob/chickens.dmi'
name = "\improper chicken"
desc = "Hopefully the eggs are good this season."
gender = FEMALE
mob_biotypes = MOB_ORGANIC|MOB_BEAST
icon_state = "chicken_brown"
icon_living = "chicken_brown"
icon_dead = "chicken_brown_dead"
speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
speak_emote = list("clucks","croons")
emote_hear = list("clucks.")
emote_see = list("pecks at the ground.","flaps its wings viciously.")
density = FALSE
speak_chance = 2
turns_per_move = 3
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
var/egg_type = /obj/item/reagent_containers/food/snacks/egg
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 = 15
maxHealth = 15
ventcrawler = VENTCRAWLER_ALWAYS
var/eggsleft = 0
var/eggsFertile = FALSE
var/body_color
var/icon_prefix = "chicken"
pass_flags = PASSTABLE | PASSMOB
mob_size = MOB_SIZE_SMALL
var/list/feedMessages = list("It clucks happily.","It clucks happily.")
var/list/layMessage = EGG_LAYING_MESSAGES
var/list/validColors = list("brown","black","white")
gold_core_spawnable = FRIENDLY_SPAWN
var/static/chicken_count = 0
var/partner //for the sex.
var/egglay_timer = 0
var/obj/structure/nestbox/nest_target
var/last_egg
var/force_gender //for map loading
do_footstep = TRUE
/mob/living/simple_animal/chicken/Initialize()
. = ..()
if((prob(30) && !force_gender) || force_gender == "male") //30% of a male. or setup if already male.
gender = MALE
name = "rooster"
if(!body_color)
body_color = pick(validColors)
icon_state = "[icon_prefix]_[body_color]"
icon_living = "[icon_prefix]_[body_color]"
icon_dead = "[icon_prefix]_[body_color]_dead"
pixel_x = rand(-6, 6)
pixel_y = rand(0, 10)
++chicken_count
/mob/living/simple_animal/chicken/Destroy()
--chicken_count
return ..()
/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
if(istype(O, food_type)) //feedin' dem chickens
if(!stat && eggsleft < 2)
var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
user.visible_message(feedmsg)
qdel(O)
eggsleft += 1
egglay_timer = 0
else
to_chat(user, "<span class='warning'>[name] doesn't seem hungry!</span>")
else
..()
/mob/living/simple_animal/chicken/Life()
. = ..()
if(!.)
return
if (istype(get_turf(src), /turf/open/floor))
var/turf/open/floor/turfon = get_turf(src)
if (turfon.farm_quality > happiness)
happiness ++
if (prob(5))
visible_message("[src] pecks happily at the ground.") //CLUCK CLUCK CLUCK
else
happiness --
else
happiness --
happiness = clamp(happiness,0,100) //clamp
if (!(gender == FEMALE)) //only females lay eggs and do the rest of the code.
return
//Breeding.
if (gender == FEMALE && eggsFertile == 0 && eggsleft > 0)
for(var/mob/living/simple_animal/chicken/C in view(2,src)) //look for a male near them, or on them.
if(C)
if(C.gender == MALE) //rooster
eggsFertile = 1 //they had sex, just go with it.
partner = C //you know who the partner is.
//EEGGGG TIME
//after 10mins, lay a egg regardless.
if(world.time > (last_egg+600 SECONDS) && !eggsleft)
if(prob(15)) //just to offset
eggsleft ++
last_egg = world.time
if((!stat && eggsleft > 0) && egg_type)
egglay_timer ++
else
egglay_timer = 0
//chance to lay egg on their own.
//look for nest!
//We have found a nest, override movement
if(nest_target) //if alive and we have a target.
stop_automated_movement = 1
walk_to(src,nest_target,0,8)
else
stop_automated_movement = 0
walk_to(src,0) //reset walk_to
if (egglay_timer > 10 && !stat) //time to lay a egg and not dead.
if((!stat && eggsleft > 0) && egg_type)
if (!nest_target)
for(var/obj/structure/nestbox/N in view(3,src)) // look for a eggbox if you dont have one already
nest_target = N
break
//We are at the nest we have chosen.
if (nest_target)
for(var/obj/structure/nestbox/B in get_turf(src))
if((prob(25) && eggsleft > 0) && egg_type)
visible_message("<span class='alertalien'>[src] [pick(layMessage)]</span>")
eggsleft--
var/obj/item/E = new egg_type(get_turf(src))
E.pixel_x = rand(-6,6)
E.pixel_y = rand(-6,6)
egglay_timer = 0 //set timer
nest_target = null //layed the egg, time to move on
if(eggsFertile && partner)
if(chicken_count < MAX_CHICKENS && prob(happiness))
START_PROCESSING(SSobj, E)
eggsFertile = 0 //youve layed your fertile egg.
E.name = "fertile egg"
partner = null
last_egg = world.time
break
/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
/obj/item/reagent_containers/food/snacks/egg/process()
if(isturf(loc))
for(var/obj/structure/nestbox/B in get_turf(src)) //can only hatch in a nestbox or incubator
amount_grown += rand(1,2)
if(amount_grown >= 100)
visible_message("[src] hatches with a quiet cracking sound.")
new /mob/living/simple_animal/chick(get_turf(src))
STOP_PROCESSING(SSobj, src)
qdel(src)
break
else
STOP_PROCESSING(SSobj, src)
/mob/living/simple_animal/chicken/examine()
. = ..()
. += "this one is [gender]."
if(happiness<20)
. += "<span class='warning'>It looks stressed.</span>"
@@ -27,3 +27,7 @@ mob/proc/checkloadappearance()
else
to_chat(H, "<span class='boldannounce'>You either took too long or chose not to change. Alrighty. Remember, you have 90 seconds from spawn to get to a mirror and still do it if you wish.</span>")
return
// oracle port
/mob/proc/has_mouth()
return FALSE
@@ -0,0 +1,11 @@
//Hope you're not a Russian T-90
/datum/reagent/consumable/ethanol/javelin
name = "Javelin Cocktail"
boozepwr = 80
color = "#F54F10"
quality = DRINK_FANTASTIC
taste_description = "explosive fireballs"
glass_icon_state = "javelin"
shot_glass_icon_state = "javelin_warhead"
glass_name = "Javelin Cocktail"
glass_desc = "A man-portable, delicious glass of justice."
@@ -21,3 +21,13 @@
if(holder.has_reagent(/datum/reagent/consumable/capsaicin))
holder.remove_reagent(/datum/reagent/consumable/capsaicin, 1)
..()
/datum/reagent/consumable/kalynajuice
name = "Red Kalyna Juice"
description = "Juice from Kalyna plants."
color = "#E90501" // rgb: 233, 5, 1
taste_description = "sweet cranberries"
glass_icon_state = "kalyna"
glass_name = "glass of red kalyna juice"
glass_desc = "A vibrantly red juice!"
hydration = 4
@@ -0,0 +1,69 @@
/datum/design/ipc_liver
name = "IPC Reagent Processor"
id = "ipc_liver"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
build_path = /obj/item/organ/liver/ipc
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/design/ipc_eyes
name = "IPC Eyes"
id = "ipc_eyes"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_GLASS = 2000)
build_path = /obj/item/organ/eyes/ipc
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/design/ipc_tongue
name = "Positronic Voicebox"
id = "ipc_tongue"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
build_path = /obj/item/organ/tongue/robot/ipc
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/design/ipc_stomach
name = "Micro-cell"
id = "ipc_stomach"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000, MAT_PLASMA = 200)
build_path = /obj/item/organ/stomach/cell
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/design/synthliz_stomach
name = "Synthetic Lizardperson Stomach"
id = "synthliz_stomach"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
build_path = /obj/item/organ/stomach/synthliz
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/design/power_cord
name = "IPC Power Cord"
id = "power_cord"
build_type = PROTOLATHE
materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
build_path = /obj/item/organ/cyberimp/arm/power_cord
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
construction_time = 100
/datum/techweb_node/ipc_organs
id = "ipc_organs"
display_name = "IPC Parts"
description = "We have the technology to replace him."
prereq_ids = list("cyber_organs","robotics")
design_ids = list("ipc_liver", "ipc_eyes", "ipc_tongue", "ipc_stomach", "synthliz_stomach", "power_cord")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
export_price = 5000
@@ -12,6 +12,7 @@ var/const/RESIZE_MICRO = 0.25
/mob/living
var/size_multiplier = 1 //multiplier for the mob's icon size atm
var/previous_size = 1
var/small_speech = FALSE
//Cyanosis - Action that resizes the sprite for the client but nobody else. Say goodbye to attacking yourself when someone's above you lmao
var/datum/action/sizecode_resize/small_sprite
@@ -237,8 +238,14 @@ mob/living/get_effective_size()
//Proc for changing mob_size to be grabbed for item weight classes
/mob/living/proc/update_mobsize(var/mob/living/tmob)
if(small_speech == TRUE) //if they have small speech reset it.
small_speech = FALSE
UnregisterSignal(src, COMSIG_MOB_SAY)
if(size_multiplier <= 0.50)
mob_size = 0
RegisterSignal(src, COMSIG_MOB_SAY, .proc/handle_small_speech)
small_speech = TRUE
if(size_multiplier < 1)
mob_size = 1
if(size_multiplier == 1)
@@ -246,6 +253,9 @@ mob/living/get_effective_size()
if(size_multiplier > 1)
mob_size = 3
/mob/living/proc/handle_small_speech(owner, list/speech_args) //for making peoples text small
speech_args[SPEECH_SPANS] |= SPAN_SMALL
//Proc for instantly grabbing valid size difference. Code optimizations soon(TM)
/*
/mob/living/proc/sizeinteractioncheck(var/mob/living/tmob)
@@ -23,3 +23,11 @@
w_class = WEIGHT_CLASS_BULKY
sharpness = IS_SHARP_ACCURATE
attack_verb = list("slashed", "cut")
// oracle port
/obj/item/organ/cyberimp/arm/power_cord
name = "power cord implant"
desc = "An internal power cord hooked up to a battery. Useful if you run on volts."
contents = newlist(/obj/item/apc_powercord)
zone = "l_arm"