diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index 4ed099d9e2..59790df5f5 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -122,3 +122,4 @@ #define ORGAN_SLOT_BRAIN_ANTISTUN "brain_antistun" #define ORGAN_SLOT_TAIL "tail" #define ORGAN_SLOT_PENIS "penis" +#define ORGAN_SLOT_BREASTS "breasts" \ No newline at end of file diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm index 3338fc1cda..8bcccbb02a 100644 --- a/code/__DEFINES/components.dm +++ b/code/__DEFINES/components.dm @@ -137,6 +137,9 @@ #define COMSIG_LIVING_EXTINGUISHED "living_extinguished" //from base of mob/living/ExtinguishMob() (/mob/living) #define COMSIG_LIVING_ELECTROCUTE_ACT "living_electrocute_act" //from base of mob/living/electrocute_act(): (shock_damage) #define COMSIG_LIVING_MINOR_SHOCK "living_minor_shock" //sent by stuff like stunbatons and tasers: () +#define COMSIG_LIVING_SAY "say" //mob/living/say() - return COMSIG_I_FORGET_WHAT_TO_CALL_IT to interrupt before message sent. + #define COMPONENT_NO_SAY 1 // Here I am pretending to know what I'm doing. + // /mob/living/carbon signals #define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity)) @@ -145,6 +148,7 @@ #define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled) #define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value) + // /obj/item signals #define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user) #define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob) diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 36049de77b..f91843a965 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -109,5 +109,6 @@ GLOBAL_LIST_INIT(maintenance_loot, list( /obj/item/reagent_containers/pill/floorpill = 1, /obj/item/storage/daki = 3, //VERY IMPORTANT CIT CHANGE - adds bodypillows to maint /obj/item/storage/pill_bottle/penis_enlargement = 2, + /obj/item/storage/pill_bottle/breast_enlargement = 2, "" = 3 )) diff --git a/code/controllers/subsystem/processing/chemistry.dm b/code/controllers/subsystem/processing/chemistry.dm new file mode 100644 index 0000000000..da31d65fb3 --- /dev/null +++ b/code/controllers/subsystem/processing/chemistry.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(chemistry) + wait = 5 + flags = SS_KEEP_TIMING + + diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm index 933c38505b..01162889fd 100644 --- a/code/datums/components/mood.dm +++ b/code/datums/components/mood.dm @@ -15,7 +15,7 @@ /datum/component/mood/Initialize() if(!isliving(parent)) return COMPONENT_INCOMPATIBLE - + START_PROCESSING(SSmood, src) RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/add_event) @@ -118,6 +118,8 @@ if(owner.client && owner.hud_used) if(sanity < 25) screen_obj.icon_state = "mood_insane" + else if (owner.has_status_effect(/datum/status_effect/chem/enthrall))//Fermichem enthral chem, maybe change? + screen_obj.icon_state = "mood_entrance" else screen_obj.icon_state = "mood[mood_level]" @@ -160,7 +162,7 @@ clear_event(null, "depression") holdmyinsanityeffect = insanity_effect - + HandleNutrition(owner) /datum/component/mood/proc/DecreaseSanity(amount, minimum = SANITY_INSANE) diff --git a/code/datums/mood_events/drug_events.dm b/code/datums/mood_events/drug_events.dm index 40c239180e..6ed33b0f00 100644 --- a/code/datums/mood_events/drug_events.dm +++ b/code/datums/mood_events/drug_events.dm @@ -37,3 +37,19 @@ /datum/mood_event/withdrawal_critical/add_effects(drug_name) description = "[drug_name]! [drug_name]! [drug_name]!\n" + +/datum/mood_event/happiness_drug + description = "I can't feel anything and I never want this to end.\n" + mood_change = 50 + +/datum/mood_event/happiness_drug_good_od + description = "YES! YES!! YES!!!\n" + mood_change = 100 + timeout = 300 + special_screen_obj = "mood_happiness_good" + +/datum/mood_event/happiness_drug_bad_od + description = "NO! NO!! NO!!!\n" + mood_change = -100 + timeout = 300 + special_screen_obj = "mood_happiness_bad" diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index 1a666ce921..e6c370b097 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -1,322 +1,330 @@ -/* First aid storage - * Contains: - * First Aid Kits - * Pill Bottles - * Dice Pack (in a pill bottle) - */ - -/* - * First Aid Kits - */ -/obj/item/storage/firstaid - name = "first-aid kit" - desc = "It's an emergency medical kit for those serious boo-boos." - icon_state = "firstaid" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - throw_speed = 3 - throw_range = 7 - var/empty = FALSE - -/obj/item/storage/firstaid/regular - icon_state = "firstaid" - desc = "A first aid kit with the ability to heal common types of injuries." - -/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS - -/obj/item/storage/firstaid/regular/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/ancient - icon_state = "firstaid" - desc = "A first aid kit with the ability to heal common types of injuries." - -/obj/item/storage/firstaid/ancient/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/bruise_pack(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - new /obj/item/stack/medical/ointment(src) - -/obj/item/storage/firstaid/fire - name = "burn treatment kit" - desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down." - icon_state = "ointment" - item_state = "firstaid-ointment" - -/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!") - return FIRELOSS - -/obj/item/storage/firstaid/fire/Initialize(mapload) - . = ..() - icon_state = pick("ointment","firefirstaid") - -/obj/item/storage/firstaid/fire/PopulateContents() - if(empty) - return - for(var/i in 1 to 3) - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - new /obj/item/reagent_containers/pill/oxandrolone(src) - new /obj/item/reagent_containers/pill/oxandrolone(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/toxin - name = "toxin treatment kit" - desc = "Used to treat toxic blood content and radiation poisoning." - icon_state = "antitoxin" - item_state = "firstaid-toxin" - -/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return TOXLOSS - -/obj/item/storage/firstaid/toxin/Initialize(mapload) - . = ..() - icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") - -/obj/item/storage/firstaid/toxin/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/syringe/charcoal(src) - for(var/i in 1 to 2) - new /obj/item/storage/pill_bottle/charcoal(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/radbgone - name = "radiation treatment kit" - desc = "Used to treat minor toxic blood content and major radiation poisoning." - icon_state = "antitoxin" - item_state = "firstaid-toxin" - -/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return TOXLOSS - -/obj/item/storage/firstaid/radbgone/PopulateContents() - if(empty) - return - if(prob(50)) - new /obj/item/reagent_containers/pill/mutarad(src) - if(prob(80)) - new /obj/item/reagent_containers/pill/antirad_plus(src) - new /obj/item/reagent_containers/syringe/charcoal(src) - new /obj/item/storage/pill_bottle/charcoal(src) - new /obj/item/reagent_containers/pill/mutadone(src) - new /obj/item/reagent_containers/pill/antirad(src) - new /obj/item/reagent_containers/food/drinks/bottle/vodka(src) - new /obj/item/healthanalyzer(src) - - -/obj/item/storage/firstaid/o2 - name = "oxygen deprivation treatment kit" - desc = "A box full of oxygen goodies." - icon_state = "o2" - item_state = "firstaid-o2" - -/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return OXYLOSS - -/obj/item/storage/firstaid/o2/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/pill/salbutamol(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/reagent_containers/hypospray/medipen(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/brute - name = "brute trauma treatment kit" - desc = "A first aid kit for when you get toolboxed." - icon_state = "brute" - item_state = "firstaid-brute" - -/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user) - user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS - -/obj/item/storage/firstaid/brute/PopulateContents() - if(empty) - return - for(var/i in 1 to 4) - new /obj/item/reagent_containers/pill/patch/styptic(src) - new /obj/item/stack/medical/gauze(src) - new /obj/item/stack/medical/gauze(src) - new /obj/item/healthanalyzer(src) - -/obj/item/storage/firstaid/tactical - name = "combat medical kit" - desc = "I hope you've got insurance." - icon_state = "bezerk" - -/obj/item/storage/firstaid/tactical/ComponentInitialize() - . = ..() - GET_COMPONENT(STR, /datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_NORMAL - -/obj/item/storage/firstaid/tactical/PopulateContents() - if(empty) - return - new /obj/item/stack/medical/gauze(src) - new /obj/item/defibrillator/compact/combat/loaded(src) - new /obj/item/reagent_containers/hypospray/combat(src) - new /obj/item/reagent_containers/pill/patch/styptic(src) - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - new /obj/item/reagent_containers/syringe/lethal/choral(src) - new /obj/item/clothing/glasses/hud/health/night(src) - -/* - * Pill Bottles - */ - -/obj/item/storage/pill_bottle - name = "pill bottle" - desc = "It's an airtight container for storing medication." - icon_state = "pill_canister" - icon = 'icons/obj/chemical.dmi' - item_state = "contsolid" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - w_class = WEIGHT_CLASS_SMALL - -/obj/item/storage/pill_bottle/ComponentInitialize() - . = ..() - GET_COMPONENT(STR, /datum/component/storage) - STR.allow_quick_gather = TRUE - STR.click_gather = TRUE - STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice)) - -/obj/item/storage/pill_bottle/suicide_act(mob/user) - user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!") - return (TOXLOSS) - -/obj/item/storage/pill_bottle/charcoal - name = "bottle of charcoal pills" - desc = "Contains pills used to counter toxins." - -/obj/item/storage/pill_bottle/charcoal/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/charcoal(src) - -/obj/item/storage/pill_bottle/antirad - name = "bottle of charcoal pills" - desc = "Contains pills used to counter radiation poisoning." - -/obj/item/storage/pill_bottle/anitrad/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/antirad(src) - -/obj/item/storage/pill_bottle/epinephrine - name = "bottle of epinephrine pills" - desc = "Contains pills used to stabilize patients." - -/obj/item/storage/pill_bottle/epinephrine/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/epinephrine(src) - -/obj/item/storage/pill_bottle/mutadone - name = "bottle of mutadone pills" - desc = "Contains pills used to treat genetic abnormalities." - -/obj/item/storage/pill_bottle/mutadone/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mutadone(src) - -/obj/item/storage/pill_bottle/mannitol - name = "bottle of mannitol pills" - desc = "Contains pills used to treat brain damage." - -/obj/item/storage/pill_bottle/mannitol/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mannitol(src) - -/obj/item/storage/pill_bottle/stimulant - name = "bottle of stimulant pills" - desc = "Guaranteed to give you that extra burst of energy during a long shift!" - -/obj/item/storage/pill_bottle/stimulant/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/stimulant(src) - -/obj/item/storage/pill_bottle/mining - name = "bottle of patches" - desc = "Contains patches used to treat brute and burn damage." - -/obj/item/storage/pill_bottle/mining/PopulateContents() - new /obj/item/reagent_containers/pill/patch/silver_sulf(src) - for(var/i in 1 to 3) - new /obj/item/reagent_containers/pill/patch/styptic(src) - -/obj/item/storage/pill_bottle/zoom - name = "suspicious pill bottle" - desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds." - -/obj/item/storage/pill_bottle/zoom/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/zoom(src) - -/obj/item/storage/pill_bottle/happy - name = "suspicious pill bottle" - desc = "There is a smiley on the top." - -/obj/item/storage/pill_bottle/happy/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/happy(src) - -/obj/item/storage/pill_bottle/lsd - name = "suspicious pill bottle" - desc = "There is a badly drawn thing with the shape of a mushroom." - -/obj/item/storage/pill_bottle/lsd/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/lsd(src) - -/obj/item/storage/pill_bottle/aranesp - name = "suspicious pill bottle" - desc = "The label says 'gotta go fast'." - -/obj/item/storage/pill_bottle/aranesp/PopulateContents() - for(var/i in 1 to 5) - new /obj/item/reagent_containers/pill/aranesp(src) - -/obj/item/storage/pill_bottle/antirad_plus - name = "anti radiation deluxe pill bottle" - desc = "The label says 'Med-Co branded pills'." - -/obj/item/storage/pill_bottle/antirad_plus/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/antirad_plus(src) - -/obj/item/storage/pill_bottle/mutarad - name = "radiation treatment deluxe pill bottle" - desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`." - -/obj/item/storage/pill_bottle/mutarad/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/mutarad(src) - -/obj/item/storage/pill_bottle/penis_enlargement - name = "penis enlargement pills" - desc = "You want penis enlargement pills?" - -/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents() - for(var/i in 1 to 7) - new /obj/item/reagent_containers/pill/penis_enlargement(src) +/* First aid storage + * Contains: + * First Aid Kits + * Pill Bottles + * Dice Pack (in a pill bottle) + */ + +/* + * First Aid Kits + */ +/obj/item/storage/firstaid + name = "first-aid kit" + desc = "It's an emergency medical kit for those serious boo-boos." + icon_state = "firstaid" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + throw_speed = 3 + throw_range = 7 + var/empty = FALSE + +/obj/item/storage/firstaid/regular + icon_state = "firstaid" + desc = "A first aid kit with the ability to heal common types of injuries." + +/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/storage/firstaid/regular/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/ancient + icon_state = "firstaid" + desc = "A first aid kit with the ability to heal common types of injuries." + +/obj/item/storage/firstaid/ancient/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/bruise_pack(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + new /obj/item/stack/medical/ointment(src) + +/obj/item/storage/firstaid/fire + name = "burn treatment kit" + desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down." + icon_state = "ointment" + item_state = "firstaid-ointment" + +/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!") + return FIRELOSS + +/obj/item/storage/firstaid/fire/Initialize(mapload) + . = ..() + icon_state = pick("ointment","firefirstaid") + +/obj/item/storage/firstaid/fire/PopulateContents() + if(empty) + return + for(var/i in 1 to 3) + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + new /obj/item/reagent_containers/pill/oxandrolone(src) + new /obj/item/reagent_containers/pill/oxandrolone(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/toxin + name = "toxin treatment kit" + desc = "Used to treat toxic blood content and radiation poisoning." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return TOXLOSS + +/obj/item/storage/firstaid/toxin/Initialize(mapload) + . = ..() + icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3") + +/obj/item/storage/firstaid/toxin/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/syringe/charcoal(src) + for(var/i in 1 to 2) + new /obj/item/storage/pill_bottle/charcoal(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/radbgone + name = "radiation treatment kit" + desc = "Used to treat minor toxic blood content and major radiation poisoning." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return TOXLOSS + +/obj/item/storage/firstaid/radbgone/PopulateContents() + if(empty) + return + if(prob(50)) + new /obj/item/reagent_containers/pill/mutarad(src) + if(prob(80)) + new /obj/item/reagent_containers/pill/antirad_plus(src) + new /obj/item/reagent_containers/syringe/charcoal(src) + new /obj/item/storage/pill_bottle/charcoal(src) + new /obj/item/reagent_containers/pill/mutadone(src) + new /obj/item/reagent_containers/pill/antirad(src) + new /obj/item/reagent_containers/food/drinks/bottle/vodka(src) + new /obj/item/healthanalyzer(src) + + +/obj/item/storage/firstaid/o2 + name = "oxygen deprivation treatment kit" + desc = "A box full of oxygen goodies." + icon_state = "o2" + item_state = "firstaid-o2" + +/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return OXYLOSS + +/obj/item/storage/firstaid/o2/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/pill/salbutamol(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/reagent_containers/hypospray/medipen(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/brute + name = "brute trauma treatment kit" + desc = "A first aid kit for when you get toolboxed." + icon_state = "brute" + item_state = "firstaid-brute" + +/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/storage/firstaid/brute/PopulateContents() + if(empty) + return + for(var/i in 1 to 4) + new /obj/item/reagent_containers/pill/patch/styptic(src) + new /obj/item/stack/medical/gauze(src) + new /obj/item/stack/medical/gauze(src) + new /obj/item/healthanalyzer(src) + +/obj/item/storage/firstaid/tactical + name = "combat medical kit" + desc = "I hope you've got insurance." + icon_state = "bezerk" + +/obj/item/storage/firstaid/tactical/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + +/obj/item/storage/firstaid/tactical/PopulateContents() + if(empty) + return + new /obj/item/stack/medical/gauze(src) + new /obj/item/defibrillator/compact/combat/loaded(src) + new /obj/item/reagent_containers/hypospray/combat(src) + new /obj/item/reagent_containers/pill/patch/styptic(src) + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + new /obj/item/reagent_containers/syringe/lethal/choral(src) + new /obj/item/clothing/glasses/hud/health/night(src) + +/* + * Pill Bottles + */ + +/obj/item/storage/pill_bottle + name = "pill bottle" + desc = "It's an airtight container for storing medication." + icon_state = "pill_canister" + icon = 'icons/obj/chemical.dmi' + item_state = "contsolid" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/pill_bottle/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.allow_quick_gather = TRUE + STR.click_gather = TRUE + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice)) + +/obj/item/storage/pill_bottle/suicide_act(mob/user) + user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return (TOXLOSS) + +/obj/item/storage/pill_bottle/charcoal + name = "bottle of charcoal pills" + desc = "Contains pills used to counter toxins." + +/obj/item/storage/pill_bottle/charcoal/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/charcoal(src) + +/obj/item/storage/pill_bottle/antirad + name = "bottle of charcoal pills" + desc = "Contains pills used to counter radiation poisoning." + +/obj/item/storage/pill_bottle/anitrad/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/antirad(src) + +/obj/item/storage/pill_bottle/epinephrine + name = "bottle of epinephrine pills" + desc = "Contains pills used to stabilize patients." + +/obj/item/storage/pill_bottle/epinephrine/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/epinephrine(src) + +/obj/item/storage/pill_bottle/mutadone + name = "bottle of mutadone pills" + desc = "Contains pills used to treat genetic abnormalities." + +/obj/item/storage/pill_bottle/mutadone/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mutadone(src) + +/obj/item/storage/pill_bottle/mannitol + name = "bottle of mannitol pills" + desc = "Contains pills used to treat brain damage." + +/obj/item/storage/pill_bottle/mannitol/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mannitol(src) + +/obj/item/storage/pill_bottle/stimulant + name = "bottle of stimulant pills" + desc = "Guaranteed to give you that extra burst of energy during a long shift!" + +/obj/item/storage/pill_bottle/stimulant/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/stimulant(src) + +/obj/item/storage/pill_bottle/mining + name = "bottle of patches" + desc = "Contains patches used to treat brute and burn damage." + +/obj/item/storage/pill_bottle/mining/PopulateContents() + new /obj/item/reagent_containers/pill/patch/silver_sulf(src) + for(var/i in 1 to 3) + new /obj/item/reagent_containers/pill/patch/styptic(src) + +/obj/item/storage/pill_bottle/zoom + name = "suspicious pill bottle" + desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds." + +/obj/item/storage/pill_bottle/zoom/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/zoom(src) + +/obj/item/storage/pill_bottle/happy + name = "suspicious pill bottle" + desc = "There is a smiley on the top." + +/obj/item/storage/pill_bottle/happy/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/happy(src) + +/obj/item/storage/pill_bottle/lsd + name = "suspicious pill bottle" + desc = "There is a badly drawn thing with the shape of a mushroom." + +/obj/item/storage/pill_bottle/lsd/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/lsd(src) + +/obj/item/storage/pill_bottle/aranesp + name = "suspicious pill bottle" + desc = "The label says 'gotta go fast'." + +/obj/item/storage/pill_bottle/aranesp/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/aranesp(src) + +/obj/item/storage/pill_bottle/antirad_plus + name = "anti radiation deluxe pill bottle" + desc = "The label says 'Med-Co branded pills'." + +/obj/item/storage/pill_bottle/antirad_plus/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/antirad_plus(src) + +/obj/item/storage/pill_bottle/mutarad + name = "radiation treatment deluxe pill bottle" + desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`." + +/obj/item/storage/pill_bottle/mutarad/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/mutarad(src) + +/obj/item/storage/pill_bottle/penis_enlargement + name = "penis enlargement pills" + desc = "Made by Fermichem - They have a little picture of Doctor Ronald Hyatt with a giant dong on them. The warming states not to take more than 10u at a time." + +/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/penis_enlargement(src) + +/obj/item/storage/pill_bottle/breast_enlargement + name = "breast enlargement pills" + desc = "Made by Fermichem - They have a woman with breasts larger than she is on them. The warming states not to take more than 10u at a time." + +/obj/item/storage/pill_bottle/breast_enlargement/PopulateContents() + for(var/i in 1 to 7) + new /obj/item/reagent_containers/pill/breast_enlargement(src) diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index fb14cab18f..c51c318e3e 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -53,10 +53,6 @@ var/addiction_tick = 1 var/list/datum/reagent/addiction_list = new/list() var/reagents_holder_flags - var/targetVol = 0 - var/reactedVol = 0 - var/fermiIsReacting = FALSE - var/fermiReactID = null /datum/reagents/New(maximum=100) maximum_volume = maximum @@ -341,361 +337,205 @@ R.on_update (A) update_total() -/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar - if(fermiIsReacting == TRUE) - //reagents_holder_flags |= REAGENT_NOREACT unsure if this is needed - return - var/list/cached_reagents = reagent_list //a list of the reagents? - var/list/cached_reactions = GLOB.chemical_reactions_list //a list of the whole reactions? - var/datum/cached_my_atom = my_atom //It says my atom, but I didn't bring one with me!! - if(reagents_holder_flags & REAGENT_NOREACT) //Not sure on reagents_holder_flags, but I think it checks to see if theres a reaction with current stuff. - return //Yup, no reactions here. No siree. +/datum/reagents/process() + var/occured = handle_reactions(TRUE) + if(!occured) + return PROCESS_KILL - var/reaction_occurred = 0 // checks if reaction, binary variable - var/continue_reacting = FALSE //Helps keep track what kind of reaction is occuring; standard or fermi. - - //if(fermiIsReacting == TRUE) - /* if (reactedVol >= targetVol && targetVol != 0) - STOP_PROCESSING(SSprocessing, src) - fermiIsReacting = FALSE - message_admins("FermiChem processing stopped in reaction handler") - reaction_occurred = 1 - return - else - message_admins("FermiChem processing passed in reaction handler") - return - */ - - - do //What does do do in byond? It sounds very redundant? is it a while loop? - var/list/possible_reactions = list() //init list - reaction_occurred = 0 // sets it back to 0? - for(var/reagent in cached_reagents) //for reagent in beaker/holder - var/datum/reagent/R = reagent //check to make sure that reagent is there for the reaction list - for(var/reaction in cached_reactions[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id +/datum/reagents/proc/handle_reactions(fermi_chem_react = FALSE)//HERE EDIT HERE THE MAIN REACTION FERMICHEMS ASSEMBLE! I hope rp is similar + return + if(reagents_holder_flags & REAGENT_NOREACT) + return //don't react + //cache things for performance + var/list/cached_reagents = reagent_list + var/list/cached_reactions = GLOB.chemical_reactions_list + var/datum/cached_my_atom = my_atom + var/reaction_occurred //if a reaction happened + var/list/fermichem_reacted //keeps track of fermichem reactions that already reacted to prevent it from being instant + do + var/list/possible_reactions + reaction_occurred = FALSE + for(var/reagent in cached_reagents) + var/datum/reagent/R = reagent + for(var/reaction in cached_reactions[R.id]) if(!reaction) continue - var/datum/chemical_reaction/C = reaction var/list/cached_required_reagents = C.required_reagents - var/total_required_reagents = cached_required_reagents.len - var/total_matching_reagents = 0 var/list/cached_required_catalysts = C.required_catalysts - var/total_required_catalysts = cached_required_catalysts.len - var/total_matching_catalysts= 0 - var/matching_container = 0 - var/matching_other = 0 var/required_temp = C.required_temp var/is_cold_recipe = C.is_cold_recipe - var/meets_temp_requirement = 0 var/has_special_react = C.special_react - var/can_special_react = 0 - - + var/fail = FALSE for(var/B in cached_required_reagents) if(!has_reagent(B, cached_required_reagents[B])) + fail = TRUE break - total_matching_reagents++ + if(fail) + continue for(var/B in cached_required_catalysts) if(!has_reagent(B, cached_required_catalysts[B])) + fail = TRUE break - total_matching_catalysts++ + if(fail) + continue if(cached_my_atom) - if(!C.required_container) - matching_container = 1 - - else - if(cached_my_atom.type == C.required_container)//if the suspected container is a container - matching_container = 1 + if(C.required_container && C.required_container != cached_my_atom.type) + continue if (isliving(cached_my_atom) && !C.mob_react) //Makes it so certain chemical reactions don't occur in mobs - return - if(!C.required_other)//Checks for other things required - matching_other = 1//binary check passes - - else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem - var/obj/item/slime_extract/M = cached_my_atom - - if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this - matching_other = 1 + continue + if(C.required_other) //Checks for other things required + if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract. This might be complicated as to not break them via fermichem + var/obj/item/slime_extract/M = cached_my_atom + if(M.Uses <= 0) // added a limit to slime cores -- Muskets requested this + continue else - if(!C.required_container)//I'm not sure why this is here twice, I think if it's not a beaker? Oh, cyro. - matching_container = 1 - if(!C.required_other) - matching_other = 1 - - //FermiChem - /* - if (chem_temp > C.ExplodeTemp)//Check to see if reaction is too hot! - if (C.FermiExplode == TRUE) - //To be added! - else - FermiExplode() - //explode function!! - */ - - if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!! - meets_temp_requirement = 1//binary pass - - if(!has_special_react || C.check_special_react(src)) - can_special_react = 1 - - if(total_matching_reagents == total_required_reagents && total_matching_catalysts == total_required_catalysts && matching_container && matching_other && meets_temp_requirement && can_special_react) - possible_reactions += C - - if(possible_reactions.len)//does list exist? + if(C.required_container || C.required_other) + continue + if(required_temp && (is_cold_recipe? (chem_temp > required_temp) : (chem_temp < required_temp))) + continue + if(has_special_react && !C.check_special_react(src)) + continue + if(C.FermiChem) //fermichem checks + if(chem_temp < C.OptimalTempMin) //too low temperature + continue + if(LAZYACCESS(fermichem_reacted, C)) //fermichems don't keep reacting instantly + continue + START_PROCESSING(SSchemistry, src) //start processing + if(!fermi_chem_react) //only react fermichems on process icks + continue + LAZYADD(possible_reactions, C) + if(length(possible_reactions)) //does list exist? var/datum/chemical_reaction/selected_reaction = possible_reactions[1] - //select the reaction with the most extreme temperature requirements - for(var/V in possible_reactions)//why V, surely that would indicate volume? V is the reaction potential. - var/datum/chemical_reaction/competitor = V //competitor? I think this is theres two of them. Troubling..! - if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met. - if(competitor.required_temp <= selected_reaction.required_temp)//only returns with lower if reaction "is cold" var. - selected_reaction = competitor - else - if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first. - selected_reaction = competitor + for(var/I in possible_reactions) + var/datum/chemical_reaction/competitor = I + if(selected_reaction.is_cold_recipe? competitor.required_temp < selected_reaction.required_temp : competitor.required_temp > selected_reaction.required_temp) + selected_reaction = competitor var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list var/list/cached_results = selected_reaction.results//resultant chemical list - var/special_react_result = selected_reaction.check_special_react(src) - var/list/multiplier = INFINITY //Wat - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - + var/special_react_result = selected_reaction.special_react //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction. //FermiChem relies on two additional properties; pH and impurity //Temperature plays into a larger role too. //BRANCH HERE - //if(selected_reaction) - var/datum/chemical_reaction/C = selected_reaction - - if (C.FermiChem == TRUE && !continue_reacting) - message_admins("FermiChem Proc'd") - - for(var/P in selected_reaction.results) - targetVol = cached_results[P]*multiplier - message_admins("FermiChem target volume: [targetVol]") - - if (chem_temp > C.OptimalTempMin)//To prevent pointless reactions - //if (reactedVol < targetVol) - if (fermiIsReacting == TRUE) - return 0 - else - //reactedVol = FermiReact(selected_reaction, chem_temp, pH, multiplier, reactedVol, targetVol, cached_required_reagents, cached_results) - START_PROCESSING(SSprocessing, src) - message_admins("FermiChem processing started") - fermiIsReacting = TRUE - fermiReactID = selected_reaction - reaction_occurred = 1 - //else - // fermiIsReacting = FALSE - // STOP_PROCESSING(SSfastprocess, src) - else - return 0 - - - SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", reactedVol, C.id)//log - - //Standard reaction mechanics: - else - - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - + var/multiplier = INFINITY //the multiplier of the stnadard "1 reaction" we managed to do this cycle + if(!selected_reaction.FermiChem) //it's a normal ss13 chem reaction, instant reactions. for(var/B in cached_required_reagents) - remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in selected_reaction.results)//Not sure how this works, what is selected_reaction.results? + multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B])) //cap by the multiplier of the required you can get out of this + //remove reactants + for(var/B in cached_required_reagents) + remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = TRUE) + //add products + for(var/P in cached_results) multiplier = max(multiplier, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log - add_reagent(P, cached_results[P]*multiplier, null, chem_temp)//add reagent function!! I THINK I can do this: + SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P] * multiplier, P) + add_reagent(P, cached_results[P]*multiplier, null, chem_temp) + else //FermiiiCheeeem! + //FERMICHEM BEGIN + //--CHECKS + message_admins("FermiChem Proc'd") + var/target_volume = 0 + for(var/result_id in cached_results) + target_volume += multiplier * cached_results[result_id] + message_admins("FermiChem target volume: [target_volume]") + //--PROCESS + message_admins("FermiChem processing started") + //--REACTION + //set up fermichem variables + var/deltaT = 0 + var/deltapH = 0 + var/stepChemAmount = 0 + var/purity = 1 + //For now, purity is handled elsewhere + //check extremes first + if(chem_temp > selected_reaction.ExplodeTemp) + FermiExplode(selected_reaction) + else if(!ISINRANGE(pH, 0, 14)) + //Create chemical sludge eventually(for now just destroy the beaker I guess?) + //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) + FermiExplode() + //Calculate DeltaT (Deviation of T from optimal) + if (chem_temp < selected_reaction.OptimalTempMax && chem_temp >= selected_reaction.OptimalTempMin) + deltaT = (((selected_reaction.OptimalTempMin - chem_temp)**selected_reaction.CurveSharpT)/((selected_reaction.OptimalTempMax - selected_reaction.OptimalTempMin)**selected_reaction.CurveSharpT)) + else if (chem_temp >= selected_reaction.OptimalTempMax) + deltaT = 1 + else + deltaT = 0 + message_admins("calculating temperature factor, min: [selected_reaction.OptimalTempMin], max: [selected_reaction.OptimalTempMax], Exponential: [selected_reaction.CurveSharpT], deltaT: [deltaT]") + //Calculate DeltapH (Deviation of pH from optimal) + //Lower range + if (pH < selected_reaction.OptimalpHMin) + if (pH < (selected_reaction.OptimalpHMin - selected_reaction.ReactpHLim)) + deltapH = 0 + else + deltapH = (((pH - (selected_reaction.OptimalpHMin - selected_reaction.ReactpHLim))**selected_reaction.CurveSharppH)/(selected_reaction.ReactpHLim**selected_reaction.CurveSharppH)) + //Upper range + else if (pH > selected_reaction.OptimalpHMin) + if (pH > (selected_reaction.OptimalpHMin + selected_reaction.ReactpHLim)) + deltapH = 0 + else + deltapH = ((selected_reaction.ReactpHLim -(pH - (selected_reaction.OptimalpHMax + selected_reaction.ReactpHLim))+selected_reaction.ReactpHLim)/(selected_reaction.ReactpHLim**selected_reaction.CurveSharppH)) + //Within mid range + else if (pH >= selected_reaction.OptimalpHMin && pH <= selected_reaction.OptimalpHMax) + deltapH = 1 + //This should never proc: + else + message_admins("Fermichem's pH broke!! Please let Fermis know!!") + WARNING("[my_atom] attempted to determine FermiChem pH for '[selected_reaction.id]' which broke for some reason! ([usr])") + //TODO Add CatalystFact + message_admins("calculating pH factor(purity), pH: [pH], min: [selected_reaction.OptimalpHMin]-[selected_reaction.ReactpHLim], max: [selected_reaction.OptimalpHMax]+[selected_reaction.ReactpHLim], deltapH: [deltapH]") + stepChemAmount = target_volume * deltaT + if (stepChemAmount > selected_reaction.RateUpLim) + stepChemAmount = selected_reaction.RateUpLim + else if (stepChemAmount <= 0.01) + message_admins("stepChem underflow [stepChemAmount]") + stepChemAmount = 0.02 + purity = deltapH + message_admins("cached_results: [cached_results], stepChemAmount [stepChemAmount]") + if(stepChemAmount > multiplier) //too much + message_admins("stepChemAmount was over multiplier for some reason..?") + for(var/B in cached_required_reagents) + message_admins("cached_required_reagents(B): [cached_required_reagents[B]], base stepChemAmount [stepChemAmount]") + remove_reagent(B, (stepChemAmount * cached_required_reagents[B]), safety = TRUE)//safety? removes reagents from beaker using remove function. + for(var/P in cached_results)//Not sure how this works, what is selected_reaction.results? + //reactedVol = max(reactedVol, 1) //this shouldnt happen ... + SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmount, P)//log + add_reagent(P, cached_results[P] * stepChemAmount, null, chem_temp)//add reagent function!! I THINK I can do this: + message_admins("purity: [purity], purity of beaker") + message_admins("Temp before change: [chem_temp], pH after change: [pH]") + //Apply pH changes and thermal output of reaction to beaker + chem_temp += (selected_reaction.ThermicConstant * stepChemAmount) + pH += (selected_reaction.HIonRelease * stepChemAmount) + message_admins("Temp after change: [chem_temp], pH after change: [pH]") + SSblackbox.record_feedback("tally", "Fermi_chemical_reaction", multiplier, selected_reaction.id)//log + //ensure the same thing doesn't happen in the same tick + LAZYSET(fermichem_reacted, selected_reaction, TRUE) + //FERMICHEM END + //reaction is done, do the effects. + var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers + var/iconhtml = icon2html(cached_my_atom, seen) + if(cached_my_atom) + if(!ismob(cached_my_atom)) // No bubbling mobs + if(selected_reaction.mix_sound) + playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1) - var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers - var/iconhtml = icon2html(cached_my_atom, seen) - if(cached_my_atom) - if(!ismob(cached_my_atom)) // No bubbling mobs - if(selected_reaction.mix_sound) - playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1) + for(var/mob/M in seen) + to_chat(M, "[iconhtml] [selected_reaction.mix_message]") + if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. + var/obj/item/slime_extract/ME2 = my_atom + ME2.Uses-- + if(ME2.Uses <= 0) // give the notification that the slime core is dead for(var/mob/M in seen) - to_chat(M, "[iconhtml] [selected_reaction.mix_message]") - - if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up. - var/obj/item/slime_extract/ME2 = my_atom - ME2.Uses-- - if(ME2.Uses <= 0) // give the notification that the slime core is dead - for(var/mob/M in seen) - to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") - ME2.name = "used slime extract" - ME2.desc = "This extract has been used up." - - selected_reaction.on_reaction(src, multiplier, special_react_result) - reaction_occurred = 1 - continue_reacting = TRUE - - while(reaction_occurred)//while do nothing? - update_total()//Don't know waht this does. - return 0//end! - -/datum/reagents/process() - var/datum/chemical_reaction/C = fermiReactID - var/list/cached_required_reagents = C.required_reagents//update reagents list - var/list/cached_results = C.results//resultant chemical list - var/multiplier = INFINITY - - message_admins("updating targetVol from [targetVol]") - for(var/B in cached_required_reagents) // - multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B])) - if (multiplier == 0) - STOP_PROCESSING(SSprocessing, src) - fermiIsReacting = FALSE - message_admins("FermiChem STOPPED due to reactant removal! Reacted vol: [reactedVol] of [targetVol]") - reactedVol = 0 - targetVol = 0 - handle_reactions() - update_total() - return - for(var/P in cached_results) - targetVol = cached_results[P]*multiplier - - message_admins("to [targetVol]") - - if (fermiIsReacting == FALSE) - message_admins("THIS SHOULD NEVER APPEAR!") - - if (chem_temp > C.OptimalTempMin && fermiIsReacting == TRUE)//To prevent pointless reactions - if (reactedVol < targetVol) - reactedVol = FermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results) - message_admins("FermiChem tick activated started, Reacted vol: [reactedVol] of [targetVol]") - else - STOP_PROCESSING(SSprocessing, src) - fermiIsReacting = FALSE - message_admins("FermiChem STOPPED due to volume reached! Reacted vol: [reactedVol] of [targetVol]") - reactedVol = 0 - targetVol = 0 - handle_reactions() - update_total() - return - else - STOP_PROCESSING(SSprocessing, src) - message_admins("FermiChem STOPPED due to temperature! Reacted vol: [reactedVol] of [targetVol]") - fermiIsReacting = FALSE - reactedVol = 0 - targetVol = 0 - handle_reactions() - update_total() - return - - //handle_reactions() - -/datum/reagents/proc/FermiReact(selected_reaction, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results) - var/datum/chemical_reaction/C = selected_reaction - var/deltaT = 0 - var/deltapH = 0 - var/stepChemAmmount = 0 - //var/ammoReacted = 0 - //get purity from combined beaker reactant purities HERE. - var/purity = 1 - //var/tempVol = totalVol - - message_admins("Loop beginning") - //Begin Parse - - //Check extremes first - if (chem_temp > C.ExplodeTemp) - //go to explode proc - message_admins("temperature is over limit: [C.ExplodeTemp] Current temperature: [chem_temp]") - FermiExplode() - - if (pH > 14 || pH < 0) - //Create chemical sludge eventually(for now just destroy the beaker I guess?) - //TODO Strong acids eat glass, make it so you NEED plastic beakers for superacids(for some reactions) - message_admins("pH is lover limit, cur pH: [pH]") - FermiExplode() - - //For now, purity is handled elsewhere - - //Calculate DeltaT (Deviation of T from optimal) - if (chem_temp < C.OptimalTempMax && chem_temp >= C.OptimalTempMin) - deltaT = (((C.OptimalTempMin - chem_temp)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT)) - else if (chem_temp >= C.OptimalTempMax) - deltaT = 1 - else - deltaT = 0 - message_admins("calculating temperature factor, min: [C.OptimalTempMin], max: [C.OptimalTempMax], Exponential: [C.CurveSharpT], deltaT: [deltaT]") - - //Calculate DeltapH (Deviation of pH from optimal) - //Lower range - if (pH < C.OptimalpHMin) - if (pH < (C.OptimalpHMin - C.ReactpHLim)) - deltapH = 0 - else - deltapH = (((pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH)) - //Upper range - else if (pH > C.OptimalpHMin) - if (pH > (C.OptimalpHMin + C.ReactpHLim)) - deltapH = 0 - else - deltapH = ((C.ReactpHLim -(pH - (C.OptimalpHMax + C.ReactpHLim))+C.ReactpHLim)/(C.ReactpHLim**C.CurveSharppH)) - //Within mid range - else if (pH >= C.OptimalpHMin && pH <= C.OptimalpHMax) - deltapH = 1 - //This should never proc: - else - message_admins("Fermichem's pH broke!! Please let Fermis know!!") - WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])") - //TODO Add CatalystFact - message_admins("calculating pH factor(purity), pH: [pH], min: [C.OptimalpHMin]-[C.ReactpHLim], max: [C.OptimalpHMax]+[C.ReactpHLim], deltapH: [deltapH]") - - stepChemAmmount = targetVol * deltaT - if (stepChemAmmount > C.RateUpLim) - stepChemAmmount = C.RateUpLim - else if (stepChemAmmount <= 0.01) - message_admins("stepChem underflow [stepChemAmmount]") - stepChemAmmount = 0.02 - - if ((reactedVol + stepChemAmmount) > targetVol) - stepChemAmmount = targetVol - reactedVol - message_admins("target volume reached. Reaction should stop after this loop. stepChemAmmount: [stepChemAmmount] + reactedVol: [reactedVol] = targetVol [targetVol]") - - if (reactedVol > 0) - purity = ((purity * reactedVol) + (deltapH * stepChemAmmount)) /((reactedVol+ stepChemAmmount)) //This should add the purity to the product - else - purity = deltapH - - // End. - /* - for(var/B in cached_required_reagents) // - tempVol = min(reactedVol, round(get_reagent_amount(B) / cached_required_reagents[B]))//a simple one over the other? (Is this for multiplying end product? Useful for toxinsludge buildup) - */ - message_admins("cached_results: [cached_results], reactedVol: [reactedVol], stepChemAmmount [stepChemAmmount]") - - - - for(var/B in cached_required_reagents) - message_admins("cached_required_reagents(B): [cached_required_reagents[B]], reactedVol: [reactedVol], base stepChemAmmount [stepChemAmmount]") - remove_reagent(B, (stepChemAmmount * cached_required_reagents[B]), safety = 1)//safety? removes reagents from beaker using remove function. - - for(var/P in cached_results)//Not sure how this works, what is selected_reaction.results? - //reactedVol = max(reactedVol, 1) //this shouldnt happen ... - SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*stepChemAmmount, P)//log - add_reagent(P, cached_results[P]*stepChemAmmount, null, chem_temp)//add reagent function!! I THINK I can do this: - - message_admins("purity: [purity], purity of beaker") - message_admins("Temp before change: [chem_temp], pH after change: [pH]") - //Apply pH changes and thermal output of reaction to beaker - chem_temp += (C.ThermicConstant * stepChemAmmount) - pH += (C.HIonRelease * stepChemAmmount) - message_admins("Temp after change: [chem_temp], pH after change: [pH]") - - - reactedVol = reactedVol + stepChemAmmount - - - return (reactedVol) - -/datum/reagents/proc/FermiExplode() - return + to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.") + ME2.name = "used slime extract" + ME2.desc = "This extract has been used up." + selected_reaction.on_reaction(src, multiplier, special_react_result) + reaction_occurred = TRUE + while(reaction_occurred) + update_total() + return reaction_occurred /datum/reagents/proc/isolate_reagent(reagent) var/list/cached_reagents = reagent_list diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 1bf862bd5e..4a3579bf07 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -130,3 +130,7 @@ rs += "[R.name], [R.volume]" return rs.Join(" | ") + +//Handler for explosion reaction +/datum/reagents/proc/FermiExplode(turf/T, obj/O, mob/living/M, volume) + return diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index d77756a649..cd439b1899 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -359,6 +359,83 @@ ..() . = 1 +/datum/reagent/drug/happiness + name = "Happiness" + id = "happiness" + description = "Fills you with ecstasic numbness and causes minor brain damage. Highly addictive. If overdosed causes sudden mood swings." + reagent_state = LIQUID + color = "#FFF378" + addiction_threshold = 10 + overdose_threshold = 20 + +/datum/reagent/drug/happiness/on_mob_add(mob/living/L) + ..() + L.add_trait(TRAIT_FEARLESS, id) + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug) + +/datum/reagent/drug/happiness/on_mob_delete(mob/living/L) + L.remove_trait(TRAIT_FEARLESS, id) + SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "happiness_drug") + ..() + +/datum/reagent/drug/happiness/on_mob_life(mob/living/carbon/M) + M.jitteriness = 0 + M.confused = 0 + M.disgust = 0 + M.adjustBrainLoss(0.2) + ..() + . = 1 + +/datum/reagent/drug/happiness/overdose_process(mob/living/M) + if(prob(30)) + var/reaction = rand(1,3) + switch(reaction) + if(1) + M.emote("laugh") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_good_od) + if(2) + M.emote("sway") + M.Dizzy(25) + if(3) + M.emote("frown") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_bad_od) + M.adjustBrainLoss(0.5) + ..() + . = 1 + +/datum/reagent/drug/happiness/addiction_act_stage1(mob/living/M)// all work and no play makes jack a dull boy + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_DISTURBED)) + M.Jitter(5) + if(prob(20)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage2(mob/living/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_UNSTABLE)) + M.Jitter(10) + if(prob(30)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage3(mob/living/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(min(mood.sanity, SANITY_CRAZY)) + M.Jitter(15) + if(prob(40)) + M.emote(pick("twitch","laugh","frown")) + ..() + +/datum/reagent/drug/happiness/addiction_act_stage4(mob/living/carbon/human/M) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + mood.setSanity(SANITY_INSANE) + M.Jitter(20) + if(prob(50)) + M.emote(pick("twitch","laugh","frown")) + ..() + . = 1 + /datum/reagent/drug/skooma name = "Skooma" id = "skooma" @@ -429,4 +506,3 @@ if(prob(40)) M.emote(pick("twitch","drool","moan")) ..() - diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 3970e8157b..94db5dba61 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -60,6 +60,9 @@ M.SetSleeping(0, 0) M.jitteriness = 0 M.cure_all_traumas(TRAUMA_RESILIENCE_MAGIC) + if(M.blood_volume < BLOOD_VOLUME_NORMAL) + M.blood_volume = BLOOD_VOLUME_NORMAL + for(var/thing in M.diseases) var/datum/disease/D = thing if(D.severity == DISEASE_SEVERITY_POSITIVE) @@ -1296,3 +1299,37 @@ M.adjustStaminaLoss(1.5*REM, 0) ..() return TRUE + +/datum/reagent/medicine/psicodine + name = "Psicodine" + id = "psicodine" + description = "Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage." + reagent_state = LIQUID + color = "#07E79E" + metabolization_rate = 0.25 * REAGENTS_METABOLISM + overdose_threshold = 30 + +/datum/reagent/medicine/psicodine/on_mob_add(mob/living/L) + ..() + L.add_trait(TRAIT_FEARLESS, id) + +/datum/reagent/medicine/psicodine/on_mob_delete(mob/living/L) + L.remove_trait(TRAIT_FEARLESS, id) + ..() + +/datum/reagent/medicine/psicodine/on_mob_life(mob/living/carbon/M) + M.jitteriness = max(0, M.jitteriness-6) + M.dizziness = max(0, M.dizziness-6) + M.confused = max(0, M.confused-6) + M.disgust = max(0, M.disgust-6) + GET_COMPONENT_FROM(mood, /datum/component/mood, M) + if(mood.sanity <= SANITY_NEUTRAL) // only take effect if in negative sanity and then... + mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL)) // set minimum to prevent unwanted spiking over neutral + ..() + . = 1 + +/datum/reagent/medicine/psicodine/overdose_process(mob/living/M) + M.hallucination = min(max(0, M.hallucination + 5), 60) + M.adjustToxLoss(1, 0) + ..() + . = 1 diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index f5f5eda104..59f4b4576c 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -35,6 +35,9 @@ var/FermiChem = FALSE //If the chemical uses the Fermichem reaction mechanics var/FermiExplode = FALSE //If the chemical explodes in a special way as a result of var/ImpureChem = "toxin" //What chemical is produced with an inpure reaction + var/InverseChemVal = 0.3 + var/InverseChem = "toxin" + /datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact) return diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm index d91e2af7e9..27b1fe12ee 100644 --- a/code/modules/reagents/chemistry/recipes/drugs.dm +++ b/code/modules/reagents/chemistry/recipes/drugs.dm @@ -41,6 +41,13 @@ results = list("aranesp" = 3) required_reagents = list("epinephrine" = 1, "atropine" = 1, "morphine" = 1) +/datum/chemical_reaction/happiness + name = "Happiness" + id = "happiness" + results = list("happiness" = 4) + required_reagents = list("nitrous_oxide" = 2, "epinephrine" = 1, "ethanol" = 1) + required_catalysts = list("plasma" = 5) + /datum/chemical_reaction/skooma name = "skooma" id = "skooma" diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm index dc7c32d925..4cecf4216c 100644 --- a/code/modules/reagents/chemistry/recipes/medicine.dm +++ b/code/modules/reagents/chemistry/recipes/medicine.dm @@ -172,6 +172,12 @@ results = list("mutadone" = 3) required_reagents = list("mutagen" = 1, "acetone" = 1, "bromine" = 1) +/datum/chemical_reaction/neurine + name = "Neurine" + id = "neurine" + results = list("neurine" = 3) + required_reagents = list("mannitol" = 1, "acetone" = 1, "oxygen" = 1) + /datum/chemical_reaction/antihol name = "antihol" id = "antihol" @@ -252,3 +258,9 @@ results = list("modafinil" = 5) required_reagents = list("diethylamine" = 1, "ammonia" = 1, "phenol" = 1, "acetone" = 1, "sacid" = 1) required_catalysts = list("bromine" = 1) // as close to the real world synthesis as possible + +/datum/chemical_reaction/psicodine + name = "Psicodine" + id = "psicodine" + results = list("psicodine" = 5) + required_reagents = list( "mannitol" = 2, "water" = 2, "impedrezene" = 1) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index bcd08b1853..e34f34675c 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -528,6 +528,16 @@ /datum/chemical_reaction/life/on_reaction(datum/reagents/holder, created_volume) chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life") // Lol. +//This is missing, I'm adding it back (see tgwiki). Not sure why we don't have it. +/datum/chemical_reaction/life_friendly + name = "Life (Friendly)" + id = "life_friendly" + required_reagents = list("strange_reagent" = 1, "synthflesh" = 1, "sugar" = 1) + required_temp = 374 + +/datum/chemical_reaction/life_friendly/on_reaction(datum/reagents/holder, created_volume) + chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN) //Pray for cute cats + /datum/chemical_reaction/corgium name = "corgium" id = "corgium" diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index ed2ca66aae..a3633e2f00 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -1,239 +1,243 @@ -/obj/item/reagent_containers/pill - name = "pill" - desc = "A tablet or capsule." - icon = 'icons/obj/chemical.dmi' - icon_state = "pill" - item_state = "pill" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - possible_transfer_amounts = list() - volume = 50 - grind_results = list() - var/apply_type = INGEST - var/apply_method = "swallow" - var/roundstart = 0 - var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills - var/dissolvable = TRUE - -/obj/item/reagent_containers/pill/Initialize() - . = ..() - if(!icon_state) - icon_state = "pill[rand(1,20)]" - if(reagents.total_volume && roundstart) - name += " ([reagents.total_volume]u)" - - -/obj/item/reagent_containers/pill/attack_self(mob/user) - return - - -/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone) - if(!canconsume(M, user)) - return 0 - - if(M == user) - M.visible_message("[user] attempts to [apply_method] [src].") - if(self_delay) - if(!do_mob(user, M, self_delay)) - return 0 - to_chat(M, "You [apply_method] [src].") - - else - M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \ - "[user] attempts to force [M] to [apply_method] [src].") - if(!do_mob(user, M)) - return 0 - M.visible_message("[user] forces [M] to [apply_method] [src].", \ - "[user] forces [M] to [apply_method] [src].") - - - log_combat(user, M, "fed", reagents.log_list()) - if(reagents.total_volume) - reagents.reaction(M, apply_type) - reagents.trans_to(M, reagents.total_volume) - qdel(src) - return 1 - - -/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity) - . = ..() - if(!proximity) - return - if(!dissolvable || !target.is_refillable()) - return - if(target.is_drainable() && !target.reagents.total_volume) - to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.") - return - - if(target.reagents.holder_full()) - to_chat(user, "[target] is full.") - return - - to_chat(user, "You dissolve [src] in [target].") - for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius - to_chat(O, "[user] slips something into [target]!") - reagents.trans_to(target, reagents.total_volume) - qdel(src) - -/obj/item/reagent_containers/pill/tox - name = "toxins pill" - desc = "Highly toxic." - icon_state = "pill5" - list_reagents = list("toxin" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/cyanide - name = "cyanide pill" - desc = "Don't swallow this." - icon_state = "pill5" - list_reagents = list("cyanide" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/adminordrazine - name = "adminordrazine pill" - desc = "It's magic. We don't have to explain it." - icon_state = "pill16" - list_reagents = list("adminordrazine" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/morphine - name = "morphine pill" - desc = "Commonly used to treat insomnia." - icon_state = "pill8" - list_reagents = list("morphine" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/stimulant - name = "stimulant pill" - desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!" - icon_state = "pill19" - list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/salbutamol - name = "salbutamol pill" - desc = "Used to treat oxygen deprivation." - icon_state = "pill16" - list_reagents = list("salbutamol" = 30) - roundstart = 1 - -/obj/item/reagent_containers/pill/charcoal - name = "charcoal pill" - desc = "Neutralizes many common toxins." - icon_state = "pill17" - list_reagents = list("charcoal" = 10) - roundstart = 1 - -/obj/item/reagent_containers/pill/epinephrine - name = "epinephrine pill" - desc = "Used to stabilize patients." - icon_state = "pill5" - list_reagents = list("epinephrine" = 15) - roundstart = 1 - -/obj/item/reagent_containers/pill/mannitol - name = "mannitol pill" - desc = "Used to treat brain damage." - icon_state = "pill17" - list_reagents = list("mannitol" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/mutadone - name = "mutadone pill" - desc = "Used to treat genetic damage." - icon_state = "pill20" - list_reagents = list("mutadone" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/salicyclic - name = "salicylic acid pill" - desc = "Used to dull pain." - icon_state = "pill9" - list_reagents = list("sal_acid" = 24) - roundstart = 1 - -/obj/item/reagent_containers/pill/oxandrolone - name = "oxandrolone pill" - desc = "Used to stimulate burn healing." - icon_state = "pill11" - list_reagents = list("oxandrolone" = 24) - roundstart = 1 - -/obj/item/reagent_containers/pill/insulin - name = "insulin pill" - desc = "Handles hyperglycaemic coma." - icon_state = "pill18" - list_reagents = list("insulin" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/antirad - name = "potassium iodide pill" - desc = "Used to treat radition used to counter radiation poisoning." - icon_state = "pill18" - list_reagents = list("potass_iodide" = 50) - roundstart = 1 - -/obj/item/reagent_containers/pill/antirad_plus - name = "prussian blue pill" - desc = "Used to treat heavy radition poisoning." - icon = 'modular_citadel/icons/obj/modularpills.dmi' - icon_state = "prussian_blue" - list_reagents = list("prussian_blue" = 25, "water" = 10) - roundstart = 1 - -/obj/item/reagent_containers/pill/mutarad - name = "radiation treatment deluxe pill" - desc = "Used to treat heavy radition poisoning and genetic defects." - icon = 'modular_citadel/icons/obj/modularpills.dmi' - icon_state = "anit_rad_fixgene" - list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5) - roundstart = 1 - -///////////////////////////////////////// this pill is used only in a legion mob drop -/obj/item/reagent_containers/pill/shadowtoxin - name = "black pill" - desc = "I wouldn't eat this if I were you." - icon_state = "pill9" - color = "#454545" - list_reagents = list("shadowmutationtoxin" = 1) -//////////////////////////////////////// drugs -/obj/item/reagent_containers/pill/zoom - name = "zoom pill" - list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1) - - -/obj/item/reagent_containers/pill/happy - name = "happy pill" - list_reagents = list("sugar" = 10, "space_drugs" = 10) - - -/obj/item/reagent_containers/pill/lsd - name = "hallucinogen pill" - list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15) - - -/obj/item/reagent_containers/pill/aranesp - name = "speedy pill" - list_reagents = list("aranesp" = 10) - -/obj/item/reagent_containers/pill/floorpill - name = "floorpill" - desc = "A strange pill found in the depths of maintenance" - icon_state = "pill21" - var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill") - var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\ - , "Surely, there's no way this could go bad.") - -/obj/item/reagent_containers/pill/floorpill/Initialize() - list_reagents = list(get_random_reagent_id() = rand(10,50)) - . = ..() - name = pick(names) - if(prob(20)) - desc = pick(descs) - -/obj/item/reagent_containers/pill/get_belt_overlay() - return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch") - -/obj/item/reagent_containers/pill/penis_enlargement - name = "penis enlargement pill" - list_reagents = list("penis_enlargement" = 30) +/obj/item/reagent_containers/pill + name = "pill" + desc = "A tablet or capsule." + icon = 'icons/obj/chemical.dmi' + icon_state = "pill" + item_state = "pill" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + possible_transfer_amounts = list() + volume = 50 + grind_results = list() + var/apply_type = INGEST + var/apply_method = "swallow" + var/roundstart = 0 + var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills + var/dissolvable = TRUE + +/obj/item/reagent_containers/pill/Initialize() + . = ..() + if(!icon_state) + icon_state = "pill[rand(1,20)]" + if(reagents.total_volume && roundstart) + name += " ([reagents.total_volume]u)" + + +/obj/item/reagent_containers/pill/attack_self(mob/user) + return + + +/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone) + if(!canconsume(M, user)) + return 0 + + if(M == user) + M.visible_message("[user] attempts to [apply_method] [src].") + if(self_delay) + if(!do_mob(user, M, self_delay)) + return 0 + to_chat(M, "You [apply_method] [src].") + + else + M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \ + "[user] attempts to force [M] to [apply_method] [src].") + if(!do_mob(user, M)) + return 0 + M.visible_message("[user] forces [M] to [apply_method] [src].", \ + "[user] forces [M] to [apply_method] [src].") + + + log_combat(user, M, "fed", reagents.log_list()) + if(reagents.total_volume) + reagents.reaction(M, apply_type) + reagents.trans_to(M, reagents.total_volume) + qdel(src) + return 1 + + +/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity) + . = ..() + if(!proximity) + return + if(!dissolvable || !target.is_refillable()) + return + if(target.is_drainable() && !target.reagents.total_volume) + to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.") + return + + if(target.reagents.holder_full()) + to_chat(user, "[target] is full.") + return + + to_chat(user, "You dissolve [src] in [target].") + for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius + to_chat(O, "[user] slips something into [target]!") + reagents.trans_to(target, reagents.total_volume) + qdel(src) + +/obj/item/reagent_containers/pill/tox + name = "toxins pill" + desc = "Highly toxic." + icon_state = "pill5" + list_reagents = list("toxin" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/cyanide + name = "cyanide pill" + desc = "Don't swallow this." + icon_state = "pill5" + list_reagents = list("cyanide" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/adminordrazine + name = "adminordrazine pill" + desc = "It's magic. We don't have to explain it." + icon_state = "pill16" + list_reagents = list("adminordrazine" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/morphine + name = "morphine pill" + desc = "Commonly used to treat insomnia." + icon_state = "pill8" + list_reagents = list("morphine" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/stimulant + name = "stimulant pill" + desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!" + icon_state = "pill19" + list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/salbutamol + name = "salbutamol pill" + desc = "Used to treat oxygen deprivation." + icon_state = "pill16" + list_reagents = list("salbutamol" = 30) + roundstart = 1 + +/obj/item/reagent_containers/pill/charcoal + name = "charcoal pill" + desc = "Neutralizes many common toxins." + icon_state = "pill17" + list_reagents = list("charcoal" = 10) + roundstart = 1 + +/obj/item/reagent_containers/pill/epinephrine + name = "epinephrine pill" + desc = "Used to stabilize patients." + icon_state = "pill5" + list_reagents = list("epinephrine" = 15) + roundstart = 1 + +/obj/item/reagent_containers/pill/mannitol + name = "mannitol pill" + desc = "Used to treat brain damage." + icon_state = "pill17" + list_reagents = list("mannitol" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/mutadone + name = "mutadone pill" + desc = "Used to treat genetic damage." + icon_state = "pill20" + list_reagents = list("mutadone" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/salicyclic + name = "salicylic acid pill" + desc = "Used to dull pain." + icon_state = "pill9" + list_reagents = list("sal_acid" = 24) + roundstart = 1 + +/obj/item/reagent_containers/pill/oxandrolone + name = "oxandrolone pill" + desc = "Used to stimulate burn healing." + icon_state = "pill11" + list_reagents = list("oxandrolone" = 24) + roundstart = 1 + +/obj/item/reagent_containers/pill/insulin + name = "insulin pill" + desc = "Handles hyperglycaemic coma." + icon_state = "pill18" + list_reagents = list("insulin" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/antirad + name = "potassium iodide pill" + desc = "Used to treat radition used to counter radiation poisoning." + icon_state = "pill18" + list_reagents = list("potass_iodide" = 50) + roundstart = 1 + +/obj/item/reagent_containers/pill/antirad_plus + name = "prussian blue pill" + desc = "Used to treat heavy radition poisoning." + icon = 'modular_citadel/icons/obj/modularpills.dmi' + icon_state = "prussian_blue" + list_reagents = list("prussian_blue" = 25, "water" = 10) + roundstart = 1 + +/obj/item/reagent_containers/pill/mutarad + name = "radiation treatment deluxe pill" + desc = "Used to treat heavy radition poisoning and genetic defects." + icon = 'modular_citadel/icons/obj/modularpills.dmi' + icon_state = "anit_rad_fixgene" + list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5) + roundstart = 1 + +///////////////////////////////////////// this pill is used only in a legion mob drop +/obj/item/reagent_containers/pill/shadowtoxin + name = "black pill" + desc = "I wouldn't eat this if I were you." + icon_state = "pill9" + color = "#454545" + list_reagents = list("shadowmutationtoxin" = 1) +//////////////////////////////////////// drugs +/obj/item/reagent_containers/pill/zoom + name = "zoom pill" + list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1) + + +/obj/item/reagent_containers/pill/happy + name = "happy pill" + list_reagents = list("sugar" = 10, "space_drugs" = 10) + + +/obj/item/reagent_containers/pill/lsd + name = "hallucinogen pill" + list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15) + + +/obj/item/reagent_containers/pill/aranesp + name = "speedy pill" + list_reagents = list("aranesp" = 10) + +/obj/item/reagent_containers/pill/floorpill + name = "floorpill" + desc = "A strange pill found in the depths of maintenance" + icon_state = "pill21" + var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill") + var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\ + , "Surely, there's no way this could go bad.") + +/obj/item/reagent_containers/pill/floorpill/Initialize() + list_reagents = list(get_random_reagent_id() = rand(10,50)) + . = ..() + name = pick(names) + if(prob(20)) + desc = pick(descs) + +/obj/item/reagent_containers/pill/get_belt_overlay() + return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch") + +/obj/item/reagent_containers/pill/penis_enlargement + name = "penis enlargement pill" + list_reagents = list("PEenlager" = 10) + +/obj/item/reagent_containers/pill/breast_enlargement + name = "breast enlargement pill" + list_reagents = list("BEenlager" = 10) \ No newline at end of file diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index d5b2d16e67..64020bf167 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -196,3 +196,25 @@ /obj/item/organ/tongue/robot/get_spans() return ..() | SPAN_ROBOT + +//FermiChem +/obj/item/organ/tongue/OwO + name = "fluffy tongue" + desc = "OwO what's this?" + icon_state = "tonguenormal" + taste_sensitivity = 10 // extra sensitive and inquisitive uwu + +/obj/item/organ/tongue/OwO/TongueSpeech(var/message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "ne", "nye") + message = replacetext(message, "nu", "nyu") + message = replacetext(message, "na", "nya") + message = replacetext(message, "no", "nyo") + message = replacetext(message, "ove", "uv") + //message = replacetext(message, "th", "ff") //too incoherent in practice + message = replacetext(message, "l", "w") + message = replacetext(message, "r", "w") + if(prob(20)) + message += pick(" OwO", " uwu") + message = lowertext(message) + return message diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 55ead3b5b4..6700acc201 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -608,6 +608,696 @@ return cooldown +////////////////////////////////////// +///////ENTHRAL VELVET CHORDS////////// +////////////////////////////////////// + +//Heavily modified voice of god code +/obj/item/organ/vocal_cords/velvet + name = "velvet chords" + desc = "The voice spoken from these just make you want to drift off, sleep and obey." + icon_state = "voice_of_god" + actions_types = list(/datum/action/item_action/organ_action/colossus) + var/next_command = 0 + var/cooldown_mod = 1 + var/base_multiplier = 1 + spans = list("say","yell") + +/* +/datum/action/item_action/organ_action/colossus + name = "Voice of God" + var/obj/item/organ/vocal_cords/colossus/cords = null + +/datum/action/item_action/organ_action/colossus/New() + ..() + cords = target + +/datum/action/item_action/organ_action/colossus/IsAvailable() + if(world.time < cords.next_command) + return FALSE + if(!owner) + return FALSE + if(!owner.can_speak()) + return FALSE + if(check_flags & AB_CHECK_CONSCIOUS) + if(owner.stat) + return FALSE + return TRUE + +/datum/action/item_action/organ_action/colossus/Trigger() + . = ..() + if(!IsAvailable()) + if(world.time < cords.next_command) + to_chat(owner, "You must wait [DisplayTimeText(cords.next_command - world.time)] before Speaking again.") + return + var/command = input(owner, "Speak with the Voice of God", "Command") + if(QDELETED(src) || QDELETED(owner)) + return + if(!command) + return + owner.say(".x[command]") + +/obj/item/organ/vocal_cords/colossus/can_speak_with() + if(world.time < next_command) + to_chat(owner, "You must wait [DisplayTimeText(next_command - world.time)] before Speaking again.") + return FALSE + if(!owner) + return FALSE + if(!owner.can_speak()) + to_chat(owner, "You are unable to speak!") + return FALSE + return TRUE +*/ + +/obj/item/organ/vocal_cords/velvet/handle_speech(message) + velvetspeech(message, owner, spans, base_multiplier) + return //velvetspeech should handle speech + + + +/obj/item/organ/vocal_cords/velvet/speak_with(message) + velvetspeech(message, owner, spans, base_multiplier) + //next_command = world.time + (cooldown * cooldown_mod) + +////////////////////////////////////// +///////////FermiChem////////////////// +////////////////////////////////////// + +/proc/velvetspeech(message, mob/living/user, list/span_list, base_multiplier = 1, include_speaker = FALSE, message_admins = TRUE) + var/cooldown = 0 + + if(!user || !user.can_speak() || user.stat) + return 0 //no cooldown + + var/log_message = message + if(!span_list || !span_list.len) //Not too sure what this does, I think it changes your output message depending if you're a cultist or not? I.e. font + if(iscultist(user)) + span_list = list("narsiesmall") + else if (is_servant_of_ratvar(user)) + span_list = list("ratvar") + else + span_list = list() + + user.say(message, sanitize = TRUE)//Removed spans = span_list, It should just augment normal speech + + //FIND THRALLS + + message = lowertext(message) + var/mob/living/list/listeners = list() + for(var/mob/living/L in get_hearers_in_view(8, user)) + if(L.can_hear() && !L.anti_magic_check(FALSE, TRUE) && L.stat != DEAD) + if(L.has_status_effect(/datum/status_effect/chem/enthrall))//Check to see if they have the status + if(L == user && !include_speaker) + continue + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(istype(H.ears, /obj/item/clothing/ears/earmuffs)) + continue + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)//Check to see if pet is on cooldown from last command + if (E.cooldown != 0)//If they're on cooldown you can't give them more commands. + continue + listeners += L + + if(!listeners.len) + cooldown = COOLDOWN_NONE + return cooldown + + //POWER CALCULATIONS + + var/power_multiplier = base_multiplier + + // Not sure I want to give extra power to anyone at the moment...? We'll see how it turns out + if(user.mind) + //Chaplains are very good at indoctrinating + if(user.mind.assigned_role == "Chaplain") + power_multiplier *= 2 + //Command staff has authority + if(user.mind.assigned_role in GLOB.command_positions) + power_multiplier *= 1.4 + //Why are you speaking + if(user.mind.assigned_role == "Mime") + power_multiplier *= 0.5 + + //Cultists are closer to their gods and are better at indoctrinating + if(iscultist(user)) + power_multiplier *= 2 + else if (is_servant_of_ratvar(user)) + power_multiplier *= 2 + else if (is_devil(user))//The devil is supposed to be seductive, right? + power_multiplier *= 2 + + //range = 0.5 - 4.2~ + //most cases = 1-2 + + //Try to check if the speaker specified a name or a job to focus on + var/list/specific_listeners = list() + var/found_string = null + + //Get the proper job titles + message = get_full_job_name(message) + + for(var/V in listeners) + var/mob/living/L = V + if(dd_hasprefix(message, L.real_name)) + specific_listeners += L //focus on those with the specified name + //Cut out the name so it doesn't trigger commands + found_string = L.real_name + power_multiplier += 0.5 + + else if(dd_hasprefix(message, L.first_name())) + specific_listeners += L //focus on those with the specified name + //Cut out the name so it doesn't trigger commands + found_string = L.first_name() + power_multiplier += 0.5 + + else if(L.mind && L.mind.assigned_role && dd_hasprefix(message, L.mind.assigned_role)) + specific_listeners += L //focus on those with the specified job + //Cut out the job so it doesn't trigger commands + found_string = L.mind.assigned_role + power_multiplier += 0.25 + + if(specific_listeners.len) + listeners = specific_listeners + //power_multiplier *= (1 + (1/specific_listeners.len)) //Put this is if it becomes OP, power is judged internally on a thrall, so shouldn't be nessicary. + message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1) + + var/obj/item/organ/tongue/T = user.getorganslot(ORGAN_SLOT_TONGUE) + if (T.name == "fluffy tongue") //If you sound hillarious, it's hard to take you seriously. This is a way for other players to combat/reduce their effectiveness. + power_multiplier *= 0.75 + + /* CHECK THIS STUFF IN THE CHEM STATUS INSTEAD. + if(istype(H.neck, /obj/item/clothing/neck/petcollar)) + power_multiplier *= 1.5 //Collaring players makes them more docile and accepting of their place as a pet + if(H.has_trait(TRAIT_CROCRIN_IMMUNE) || !M.canbearoused) + power_multiplier *= 1.5//Immune/asexual players are immune to the arousal based multiplier, this is to offset that so they can still be affected. Their unfamiliarty with desire makes it more on them. + */ + + //Mixables + var/static/regex/enthral_words = regex("relax|obey|love|serve|docile|so easy|ara ara") //enthral_words + var/static/regex/reward_words = regex("good boy|good girl|good pet") //reward_words + var/static/regex/punish_words = regex("bad boy|bad girl|bad pet") ////punish_words + //phase 0 + var/static/regex/saymyname_words = regex("say my name|who am i|whoami") + var/static/regex/wakeup_words = regex("revert|awaken|*snap") + //phase1 + var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush") + var/static/regex/antiresist_words = regex("unable to resist|give in")//useful if you think your target is resisting a lot + var/static/regex/resist_words = regex("resist|snap out of it|fight")//useful if two enthrallers are fighting + var/static/regex/forget_words = regex("forget|muddled|awake and forget") + var/static/regex/attract_words = regex("come here|come to me|get over here|attract") + var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //lewd + //phase 2 + var/static/regex/awoo_words = regex("howl|awoo|bark") + var/static/regex/nya_words = regex("nya|meow|mewl") + var/static/regex/sleep_words = regex("sleep|slumber|rest") + var/static/regex/strip_words = regex("strip|derobe|nude") + var/static/regex/walk_words = regex("slow down") + var/static/regex/run_words = regex("run") + var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown|kneel") + //phase 3 + var/static/regex/statecustom_words = regex("state triggers|state your triggers") + var/static/regex/custom_words = regex("new trigger|listen to me") + var/static/regex/custom_words_words = regex("speak|echo|shock|cum|kneel|strip|objective")//What a descriptive name! + var/static/regex/objective_words = regex("new objective|obey this command|unable to resist|compulsed") + var/static/regex/heal_words = regex("live|heal|survive|mend|life|pets never die") + var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt") + var/static/regex/hallucinate_words = regex("trip balls|hallucinate") + var/static/regex/hot_words = regex("heat|hot|hell") + var/static/regex/cold_words = regex("cold|cool down|chill|freeze") + var/static/regex/getup_words = regex("get up") + var/static/regex/pacify_words = regex("More and more docile|complaisant|friendly|pacifist") + var/static/regex/charge_words = regex("charge|oorah|attack") + + var/distancelist = list(1.5,1.5,1.3,1.2,1.1,1,0.8,0.6,0.5,0.25) + + + //enthral_words, reward_words, silence_words attract_words punish_words desire_words resist_words forget_words + + //Tier 1 + //ENTHRAL mixable + if(findtext(message, enthral_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, V)+1] + //power_multiplier += (get_dist(V, user)**-2)*2 //2, 2, 0.5, 0.2, 0.125, 0.05, 0.04, 0.03, alternatively make a list and use the return as index values + if(length(message)) + E.enthrallTally += (power_multiplier*(((length(message))/200) + 1)) //encourage players to say more than one word. + else + E.enthrallTally += power_multiplier*1.25 + E.cooldown += 1 + + //REWARD mixable + if(findtext(message, reward_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, V)+1] + //power_multiplier += (get_dist(V, user)**-2)*2 //2, 2, 0.5, 0.2, 0.125, 0.05, 0.04, 0.03, alternatively make a list and use the return as index values + if (L.canbearoused) + //E.resistanceTally -= 1 + L.adjustArousalLoss(1*power_multiplier) + else + E.resistanceTally /= 2*power_multiplier + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallpraise", /datum/mood_event/enthrallpraise) + E.cooldown += 1 + + //PUNISH mixable + else if(findtext(message, punish_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, V)+1] + //power_multiplier += (get_dist(V, user)**-2)*2 //2, 2, 0.5, 0.2, 0.125, 0.05, 0.04, 0.03, alternatively make a list and use the return as index values + if (L.canbearoused) + E.resistanceTally /= 1*power_multiplier + L.adjustArousalLoss(-2*power_multiplier) + else + E.resistanceTally /= 3*power_multiplier //asexuals are masochists apparently (not seriously) + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallscold", /datum/mood_event/enthrallscold) + E.cooldown += 1 + + //teir 0 + //SAY MY NAME + if((findtext(message, saymyname_words))) + for(var/V in listeners) + var/mob/living/L = V + addtimer(CALLBACK(L, /atom/movable/proc/say, "Master"), 5)//When I figure out how to do genedered names put them here + + //WAKE UP + else if((findtext(message, wakeup_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(0) + E.phase = 3 + E.status = null + to_chat(L, "The snapping of your Master's fingers brings you back to your enthralled state, obedient and ready to serve.") + L.SetSleeping(0)//Can you hear while asleep? + + //tier 1 + //SILENCE + else if((findtext(message, silence_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, C)+1] + if (E.phase == 3) //If target is fully enthralled, + C.add_trait(TRAIT_MUTE, TRAUMA_TRAIT) + else + C.silent += ((10 * power_multiplier) * E.phase) + E.cooldown += 3 + + //Antiresist + else if((findtext(message, antiresist_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + E.status = "Antiresist" + E.statusStrength = (1 * power_multiplier * E.phase) + E.cooldown += 6//Too short? + + //RESIST + else if((findtext(message, resist_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + power_multiplier *= distancelist[get_dist(user, C)+1] + E.deltaResist += (power_multiplier) + E.cooldown += 2 + + //FORGET (A way to cancel the process) + else if((findtext(message, forget_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + C.Sleeping(40) + to_chat(C, "You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!") + switch(E.phase) + if(1 to 2) + E.phase = -1 + if(3) + E.phase = 0 + E.cooldown = 0 + + //ATTRACT + else if((findtext(message, attract_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + L.throw_at(get_step_towards(user,L), 3 * power_multiplier, 1 * power_multiplier) + E.cooldown += 3 + + + //ORGASM + else if((findtext(message, orgasm_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(H.canbearoused && H.has_dna()) // probably a redundant check but for good measure + H.mob_climax(forced_climax=TRUE) + H.setArousalLoss(H.min_arousal) + E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). + E.enthrallTally += power_multiplier + else + E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so). + E.enthrallTally += power_multiplier*1.1 + to_chat(H, "Your Masters command whites out your mind in bliss!") + E.cooldown += 6 + + //teir 2 + + //awoo + else if((findtext(message, awoo_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + H.say("*awoo") + E.cooldown += 1 + + //Nya + else if((findtext(message, nya_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + var/mob/living/M = V + playsound(get_turf(M), pick('sound/effects/meow1.ogg', 'modular_citadel/sound/voice/merowr.ogg', 'modular_citadel/sound/voice/nya.ogg'), 50, 1, -1) + H.emote("me","lets out a nya!") + E.cooldown += 1 + + //SLEEP + else if((findtext(message, sleep_words))) + for(var/mob/living/carbon/C in listeners) + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY) + C.Sleeping(20 * power_multiplier) + E.cooldown += 10 + + //STRIP + else if((findtext(message, strip_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY)//Tier 2 only + E.phase = 1 + var/items = H.get_contents() + for(var/I in items) + H.dropItemToGround(I, TRUE) + to_chat(H, "Before you can even think about it, you quickly remove your clothes in response to your Master's command.") + E.cooldown += 10 + + //WALK + else if((findtext(message, walk_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY)//Tier 2 only + if(L.m_intent != MOVE_INTENT_WALK) + L.toggle_move_intent() + E.cooldown += 1 + + //RUN + else if((findtext(message, run_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(2 to INFINITY)//Tier 2 only + if(L.m_intent != MOVE_INTENT_RUN) + L.toggle_move_intent() + E.cooldown += 1 + + //KNOCKDOWN + else if(findtext(message, knockdown_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 2 only + L.Knockdown(20 * power_multiplier * E.phase) + E.cooldown += 8 + + //tier3 + + //STATE TRIGGERS + else if((findtext(message, statecustom_words))) + for(var/V in listeners) + var/speaktrigger = "" + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + if (!E.customTriggers == list())//i.e. if it's not empty + for (var/trigger in E.customTriggers) + speaktrigger = "[trigger]\n" + L.say(speaktrigger) + + //CUSTOM TRIGGERS + else if((findtext(message, custom_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3) + if (get_dist(user, H) > 1)//Requires user to be next to their pet. + to_chat(H, "You need to be next to your pet to give them a new trigger!") + return + else + if (E.mental_capacity >= 10) + var/trigger = stripped_input(user, "Enter the trigger phrase", MAX_MESSAGE_LEN) + var/trigger2 = stripped_input(user, "Enter the effect.", MAX_MESSAGE_LEN) + if ((findtext(trigger, custom_words_words))) + if (trigger2 == "speak" || trigger2 == "echo") + var/trigger3 = stripped_input(user, "Enter the phrase spoken.", MAX_MESSAGE_LEN) + E.customTriggers[trigger] = list(trigger2, trigger3) + else + E.customTriggers[trigger] = trigger2 + E.mental_capacity -= 10 + else + to_chat(user, "Your pet looks at you confused, it seems they don't understand that effect!") + else + to_chat(user, "Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them") + + //CUSTOM OBJECTIVE + else if((findtext(message, objective_words))) + for(var/V in listeners) + var/mob/living/carbon/human/H = V + var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall) + if(E.phase == 3) + if (get_dist(user, H) > 1)//Requires user to be next to their pet. + to_chat(H, "You need to be next to your pet to give them a new objective!") + return + else + user.emote("me", "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.'") + if (E.mental_capacity >= 150 || message == "objective") + var/datum/objective/brainwashing/objective = stripped_input(user, "Add an objective to give your pet.", MAX_MESSAGE_LEN) + if(!LAZYLEN(objective)) + return + //Pets don't understand harm + objective = replacetext(lowertext(objective), "kill", "hug") + objective = replacetext(lowertext(objective), "murder", "cuddle") + objective = replacetext(lowertext(objective), "harm", "snuggle") + objective = replacetext(lowertext(objective), "decapitate", "headpat") + objective = replacetext(lowertext(objective), "strangle", "meow at") + H.objective += objective + to_chat(H, "Your master whispers you a new objective.") + if(!H.objectives) + to_chat(H, "[LAZYLEN(H.objectives)]. [H.objectives.explanation_text]") + to_chat(H, "[LAZYLEN(H.objectives)]. [H.objectives.explanation_text]") + E.mental_capacity -= 150 + //else if (E.mental_capacity >= 150) + else + to_chat(user, "Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them") + + + //I dunno how to do state objectives without them revealing they're an antag + + //HEAL (maybe make this nap instead?) + else if((findtext(message, heal_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + E.status = "heal" + E.statusStrength = (5 * power_multiplier) + E.cooldown += 5 + + //STUN + if(findtext(message, stun_words)) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + L.Stun(30 * power_multiplier) + E.cooldown += 8 + + //HALLUCINATE + else if((findtext(message, hallucinate_words))) + for(var/V in listeners) + var/mob/living/carbon/C = V + var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0) + + //HOT + else if((findtext(message, hot_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + L.adjust_bodytemperature(10 * power_multiplier)//This seems nuts, reduced it + to_chat(L, "You feel your metabolism speed up!") + + //COLD + else if((findtext(message, cold_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + L.adjust_bodytemperature(-10 * power_multiplier)//This + to_chat(L, "You feel your metabolism slow down!") + + + //GET UP + else if((findtext(message, getup_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + if(L.resting) + L.lay_down() //aka get up + L.SetStun(0) + L.SetKnockdown(0) + L.SetUnconscious(0) //i said get up i don't care if you're being tased + E.cooldown += 10 //This could be really strong + + //PACIFY + else if((findtext(message, pacify_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + E.status = "pacify" + E.cooldown += 10 + + //CHARGE + else if((findtext(message, charge_words))) + for(var/V in listeners) + var/mob/living/L = V + var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall) + switch(E.phase) + if(3 to INFINITY)//Tier 3 only + E.status = "charge" + E.cooldown += 10 + + + /* THE MAYBE PILE + //MOVE + else if((findtext(message, move_words))) + var/direction + if(findtext(message, up_words)) + direction = NORTH + else if(findtext(message, down_words)) + direction = SOUTH + else if(findtext(message, left_words)) + direction = WEST + else if(findtext(message, right_words)) + direction = EAST + for(var/iter in 1 to 5 * power_multiplier) + for(var/V in listeners) + var/mob/living/L = V + addtimer(CALLBACK(GLOBAL_PROC, .proc/_step, L, direction? direction : pick(GLOB.cardinals)), 10 * (iter - 1)) + + //HELP INTENT + else if((findtext(message, helpintent_words))) + cooldown = COOLDOWN_MEME + for(var/mob/living/carbon/human/H in listeners) + addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_HELP), i * 2) + addtimer(CALLBACK(H, /mob/proc/click_random_mob), i * 2) + i++ + + //DISARM INTENT + else if((findtext(message, disarmintent_words))) + cooldown = COOLDOWN_MEME + for(var/mob/living/carbon/human/H in listeners) + addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_DISARM), i * 2) + addtimer(CALLBACK(H, /mob/proc/click_random_mob), i * 2) + i++ + + //GRAB INTENT + else if((findtext(message, grabintent_words))) + cooldown = COOLDOWN_MEME + for(var/mob/living/carbon/human/H in listeners) + addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_GRAB), i * 2) + addtimer(CALLBACK(H, /mob/proc/click_random_mob), i * 2) + i++ + + //FLIP + else if((findtext(message, flip_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + L.emote("flip") + + //SPEAK (Check what this does) + else if((findtext(message, speak_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + addtimer(CALLBACK(L, /atom/movable/proc/say, pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage")), 5 * i) + i++ + + + //SIT + else if((findtext(message, sit_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + for(var/obj/structure/chair/chair in get_turf(L)) + chair.buckle_mob(L) + break + + //STAND UP + else if((findtext(message, stand_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + if(L.buckled && istype(L.buckled, /obj/structure/chair)) + L.buckled.unbuckle_mob(L) + + //DANCE + else if((findtext(message, dance_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + addtimer(CALLBACK(L, /mob/living/.proc/emote, "dance"), 5 * i) + i++ + + //PLAY DEAD + else if((findtext(message, deathgasp_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/L = V + addtimer(CALLBACK(L, /mob/living/.proc/emote, "deathgasp"), 5 * i) + i++ + */ + + if(message_admins) + message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + log_game("[key_name(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + SSblackbox.record_feedback("tally", "Velvet_voice", 1, log_message) + + return + #undef COOLDOWN_STUN #undef COOLDOWN_DAMAGE diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index 77450b6ac3..14f5540f38 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/modular_citadel/code/datums/mood_events/chem_events.dm b/modular_citadel/code/datums/mood_events/chem_events.dm index b1280c3559..e46bf023f7 100644 --- a/modular_citadel/code/datums/mood_events/chem_events.dm +++ b/modular_citadel/code/datums/mood_events/chem_events.dm @@ -1,3 +1,33 @@ /datum/mood_event/eigenstate mood_change = -1 description = "Where the hell am I? Is this an alternative dimension ?\n" + +/datum/mood_event/enthrall + mood_change = 5 + description = "I am a good pet for Master.\n" + +/datum/mood_event/enthrallpraise + mood_change = 12 + description = "I feel so happy! I'm a good pet who Master loves!\n" + timeout = 400 + +/datum/mood_event/enthrallscold + mood_change = -12 + description = "I've failed Master... What a bad, bad pet!\n"//aaa I'm not kinky enough for this + timeout = 600 + +/datum/mood_event/enthrallmissing1 + mood_change = -5 + description = "I feel empty when Master's not around..\n" + +/datum/mood_event/enthrallmissing2 + mood_change = -10 + description = "I feel so lost in this complicated world without Master, where are they?!\n" + +/datum/mood_event/enthrallmissing3 + mood_change = -15 + description = "Where are you Master??!\n" + +/datum/mood_event/enthrallmissing4 + mood_change = -25 + description = "You're all alone, It's so hard to continute without your Master...\n" diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm index 6f3d4c99ae..319f69e664 100644 --- a/modular_citadel/code/datums/status_effects/chems.dm +++ b/modular_citadel/code/datums/status_effects/chems.dm @@ -1,7 +1,14 @@ /datum/status_effect/chem/SGDF id = "SGDF" var/mob/living/fermi_Clone + alert_type = null +/* +/obj/screen/alert/status_effect/SDGF + name = "SDGF" + desc = "You've cloned yourself! How cute." + icon_state = "SDGF" +*/ /datum/status_effect/chem/SGDF/on_apply() message_admins("SGDF status appied") @@ -21,9 +28,9 @@ return ..() /datum/status_effect/chem/SGDF/tick() - message_admins("SDGF ticking") + //message_admins("SDGF ticking") if(owner.stat == DEAD) - message_admins("SGDF status swapping") + //message_admins("SGDF status swapping") if(fermi_Clone && fermi_Clone.stat != DEAD) if(owner.mind) owner.mind.transfer_to(fermi_Clone) @@ -34,6 +41,552 @@ // to_chat(owner, "[linked_extract] desperately tries to move your soul to a living body, but can't find one!") ..() +/datum/status_effect/chem/BElarger + id = "BElarger" + alert_type = null + //var/list/items = list() + //var/items = o.get_contents() + +//mob/living/carbon/M = M tried, no dice +//owner, tried, no dice +/datum/status_effect/chem/BElarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now. + var/mob/living/carbon/human/o = owner + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W, TRUE) + playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) + //message_admins("BElarge started!") + + if(o.w_uniform || o.wear_suit) + to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling breasts! Unless you manage to reduce the size of your breasts, there's no way you're going to be able to put anything on over these melons..!") + o.visible_message("[o]'s chest suddenly bursts forth, ripping their clothes off!'") + else + to_chat(o, "Your bountiful bosom is so rich with mass, you seriously doubt you'll be able to fit any clothes over it.") + return ..() + +/datum/status_effect/chem/BElarger/tick(mob/living/carbon/human/H)//If you try to wear clothes, you fail. Slows you down if you're comically huge + var/mob/living/carbon/human/o = owner + var/obj/item/organ/genital/breasts/B = o.getorganslot("breasts") + if(!B) + o.remove_movespeed_modifier("megamilk") + o.next_move_modifier = 1 + owner.remove_status_effect(src) + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W, TRUE) + playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) + to_chat(owner, "Your enormous breasts are way too large to fit anything over them!") + //message_admins("BElarge tick!") + /* + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W) + //items |= owner.get_equipped_items(TRUE) + + //owner.dropItemToGround(owner.wear_suit) + //owner.dropItemToGround(owner.w_uniform) + */ + switch(round(B.cached_size)) + if(9) + if (!(B.breast_sizes[B.prev_size] == B.size)) + o.remove_movespeed_modifier("megamilk") + o.next_move_modifier = 1 + if(10 to INFINITY) + if (!(B.breast_sizes[B.prev_size] == B.size)) + to_chat(H, "Your indulgent busom is so substantial, it's affecting your movements!") + o.add_movespeed_modifier("megamilk", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = (round(B.cached_size) - 8)) + o.next_move_modifier = (round(B.cached_size) - 8) + ..() + +/datum/status_effect/chem/BElarger/on_remove(mob/living/carbon/M) + owner.remove_movespeed_modifier("megamilk") + owner.next_move_modifier = 1 + + +/datum/status_effect/chem/PElarger + id = "PElarger" + alert_type = null + +/datum/status_effect/chem/PElarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now. + message_admins("PElarge started!") + var/mob/living/carbon/human/o = owner + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W, TRUE) + playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) + if(o.w_uniform || o.wear_suit) + to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling pecker! Unless you manage to reduce the size of your emancipated trouser snake, there's no way you're going to be able to put anything on over this girth..!") + owner.visible_message("[o]'s schlong suddenly bursts forth, ripping their clothes off!'") + else + to_chat(o, "Your emancipated trouser snake is so ripe with girth, you seriously doubt you'll be able to fit any clothes over it.") + return ..() + + +/datum/status_effect/chem/PElarger/tick(mob/living/carbon/M) + var/mob/living/carbon/human/o = owner + var/obj/item/organ/genital/penis/P = o.getorganslot("penis") + if(!P) + o.remove_movespeed_modifier("hugedick") + o.next_move_modifier = 1 + owner.remove_status_effect(src) + message_admins("PElarge tick!") + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W, TRUE) + playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1) + to_chat(owner, "Your enormous package is way to large to fit anything over!") + switch(round(P.cached_length)) + if(11) + if (!(P.prev_size == P.size)) + to_chat(o, "Your rascally willy has become a more managable size, liberating your movements.") + o.remove_movespeed_modifier("hugedick") + o.next_move_modifier = 1 + if(12 to INFINITY) + if (!(P.prev_size == P.size)) + to_chat(o, "Your indulgent johnson is so substantial, it's affecting your movements!") + o.add_movespeed_modifier("hugedick", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = (P.length - 11.1)) + o.next_move_modifier = (round(P.length) - 11) + ..() + + +/*////////////////////////////////////////// + Mind control functions +/////////////////////////////////////////// +*/ + +/datum/status_effect/chem/enthrall + id = "enthrall" + alert_type = null + var/mob/living/E //E for enchanter + //var/mob/living/V = list() //V for victims + var/enthrallTally = 1 //Keeps track of the enthralling process + var/resistanceTally = 0 //Keeps track of the resistance + var/deltaResist //The total resistance added per resist click + //var/deltaEnthrall //currently unused (i think) + var/phase = 1 //-1: resisted state, due to be removed.0: sleeper agent, no effects unless triggered 1: initial, 2: 2nd stage - more commands, 3rd: fully enthralled, 4th Mindbroken + var/status = null //status effects + var/statusStrength = 0 //strength of status effect + var/mob/living/master //Enchanter's person + var/enthrallID //Enchanter's ckey + var/enthrallGender //Use master or mistress + //var/mob/living/master == null + var/mental_capacity //Higher it is, lower the cooldown on commands, capacity reduces with resistance. + //var/mental_cost //Current cost of custom triggers + //var/mindbroken = FALSE //Not sure I use this, replaced with phase 4 + var/datum/weakref/redirect_component1 //resistance + var/datum/weakref/redirect_component2 //say + var/distancelist = list(4,3,2,1.5,1,0.8,0.6,0.4,0.2) //Distance multipliers + var/withdrawal = FALSE //withdrawl + var/withdrawalTick = 0 //counts how long withdrawl is going on for + var/list/customTriggers = list() //the list of custom triggers (maybe have to split into two) + var/cooldown = 0 + +/datum/status_effect/chem/enthrall/on_apply(mob/living/carbon/M) + if(M.key == enthrallID) + owner.remove_status_effect(src)//This shouldn't happen, but just in case + redirect_component1 = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) //Do resistance calc if resist is pressed# + redirect_component2 = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_SAY = CALLBACK(src, .proc/owner_say)))) //Do resistance calc if resist is pressed + //Might need to add redirect component for listening too. + var/obj/item/organ/brain/B = M.getorganslot(ORGAN_SLOT_BRAIN) //It's their brain! + mental_capacity = 500 - B.get_brain_damage() + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "enthrall", /datum/mood_event/enthrall) + +/datum/status_effect/chem/enthrall/tick(mob/living/carbon/M) + + //chem calculations + if (owner.reagents.has_reagent("MKUltra")) + if (phase >= 2) + enthrallTally += phase + else + if (phase < 3) + deltaResist += 5//If you've no chem, then you break out quickly + if(prob(20)) + to_chat(owner, "Your mind starts to restore some of it's clarity as you feel the effects of the drug wain.") + if (mental_capacity <= 500 || phase == 4) + if (owner.reagents.has_reagent("mannitol")) + mental_capacity += 1 + if (owner.reagents.has_reagent("neurine")) + mental_capacity += 2 + + //mindshield check + if(M.has_trait(TRAIT_MINDSHIELD)) + resistanceTally += 5 + if(prob(20)) + to_chat(owner, "You feel lucidity returning to your mind as the mindshield buzzes, attempting to return your brain to normal function.") + + //phase specific events + switch(phase) + if(-1)//fully removed + SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrall") + owner.remove_status_effect(src) + else if(0)// sleeper agent + return + else if(1)//Initial enthrallment + if (enthrallTally > 100) + phase += 1 + mental_capacity -= resistanceTally//leftover resistance per step is taken away from mental_capacity. + enthrallTally = 0 + to_chat(owner, "Your conciousness slips, as you sink deeper into trance.") + else if (resistanceTally > 100) + enthrallTally *= 0.5 + phase = -1 + resistanceTally = 0 + to_chat(owner, "You break free of the influence in your mind, your thoughts suddenly turning lucid!") + owner.remove_status_effect(src) //If resisted in phase 1, effect is removed. + if(prob(10)) + to_chat(owner, "[pick("It feels so good to listen to [master.name].", "You can't keep your eyes off [master.name].", "[master.name]'s voice is making you feel so sleepy.", "You feel so comfortable with [master.name]", "[master.name] is so sexy and dominant, it feels right to obey them.")].") + else if (2) //partially enthralled + if (enthrallTally > 150) + phase += 1 + mental_capacity -= resistanceTally//leftover resistance per step is taken away from mental_capacity. + enthrallTally = 0 + to_chat(owner, "Your mind gives, eagerly obeying and serving [master.name].") + to_chat(owner, "You are now fully enthralled to [master.name], and eager to follow their commands. However you find that in your intoxicated state you are much less likely to resort to violence, unless it is to defend your [enthrallGender]. Equally you are unable to commit suicide, even if ordered to, as you cannot server your [enthrallGender] in death. ")//If people start using this as an excuse to be violent I'll just make them all pacifists so it's not OP. + else if (resistanceTally > 150) + enthrallTally *= 0.5 + phase -= 1 + resistanceTally = 0 + to_chat(owner, "You manage to shake some of the entrancement from your addled mind, however you can still feel yourself drawn towards [master.name].") + //owner.remove_status_effect(src) //If resisted in phase 1, effect is removed. Not at the moment, + else if (3)//fully entranced + if (resistanceTally >= 250 && withdrawalTick >= 150) + enthrallTally = 0 + phase -= 1 + resistanceTally = 0 + to_chat(owner, "The separation from you [enthrallGender] sparks a small flame of resistance in yourself, as your mind slowly starts to return to normal.") + else if (4) //mindbroken + if (mental_capacity >= 499 || owner.getBrainLoss() >=20 || !owner.reagents.has_reagent("MKUltra")) + phase = 2 + mental_capacity = 500 + customTriggers = list() + to_chat(owner, "Your mind starts to heal, fixing the damage caused by the massive ammounts of chem injected into your system earlier, .") + M.slurring = 0 + M.confused = 0 + else + return//If you break the mind of someone, you can't use status effects on them. + + + //distance calculations + switch(get_dist(master, owner)) + if(0 to 8)//If the enchanter is within range, increase enthrallTally, remove withdrawal subproc and undo withdrawal effects. + enthrallTally += distancelist[get_dist(master, owner)+1] + withdrawal = FALSE + if(withdrawalTick > 0) + withdrawalTick -= 2 + M.hallucination = max(0, M.hallucination - 2) + M.stuttering = max(0, M.stuttering - 2) + M.jitteriness = max(0, M.jitteriness - 2) + if(9 to INFINITY)//If + withdrawal = TRUE + + //Withdrawal subproc: + if (withdrawal == TRUE)//Your minions are really REALLY needy. + switch(withdrawalTick)//denial + if(20 to 40)//Gives wiggle room, so you're not SUPER needy + if(prob(10)) + to_chat(owner, "You're starting to miss your [enthrallGender].") + if(prob(10)) + owner.adjustBrainLoss(0.5) + to_chat(owner, "They'll surely be back soon") //denial + if(41) + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing1", /datum/mood_event/enthrallmissing1) + if(42 to 65)//barganing + if(prob(10)) + to_chat(owner, "They are coming back, right...?") + owner.adjustBrainLoss(1) + if(prob(20)) + to_chat(owner, "I just need to be a good pet for [enthrallGender], they'll surely return if I'm a good pet.") + owner.adjustBrainLoss(-2) + if(66) + SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing1") //Why does this not work? + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing2", /datum/mood_event/enthrallmissing2) + owner.stuttering += 20 + owner.jitteriness += 20 + if(67 to 90) //anger + if(prob(30)) + addtimer(CALLBACK(M, /mob/verb/a_intent_change, INTENT_HARM), 2) + addtimer(CALLBACK(M, /mob/proc/click_random_mob), 2) + to_chat(owner, "You suddenly lash out at the station in anger for it keeping you away from your [enthrallGender].") + if(90) + SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2") //Why does this not work? + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing3", /datum/mood_event/enthrallmissing3) + to_chat(owner, "You need to find your [enthrallGender] at all costs, you can't hold yourself back anymore.") + if(91 to 120)//depression + if(prob(20)) + owner.adjustBrainLoss(1) + owner.stuttering += 2 + owner.jitteriness += 2 + if(prob(25)) + M.hallucination += 2 + if(121) + SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3") + SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing4", /datum/mood_event/enthrallmissing4) + to_chat(owner, "You can hardly find the strength to continue without your [enthrallGender].") + if(120 to 140) //depression + if(prob(25)) + owner.SetStun(20, 0) + owner.emote("cry")//does this exist? + to_chat(owner, "You're unable to hold back your tears, suddenly sobbing as the desire to see your [enthrallGender] oncemore overwhelms you.") + owner.adjustBrainLoss(2) + owner.stuttering += 2 + owner.jitteriness += 2 + if(prob(10)) + deltaResist += 5 + if(140 to INFINITY) //acceptance + if(prob(20)) + deltaResist += 5 + if(prob(20)) + to_chat(owner, "Maybe you'll be okay without your [enthrallGender].") + if(prob(10)) + owner.adjustBrainLoss(1) + M.hallucination += 5 + + withdrawalTick++ + + //Status subproc - statuses given to you from your Master + //currently 3 statuses; antiresist -if you press resist, increases your enthrallment instead, HEAL - which slowly heals the pet, CHARGE - which breifly increases speed, PACIFY - makes pet a pacifist. + if (!status == null) + + switch(status) + if("Antiresist") + if (statusStrength == 0) + status = null + to_chat(owner, "You feel able to resist oncemore.") + else + statusStrength -= 1 + + else if("heal") + if (statusStrength == 0) + status = null + to_chat(owner, "You finish licking your wounds.") + else + statusStrength -= 1 + owner.heal_overall_damage(1, 1, 0, FALSE, FALSE) + cooldown += 1 //Cooldown doesn't process till status is done + + else if("charge") + owner.add_trait(TRAIT_GOTTAGOFAST, "MKUltra") + status = "charged" + to_chat(owner, "Your [enthrallGender]'s order fills you with a burst of speed!") + + else if ("charged") + if (statusStrength == 0) + status = null + owner.remove_trait(TRAIT_GOTTAGOFAST, "MKUltra") + owner.Knockdown(30) + to_chat(owner, "Your body gives out as the adrenaline in your system runs out.") + else + statusStrength -= 1 + cooldown += 1 //Cooldown doesn't process till status is done + + else if ("pacify") + owner.add_trait(TRAIT_PACIFISM, "MKUltra") + status = null + + //Truth serum? + //adrenals? + //M.next_move_modifier *= 0.5 + //M.adjustStaminaLoss(-5*REM) + + //final tidying + resistanceTally += deltaResist + deltaResist = 0 + if (cooldown > 0) + cooldown -= (1 + (mental_capacity/1000 )) + else + to_chat(master, "Your pet [owner.name] appears to have finished internalising your last command.") + +//Check for proximity of master DONE +//Place triggerreacts here - create a dictionary of triggerword and effect. +//message enthrallID "name appears to have mentally processed their last command." + +/datum/status_effect/chem/enthrall/on_remove(mob/living/carbon/M) + qdel(redirect_component1.resolve()) + redirect_component1 = null + qdel(redirect_component2.resolve()) + redirect_component2 = null + +/* +/datum/status_effect/chem/enthrall/mob/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + if(enthrallID.name in message || enthrallID.first_name in message) + return + else + . = ..() +*/ + +/datum/status_effect/chem/enthrall/proc/on_hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) + var/mob/living/carbon/C = owner + for (var/trigger in customTriggers) + if (trigger == message)//if trigger1 is the message + + //Speak (Forces player to talk) + if (customTriggers[trigger][1] == "speak")//trigger2 + C.visible_message("Your mouth moves on it's own, before you can even catch it. Though you find yourself fully believing in the validity of what you just said and don't think to question it.") + (C.say(customTriggers[trigger][2]))//trigger3 + + + //Echo (repeats message!) + else if (customTriggers[trigger][1] == "echo")//trigger2 + (to_chat(owner, customTriggers[trigger][2]))//trigger3 + + //Shocking truth! + else if (customTriggers[trigger] == "shock") + if (C.canbearoused) + C.electrocute_act(10, src, 1, FALSE, FALSE, FALSE, TRUE)//I've no idea how strong this is + C.adjustArousalLoss(5) + to_chat(owner, "Your muscles seize up, then start spasming wildy!") + else + C.electrocute_act(15, src, 1, FALSE, FALSE, FALSE, TRUE)//To make up for the lack of effect + + //wah intensifies + else if (customTriggers[trigger][1] == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + if (C.canbearoused) + if (C.getArousalLoss() > 80) + C.mob_climax(forced_climax=TRUE) + else + C.adjustArousalLoss(10) + else + C.throw_at(get_step_towards(speaker,C), 3, 1) //cut this if it's too hard to get working + + //kneel (knockdown) + else if (customTriggers[trigger][1] == "kneel")//as close to kneeling as you can get, I suppose. + C.Knockdown(20) + + //strip (some) clothes + else if (customTriggers[trigger][1] == "strip")//This wasn't meant to just be a lewd thing oops + var/mob/living/carbon/human/o = owner + var/items = o.get_contents() + for(var/obj/item/W in items) + if(W == o.w_uniform || W == o.wear_suit) + o.dropItemToGround(W, TRUE) + C.visible_message("You feel compelled to strip your clothes.") + + //add more fun stuff! + + + return +/* +/datum/status_effect/chem/enthrall/proc/owner_withdrawal(mob/living/carbon/M) + //3 stages, each getting worse +*/ +/datum/status_effect/chem/enthrall/proc/owner_resist(mob/living/carbon/M) + if (status == "Sleeper" || phase == 0) + return + else if (phase == 4) + to_chat(owner, "Your mind is too far gone to even entertain the thought of resisting.") + return + else if (phase == 3 || withdrawal == FALSE) + to_chat(owner, "The presence of your [enthrallGender] fully captures the horizon of your mind, removing any thoughts of resistance.") + return + else if (status == "Antiresist")//If ordered to not resist; resisting while ordered to not makes it last longer, and increases the rate in which you are enthralled. + if (statusStrength > 0) + to_chat(owner, "The order from your [enthrallGender] to give in is conflicting with your attempt to resist, drawing you deeper into trance.") + statusStrength += 1 + enthrallTally += 1 + return + else + status = null + if (deltaResist != 0)//So you can't spam it, you get one deltaResistance per tick. + deltaResist += 0.1 //Though I commend your spamming efforts. + return + + if(prob(10)) + M.emote("me",1,"squints, shaking their head for a moment.")//shows that you're trying to resist sometimes + to_chat(owner, "You attempt to shake the mental cobwebs from your mind!") + //base resistance + if (M.canbearoused) + deltaResist*= ((100 - M.arousalloss/100)/100)//more aroused you are, the weaker resistance you can give + else + deltaResist *= 0.2 + //chemical resistance, brain and annaphros are the key to undoing, but the subject has to to be willing to resist. + if (owner.reagents.has_reagent("mannitol")) + deltaResist *= 1.25 + if (owner.reagents.has_reagent("neurine")) + deltaResist *= 1.5 + if (!owner.has_trait(TRAIT_CROCRIN_IMMUNE) && M.canbearoused) + if (owner.reagents.has_reagent("anaphro")) + deltaResist *= 1.5 + if (owner.reagents.has_reagent("anaphro+")) + deltaResist *= 2 + if (owner.reagents.has_reagent("aphro")) + deltaResist *= 0.75 + if (owner.reagents.has_reagent("aphro+")) + deltaResist *= 0.5 + + //Antag resistance + //cultists are already brainwashed by their god + if(iscultist(owner)) + deltaResist *= 2 + else if (is_servant_of_ratvar(owner)) + deltaResist *= 2 + //antags should be able to resist, so they can do their other objectives. This chem does frustrate them, but they've all the tools to break free when an oportunity presents itself. + else if (owner.mind.assigned_role in GLOB.antagonists) + deltaResist *= 1.8 + + //role resistance + //Chaplains are already brainwashed by their god + if(owner.mind.assigned_role == "Chaplain") + deltaResist *= 1.5 + //Command staff has authority, + if(owner.mind.assigned_role in GLOB.command_positions) + deltaResist *= 1.4 + //if(owner.has_status == "sub"); power_multiplier *= 0.8 //for skylar //I'm kidding <3 + //Chemists should be familiar with drug effects + if(owner.mind.assigned_role == "Chemist") + deltaResist *= 1.3 + + //Happiness resistance + //Your Thralls are like pets, you need to keep them happy. + if(owner.nutrition < 250) + deltaResist += (250-owner.nutrition)/100 + if(owner.health < 100)//Harming your thrall will make them rebel harder. + deltaResist *= ((120-owner.health)/100)+1 + //Add cold/hot, oxygen, sanity, happiness? (happiness might be moot, since the mood effects are so strong) + //Mental health could play a role too in the other direction + + //If master gives you a collar, you get a sense of pride + if(istype(M.wear_neck, /obj/item/clothing/neck/petcollar)) + deltaResist *= 0.5 + + if(owner.has_trait(TRAIT_CROCRIN_IMMUNE) || !owner.canbearoused) + deltaResist *= 0.75//Immune/asexual players are immune to the arousal based multiplier, this is to offset that so they can still be affected. Their unfamiliarty with desire makes it more on them. + + if (deltaResist>0)//just in case + deltaResist /= phase//later phases require more resistance + +/datum/status_effect/chem/enthrall/proc/owner_say(message) //I can only hope this works + var/static/regex/owner_words = regex("[master.real_name]|[master.first_name()]") + if(findtext(message, owner_words)) + message = replacetext(lowertext(message), lowertext(master.real_name), "[enthrallGender]") + message = replacetext(lowertext(message), lowertext(master.name), "[enthrallGender]") + return message +/* +/datum/status_effect/chem/OwO + id = "OwO" + +/datum/status_effect/chem/PElarger/tick(message) + if(copytext(message, 1, 2) != "*") + message = replacetext(message, "ne", "nye") + message = replacetext(message, "nu", "nyu") + message = replacetext(message, "na", "nya") + message = replacetext(message, "no", "nyo") + message = replacetext(message, "ove", "uv") + message = replacetext(message, "ove", "uv") + message = replacetext(message, "th", "ff") + message = replacetext(message, "l", "w") + message = replacetext(message, "r", "w") + if(prob(20)) + message = replacetext(message, ".", "OwO.") + else if(prob(30)) + message = replacetext(message, ".", "uwu.") + message = lowertext(message) +*/ +/*Doesn't work /datum/status_effect/chem/SDGF/candidates id = "SGDFCandi" var/mob/living/fermi_Clone @@ -42,3 +595,4 @@ /datum/status_effect/chem/SDGF/candidates/on_apply() candies = pollGhostCandidates("Do you want to play as a clone and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies return ..() +*/ diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index a9e8744975..e32c9987d3 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -7,6 +7,11 @@ slot = "breasts" w_class = 3 size = BREASTS_SIZE_DEF + var/cached_size = null//for enlargement + var/prev_size //For flavour texts + var/breast_sizes = list ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "huge", "flat") + var/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/statuscheck = FALSE fluid_id = "milk" var/amount = 2 producing = TRUE @@ -19,6 +24,7 @@ /obj/item/organ/genital/breasts/Initialize() . = ..() reagents.add_reagent(fluid_id, fluid_max_volume) + prev_size = size /obj/item/organ/genital/breasts/on_life() if(QDELETED(src)) @@ -44,10 +50,14 @@ desc = "You see a pair of breasts." else desc = "You see some breasts, they seem to be quite exotic." - if (size) - desc += " You estimate that they're [uppertext(size)]-cups." - else - desc += " You wouldn't measure them in cup sizes." + if(isnum(size)) + 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 [size]cm in diameter." + else if (!isnum(size)) + if (size == "flat") + desc += " They're very small and flatchested, however." + else + desc += " You estimate that they're [uppertext(size)]-cups." + if(producing && aroused_state) desc += " They're leaking [fluid_id]." if(owner) @@ -57,3 +67,65 @@ color = "#[skintone2hex(H.skin_tone)]" else color = "#[owner.dna.features["breasts_color"]]" + + +//Allows breasts to grow and change size, with sprite changes too. +//maximum wah +//Comical sizes slow you down in movement and actions. +//Rediculous sizes remove hands. +//Should I turn someone with meter wide... assets into a blob? +//this is far too lewd wah +/obj/item/organ/genital/breasts/update_size()//wah + //var/mob/living/carbon/human/o = owner + //var/obj/item/organ/genital/breasts/B = o.getorganslot("breasts") + if (cached_size == null) + prev_size = size + return + //message_admins("Breast size at start: [size], [cached_size], [owner]") + if(cached_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!! + to_chat(owner, "You feel your breasts shrinking away from your body as your chest flattens out.") + src.Remove(owner) + switch(round(cached_size)) + if(0) //If flatchested + size = "flat" + if(statuscheck == TRUE) + message_admins("Attempting to remove.") + owner.remove_status_effect(/datum/status_effect/chem/BElarger) + statuscheck = FALSE + if(1 to 8) //If modest size + size = breast_sizes[round(cached_size)] + if(statuscheck == TRUE) + message_admins("Attempting to remove.") + owner.remove_status_effect(/datum/status_effect/chem/BElarger) + statuscheck = FALSE + if(9 to 15) //If massive + size = breast_sizes[round(cached_size)] + if(statuscheck == FALSE) + message_admins("Attempting to apply.") + owner.apply_status_effect(/datum/status_effect/chem/BElarger) + statuscheck = TRUE + + if(16 to INFINITY) //if Rediculous + size = cached_size + //message_admins("1. [breast_values[size]] vs [breast_values[prev_size]] || [size] vs [prev_size]") + //message_admins("1. [prev_size] vs [breast_values[size]]") + if(round(cached_size) < 16)//Because byond doesn't count from 0, I have to do this. + if (prev_size == 0) + prev_size = "flat" + if(size == 0)//Bloody byond with it's counting from 1 + size = "flat" + if(isnum(prev_size)) + prev_size = breast_sizes[prev_size] + //message_admins("2. [breast_values[size]] vs [breast_values[prev_size]] || [size] vs [prev_size]") + if (breast_values[size] > breast_values[prev_size]) + to_chat(owner, "Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size)]-cup.") + var/mob/living/carbon/human/H = owner + H.Force_update_genitals() + else if (breast_values[size] < breast_values[prev_size]) + to_chat(owner, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.") + var/mob/living/carbon/human/H = owner + H.Force_update_genitals() + prev_size = size + + else if (cached_size == 16.2) + to_chat(owner, "Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a hefty [uppertext(size)]cm diameter bosom.")// taking both of your hands to hold!.") diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm index c10d444f07..a3ffcf3698 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals.dm @@ -267,7 +267,13 @@ if(src && !QDELETED(src)) dna.species.handle_genitals(src) +/mob/living/carbon/human/proc/Force_update_genitals() + dna.species.handle_genitals(src) + //dna.species.handle_breasts(src) + + /datum/species/proc/handle_genitals(mob/living/carbon/human/H) + message_admins("attempting to update sprite") if(!H)//no args CRASH("H = null") if(!LAZYLEN(H.internal_organs))//if they have no organs, we're done @@ -276,15 +282,12 @@ return if(H.has_trait(TRAIT_HUSK)) return - var/list/genitals_to_add = list() var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_ADJ_LAYER, GENITALS_FRONT_LAYER) var/list/standing = list() var/size = null - for(var/L in relevant_layers) //Less hardcode H.remove_overlay(L) - //start scanning for genitals //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again for(var/obj/item/organ/O in H.internal_organs) @@ -293,7 +296,6 @@ if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes genitals_to_add += H.getorganslot(G.slot) //Now we added all genitals that aren't internal and should be rendered - //start applying overlays for(var/layer in relevant_layers) var/layertext = genitals_layertext(layer) @@ -348,3 +350,68 @@ for(var/L in relevant_layers) H.apply_overlay(L) +/* +/datum/species/proc/handle_breasts(mob/living/carbon/human/H) + //check for breasts first! + + var/obj/item/organ/genital/breasts/B = H.getorganslot("breasts") + if(!B) + return + message_admins("attempting to update sprite in a hacky way") + ///obj/item/organ/genital/breasts/update_icon(/obj/item/organ/genital) Where did this come from? + //Variables: + var/size = B.size + var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_ADJ_LAYER, GENITALS_FRONT_LAYER) + var/datum/sprite_accessory/S = GLOB.breasts_shapes_list[B.shape] + var/list/standing = list() + + if(!S || S.icon_state == "none") + return + for(var/layer in relevant_layers) + var/layertext = genitals_layertext(layer) + S = GLOB.breasts_shapes_list[B.shape] + + var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) + + //If breasts are hueg (larger than 5 only have one sprite atm) + if (size > 5) + genital_overlay.icon_state = "[B.slot]_[B.shape]_[size]_0_[layertext]"//I haven't done around sizes above 5, I dunno how..! + else + genital_overlay.icon_state = "[B.slot]_[S.icon_state]_[size]_[B.aroused_state]_[layertext]" + + //center icon + if(S.center) + genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y) + + //Check skin colour + if(use_skintones && H.dna.features["genitals_use_skintone"]) + genital_overlay.color = "#[skintone2hex(H.skin_tone)]" + else + switch(S.color_src) + if("vag_color") + genital_overlay.color = "#[H.dna.features["vag_color"]]" + if(MUTCOLORS) + if(fixed_mut_color) + genital_overlay.color = "#[fixed_mut_color]" + else + genital_overlay.color = "#[H.dna.features["mcolor"]]" + if(MUTCOLORS2) + if(fixed_mut_color2) + genital_overlay.color = "#[fixed_mut_color2]" + else + genital_overlay.color = "#[H.dna.features["mcolor2"]]" + if(MUTCOLORS3) + if(fixed_mut_color3) + genital_overlay.color = "#[fixed_mut_color3]" + else + genital_overlay.color = "#[H.dna.features["mcolor3"]]" + + standing += genital_overlay + //Standing..? + if(LAZYLEN(standing)) + H.overlays_standing[layer] = standing.Copy() + standing = list() + + for(var/L in relevant_layers) + H.apply_overlay(L) +*/ diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index f6b9f1d999..f68c31909e 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -18,25 +18,64 @@ var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF var/list/dickflags = list() var/list/knotted_types = list("knotted", "barbed, knotted") + var/statuscheck = FALSE + var/prev_size = 6 + /obj/item/organ/genital/penis/update_size() - if(length == cached_length) - return - switch(length) - if(-INFINITY to 5) + var/mob/living/carbon/human/o = owner + if(cached_length < 0)//I don't actually know what round() does to negative numbers, so to be safe!! + var/obj/item/organ/genital/penis/P = o.getorganslot("penis") + to_chat(o, "You feel your tallywacker shrinking away from your body as your groin flattens out!") + P.Remove(o) + switch(round(cached_length)) + if(0 to 4) //If modest size + length = cached_length size = 1 - if(5 to 9) + if(statuscheck == TRUE) + message_admins("Attempting to remove.") + o.remove_status_effect(/datum/status_effect/chem/PElarger) + statuscheck = FALSE + if(5 to 8) //If modest size + length = cached_length size = 2 - if(9 to INFINITY) - size = 3//no new sprites for anything larger yet -/* if(9 to 15) - size = 3 + if(statuscheck == TRUE) + message_admins("Attempting to remove.") + o.remove_status_effect(/datum/status_effect/chem/PElarger) + statuscheck = FALSE + if(9 to INFINITY) //If massive + length = cached_length + size = 3 //no new sprites for anything larger yet + if(statuscheck == FALSE) + message_admins("Attempting to apply.") + o.remove_status_effect(/datum/status_effect/chem/PElarger) + statuscheck = TRUE if(15 to INFINITY) - size = 3*/ + length = cached_length + size = 3 //no new sprites for anything larger yet + if(statuscheck == FALSE) + message_admins("Attempting to apply.") + o.apply_status_effect(/datum/status_effect/chem/PElarger) + statuscheck = TRUE + message_admins("Pinas size: [size], [cached_length], [o]") + message_admins("2. size vs prev_size") + if (round(length) > round(prev_size)) + to_chat(o, "Your [pick("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger")] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [uppertext(length)] inch penis.") + else if (round(length) < round(prev_size)) + to_chat(o, "Your [pick("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger")] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [uppertext(length)] inch penis.") + prev_size = length + icon_state = sanitize_text("penis_[shape]_[size]") + //update_body() + //P.update_icon() //Either of these don't work, why??? girth = (length * girth_ratio) - cached_length = length + //var/mob/living/carbon/human/H = owner + //H.update_genitals() + //owner.update_genitals() + + //I have no idea on how to update sprites and I hate it /obj/item/organ/genital/penis/update_appearance() + //var/mob/living/carbon/o = owner var/string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]" icon_state = sanitize_text(string) var/lowershape = lowertext(shape) @@ -49,6 +88,7 @@ color = "#[skintone2hex(H.skin_tone)]" else color = "#[owner.dna.features["cock_color"]]" + //owner.update_body() /obj/item/organ/genital/penis/update_link() if(owner) diff --git a/modular_citadel/code/modules/clothing/fermichemclothe/fermiclothes.dm b/modular_citadel/code/modules/clothing/fermichemclothe/fermiclothes.dm new file mode 100644 index 0000000000..6dcfa20b95 --- /dev/null +++ b/modular_citadel/code/modules/clothing/fermichemclothe/fermiclothes.dm @@ -0,0 +1,16 @@ +//Fermiclothes! +//Clothes made from FermiChem + +/obj/item/clothing/head/hattip //I wonder if anyone else has played cryptworlds + name = "Sythetic hat" + con = 'icons/obj/clothing/hats.dmi' + icon_state = "top_hat" + desc = "A sythesized hat, you can't seem to take it off. And tips their hat." + +/obj/item/clothing/head/hattip/attack_hand(mob/user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + if(src == C.head) + M.emote("me",1,"tips their hat.",TRUE) + return + return ..() diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm index 9f13ac4d4c..fbd2be02a9 100644 --- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm +++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm @@ -12,10 +12,10 @@ id = "fermi" taste_description = "If affection had a taste, this would be it." -/datum/reagent/fermi/on_mob_life(mob/living/carbon/M) +///datum/reagent/fermi/on_mob_life(mob/living/carbon/M) //current_cycle++ - holder.remove_reagent(src.id, metabolization_rate / M.metabolism_efficiency, FALSE) //fermi reagents stay longer if you have a better metabolism - return ..() + //holder.remove_reagent(src.id, metabolization_rate / M.metabolism_efficiency, FALSE) //fermi reagents stay longer if you have a better metabolism + //return ..() /datum/reagent/fermi/overdose_start(mob/living/carbon/M) current_cycle++ @@ -29,42 +29,31 @@ name = "Eigenstasium" id = "eigenstate" description = "A strange mixture formed from a controlled reaction of bluespace with plasma, that causes localised eigenstate fluxuations within the patient" - taste_description = "." - color = "#60A584" // rgb: 96, 0, 255 + taste_description = "wiggly" + color = "#5020H4" // rgb: 50, 20, 255 overdose_threshold = 15 addiction_threshold = 20 metabolization_rate = 0.5 * REAGENTS_METABOLISM addiction_stage2_end = 30 addiction_stage3_end = 40 addiction_stage4_end = 43 //Incase it's too long - var/turf/open/location_created = null + var/location_created var/turf/open/location_return = null - var/addictCyc1 = 1 - var/addictCyc2 = 1 - var/addictCyc3 = 1 - var/addictCyc4 = 1 + var/addictCyc1 = 0 + var/addictCyc2 = 0 + var/addictCyc3 = 0 + var/addictCyc4 = 0 var/mob/living/fermi_Tclone = null var/teleBool = FALSE mob/living/carbon/purgeBody - /* -/datum/reagent/fermi/eigenstate/oew() - . = ..() //Needed! - location_created = get_turf(src) //Sets up coordinate of where it was created - message_admins("Attempting to get creation location from on_new() [location_created]") - //..()s -*/ /datum/reagent/fermi/eigenstate/on_new() -//obj/item/reagent/fermi/eigenstate/Initialize() -//datum/reagent/fermi/eigenstate/Initialize() - . = ..() //Needed! - //if(holder && holder.my_atom) location_created = get_turf(loc) //Sets up coordinate of where it was created message_admins("Attempting to get creation location from init() [location_created]") //..() - - +*/ +//Main functions /datum/reagent/fermi/eigenstate/on_mob_life(mob/living/M) //Teleports to chemistry! switch(current_cycle) if(0) @@ -76,7 +65,7 @@ do_sparks(5,FALSE,M) if(prob(20)) do_sparks(5,FALSE,M) - message_admins("eigenstate state: [current_cycle]") + //message_admins("eigenstate state: [current_cycle]") ..() /datum/reagent/fermi/eigenstate/on_mob_delete(mob/living/M) //returns back to original location @@ -95,10 +84,10 @@ do_sparks(5,FALSE,src) do_teleport(M, get_turf(M), 10, asoundin = 'sound/effects/phasein.ogg') do_sparks(5,FALSE,src) - holder.remove_reagent("eigenstate",0.5)//So you're not stuck for 10 minutes teleporting + holder.remove_reagent(src.id, 0.5)//So you're not stuck for 10 minutes teleporting ..() //loop function - +//Addiction /datum/reagent/fermi/eigenstate/addiction_act_stage1(mob/living/M) //Welcome to Fermis' wild ride. switch(src.addictCyc1) if(1) @@ -110,7 +99,7 @@ /datum/reagent/fermi/eigenstate/addiction_act_stage2(mob/living/M) switch(src.addictCyc2) - if(1) + if(0) to_chat(M, "You start to convlse violently as you feel your consciousness split and merge across realities as your possessions fly wildy off your body.") M.Jitter(50) M.Knockdown(100) @@ -163,7 +152,7 @@ /datum/reagent/fermi/eigenstate/addiction_act_stage4(mob/living/M) //Thanks for riding Fermis' wild ride. Mild jitter and player buggery. switch(src.addictCyc4) - if(1) + if(0) do_sparks(5,FALSE,M) do_teleport(M, get_turf(M), 2, no_effects=TRUE) //teleports clone so it's hard to find the real one! do_sparks(5,FALSE,M) @@ -172,9 +161,9 @@ M.Knockdown(0) to_chat(M, "You feel your eigenstate settle, snapping an alternative version of yourself into reality. All your previous memories are lost and replaced with the alternative version of yourself. This version of you feels more [pick("affectionate", "happy", "lusty", "radical", "shy", "ambitious", "frank", "voracious", "sensible", "witty")] than your previous self, sent to god knows what universe.") M.emote("me",1,"flashes into reality suddenly, gasping as they gaze around in a bewildered and highly confused fashion!",TRUE) - M.reagents.remove_all_type(/datum/reagent/toxin, 5*REM, 0, 1) - for(var/i in M.mood_events) - SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, i.id) + M.reagents.remove_all_type(/datum/reagent, 100, 0, 1) + for (var/datum/mood_event/i in M) + SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, i) //Why does this not work? SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "Alternative dimension", /datum/mood_event/eigenstate) @@ -185,11 +174,49 @@ ..() . = 1 +//TODO ///datum/reagent/fermi/eigenstate/overheat_explode(mob/living/M) // return + //eigenstate END +/*SDGF +//////////////////////////////////////////////////// +// synthetic-derived growth factor // +////////////////////////////////////////////////// +WHAT IT DOES + +Several outcomes are possible (in priority order): + +Before the chem is even created, there is a risk of the reaction "exploding", which produces an angry teratoma that attacks the player. +0. Before the chem is activated, the purity is checked, if the purity of the reagent is less than 0.5, then sythetic-derived zombie factor is metabolised instead + 0.1 If SDZF is injected, the chem appears to act the same as normal, with nutrition gain, until the end, where it becomes toxic instead, giving a short window of warning to the player + 0.1.2 If the player can take pent in time, the player will spawn a hostile teratoma on them (less damaging), if they don't, then a zombie is spawned instead, with a small defence increase propotional to the volume + 0.2 If the purity is above 0.5, then the remaining impure volume created SDGFtox instead, which reduces blood volume and causes clone damage +1.Normal function creates a (another)player controlled clone of the player, which is spawned nude, with damage to the clone + 1.1 The remaining volume is transferred to the clone, which heals it over time, thus the player has to make a substantial ammount of the chem in order to produce a healthy clone + 1.2 If the player is infected with a zombie tumor, the tumor is transferred to the ghost controlled clone ONLY. +2. If no player can be found, a brainless clone is created over a long period of time, this body has no controller. + 2.1 If the player dies with a clone, then they play as the clone instead. However no memories are retained after splitting. +3. If there is already a clone, then SDGF heals clone, fire and brute damage slowly. This shouldn't normalise this chem as the de facto clone healing chem, as it will always try to make a ghost clone, and then a brainless clone first. +4. If there is insuffient volume to complete the cloning process, there are two outcomes + 4.1 At lower volumes, the players nutrition and blood is refunded, with light healing + 4.2 At higher volumes a stronger heal is applied to the user + +IMPORTANT FACTORS TO CONSIDER WHILE BALANCING +1. The most important factor is the required volume, this is easily edited with the metabolism rate, this chem is HARD TO MAKE, You need to make a lot of it and it's a substantial effort on the players part. There is also a substantial risk; you could spawn a hotile teratoma during the reation, you could damage yourself with clone damage, you could accidentally spawn a zombie... Basically, you've a good chance of killing yourself. + 1.1 Additionally, if you're trying to make SDZF purposely, you've no idea if you have or not, and that reaction is even harder to do. Plus, the player has a huge time window to get to medical to deal with it. If you take pent while it's in you, it'll be removed before it can spawn, and only spawns a teratoma if it's late stage. +2. The rate in which the clone is made, This thing takes time to produce fruits, it slows you down and makes you useless in combat/working. Basically you can't do anything during it. It will only get you killed if you use it in combat, If you do use it and you spawn a player clone, they're gimped for a long time, as they have to heal off the clone damage. +3. The healing - it's pretty low and a cyropod is more Useful +4. If you're an antag, you've a 50% chance of making a clone that will help you with your efforts, and you've no idea if they will or not. While clones can't directly harm you and care for you, they can hinder your efforts. +5. If people are being arses when they're a clone, slap them for it, they are told to NOT bugger around with someone else character, if it gets bad I'll add a blacklist, or do a check to see if you've played X amount of hours. + 5.1 Another solution I'm okay with is to rename the clone to [M]'s clone, so it's obvious, this obviously ruins anyone trying to clone themselves to get an alibi however. I'd prefer this to not be the case. + 5.2 Additionally, this chem is a soft buff to changelings, which apparently need a buff! + 5.3 Other similar things exist already though in the codebase; impostors, split personalites, abductors, ect. +6. Giving this to someone without concent is against space law and gets you sent to gulag. +*/ + //Clone serum #chemClone /datum/reagent/fermi/SDGF //vars, mostly only care about keeping track if there's a player in the clone or not. name = "synthetic-derived growth factor" @@ -198,61 +225,42 @@ color = "#60A584" // rgb: 96, 0, 255 var/playerClone = FALSE var/unitCheck = FALSE - metabolization_rate = 0.25 * REAGENTS_METABOLISM + metabolization_rate = 0.5 * REAGENTS_METABOLISM //var/datum/status_effect/chem/SDGF/candidates/candies var/list/candies = list() //var/polling = FALSE var/list/result = list() var/list/group = null + var/pollStarted = FALSE + var/location_created + var/startHunger //var/fClone_current_controller = OWNER //var/mob/living/split_personality/clone//there's two so they can swap without overwriting //var/mob/living/split_personality/owner //var/mob/living/carbon/SM -/* -/datum/reagent/fermi/SDGF/New() - candidates = pollGhostCandidates("Do you want to play as a clone and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies - message_admins("Attempting to poll") -^^^breaks everything -*/ -/datum/reagent/fermi/proc/sepPoll() - var/list/procCandies = list() - procCandies = pollGhostCandidates("Do you want to play as a clone and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 20) // see poll_ignore.dm, should allow admins to ban greifers or bullies - return procCandies - - /*if(1) //I'm not sure how pollCanditdates works, so I did this. Gives a chance for people to say yes. - M.apply_status_effect(/datum/status_effect/chem/SDGF/candidates) - /datum/status_effect/chem/SDGF/candidates/candies = new /datum/status_effect/chem/SDGF/candidates - ///datum/status_effect/chem/SDGF/candidates/candies = M.apply_status_effect(/datum/status_effect/chem/SDGF/candidates) - //candies = pollGhostCandidates("Do you want to play as a clone of [M.name] and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies - message_admins("Attempting to poll")*/ +//Main SDGF chemical /datum/reagent/fermi/SDGF/on_mob_life(mob/living/carbon/M) //Clones user, then puts a ghost in them! If that fails, makes a braindead clone. //Setup clone switch(current_cycle) if(1) - for(var/mob/dead/observer/G in GLOB.player_list) - group += G - for(var/m in group) - var/mob/W = m - message_admins("Attempting to poll") - showCandidatePollWindow(M, 190, "Do you want to play as a clone of [M.name] and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you.", result, null, current_cycle, TRUE) - if(19) - for(var/mob/W in result) - if(!W.key || !W.client) - result -= W - candies = result + startHunger = M.nutrition + if(pollStarted == FALSE) + pollStarted = TRUE + candies = pollGhostCandidates("Do you want to play as a clone and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you.") if(20 to INFINITY) message_admins("Number of candidates [LAZYLEN(candies)]") if(LAZYLEN(candies) && src.playerClone == FALSE) //If there's candidates, clone the person and put them in there! message_admins("Candidate found!") + to_chat(M, "The cells reach a critical micelle concentration, nucleating rapidly within your body!") //var/typepath = owner.type //clone = new typepath(owner.loc) var/typepath = M.type - var/mob/living/carbon/fermi_Gclone = new typepath(M.loc) + var/mob/living/carbon/human/fermi_Gclone = new typepath(M.loc) //var/mob/living/carbon/SM = owner //var/mob/living/carbon/M = M - var/mob/living/carbon/SM = fermi_Gclone + var/mob/living/carbon/human/SM = fermi_Gclone if(istype(SM) && istype(M)) SM.real_name = M.real_name M.dna.transfer_identity(SM) @@ -261,6 +269,8 @@ SM.key = C.key SM.mind.enslave_mind_to_creator(M) + //If they're a zombie, they can try to negate it with this. + //I seriously wonder if anyone will ever use this function. if(M.getorganslot(ORGAN_SLOT_ZOMBIE))//sure, it "treats" it, but "you've" still got it. Doesn't always work as well; needs a ghost. var/obj/item/organ/zombie_infection/ZI = M.getorganslot(ORGAN_SLOT_ZOMBIE) ZI.Remove(M) @@ -269,62 +279,96 @@ //SM.sentience_act() to_chat(SM, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with yourself, or rather, your original self.") to_chat(SM, "While you find your newfound existence strange, you share the same memories as [M.real_name]. [pick("However, You find yourself indifferent to the goals you previously had, and take more interest in your newfound independence, but still have an indescribable care for the safety of your original", "Your mind has not deviated from the tasks you set out to do, and now that there's two of you the tasks should be much easier.")]") - to_chat(M, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with yourself.") + to_chat(M, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with yourself.") M.visible_message("[M] suddenly shudders, and splits into two identical twins!") SM.copy_known_languages_from(M, FALSE) playerClone = TRUE - M.next_move_modifier = 1 - M.nutrition = 150 + M.nutrition -= 500 + //reaction_mob(SM, )I forget what this is for + //Damage the clone + SM.blood_volume = BLOOD_VOLUME_NORMAL/2 + SM.adjustCloneLoss(80, 0) + SM.setBrainLoss(40) + SM.nutrition = startHunger/2 + //var/datum/reagents/SMR = SM + ///datum/reagents + //var/mob/living/carbon/human has a holder, carbon does not + // You need to add to a holder. + // reagentS not reagent (?) + //SM.create_reagents() + + //Really hacky way to deal with this stupid problem I have + SM.reagents.add_reagent("SDGFheal", volume) + //holder.add_reagent("SDGFheal", volume) + holder.remove_reagent(src.id, 999) + //SMR = locate(/datum/reagents in SM) + //holder.trans_to(SMR, volume) + + //Give the new clone an idea of their character + //SHOULD print last 5 messages said by the original to the clones chatbox + var/list/say_log = M.logging[LOG_SAY] + if(LAZYLEN(say_log) > 5) + var/recent_speech = say_log.Copy(say_log.len+5,0) //0 so len-LING_ARS+1 to end of list + else + for(var/spoken_memory in recent_speech) + to_chat(SM, spoken_memory) + + + return //BALANCE: should I make them a pacifist, or give them some cellular damage or weaknesses? //after_success(user, SM) //qdel(src) - else //No candidates leads to two outcomes; if there's already a braincless clone, it heals the user, as well as being a rare souce of clone healing (thematic!). + else if(src.playerClone == FALSE) //No candidates leads to two outcomes; if there's already a braincless clone, it heals the user, as well as being a rare souce of clone healing (thematic!). message_admins("Failed to find clone Candidate") src.unitCheck = TRUE if(M.has_status_effect(/datum/status_effect/chem/SGDF)) // Heal the user if they went to all this trouble to make it and can't get a clone, the poor fellow. - to_chat(M, "The cells fail to catalyse around a nucleation event, instead merging with your cells.") //This stuff is hard enough to make to rob a user of some benefit. Shouldn't replace Rezadone as it requires the user to not only risk making a player controlled clone, but also requires them to have split in two (which also requires 30u of SGDF). - M.adjustCloneLoss(-2, 0) - M.adjustBruteLoss(-2, 0) - M.adjustFireLoss(-2, 0) - M.heal_bodypart_damage(1,1) - M.remove_trait(TRAIT_DISFIGURED, TRAIT_GENERIC) + switch(current_cycle) + if(21) + to_chat(M, "The cells fail to catalyse around a nucleation event, instead merging with your cells.") //This stuff is hard enough to make to rob a user of some benefit. Shouldn't replace Rezadone as it requires the user to not only risk making a player controlled clone, but also requires them to have split in two (which also requires 30u of SGDF). + M.remove_trait(TRAIT_DISFIGURED, TRAIT_GENERIC) + if(22 to INFINITY) + M.adjustCloneLoss(-1, 0) + M.adjustBruteLoss(-1, 0) + M.adjustFireLoss(-1, 0) + M.heal_bodypart_damage(1,1) else //If there's no ghosts, but they've made a large amount, then proceed to make flavourful clone, where you become fat and useless until you split. switch(current_cycle) - if(10) + if(21) to_chat(M, "You feel the synethic cells rest uncomfortably within your body as they start to pulse and grow rapidly.") - if(11 to 19) + if(22 to 29) M.nutrition = M.nutrition + (M.nutrition/10) - if(20) + if(30) to_chat(M, "You feel the synethic cells grow and expand within yourself, bloating your body outwards.") - if(21 to 39) + if(31 to 49) M.nutrition = M.nutrition + (M.nutrition/5) - if(40) + if(50) to_chat(M, "The synthetic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.") - M.next_move_modifier = 4//If this makes you fast then please fix it, it should make you slow!! + M.next_move_modifier += 4//If this makes you fast then please fix it, it should make you slow!! //candidates = pollGhostCandidates("Do you want to play as a clone of [M.name] and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies - if(41 to 69) + if(51 to 79) M.nutrition = M.nutrition + (M.nutrition/2) - if(70) + if(80) to_chat(M, "The cells begin to precipitate outwards of your body, you feel like you'll split soon...") if (M.nutrition < 20000) M.nutrition = 20000 //https://www.youtube.com/watch?v=Bj_YLenOlZI - if(76)//Upon splitting, you get really hungry and are capable again. Deletes the chem after you're done. + if(86)//Upon splitting, you get really hungry and are capable again. Deletes the chem after you're done. M.nutrition = 15//YOU BEST BE EATTING AFTER THIS YOU CUTIE - M.next_move_modifier = 1 + M.next_move_modifier -= 4 to_chat(M, "Your body splits away from the cell clone of yourself, leaving you with a drained and hollow feeling inside.") M.apply_status_effect(/datum/status_effect/chem/SGDF) - if(77 to INFINITY) - holder.remove_reagent("SGDF", 1)//removes SGDF on completion. + if(87 to INFINITY) + holder.remove_reagent(src.id, 1)//removes SGDF on completion. message_admins("Purging SGDF [volume]") message_admins("Growth nucleation occuring (SDGF), step [current_cycle] of 77") ..() -/datum/reagent/fermi/SDGF/on_mob_delete(mob/living/M) //When the chem is removed, a few things can happen. +/datum/reagent/fermi/SDGF/on_mob_delete(mob/living/M) //When the chem is removed, a few things can happen, mostly consolation prizes. + pollStarted = FALSE if (playerClone == TRUE)//If the player made a clone with it, then thats all they get. playerClone = FALSE return @@ -340,109 +384,506 @@ M.nutrition += 250 else if (src.unitCheck == TRUE && !M.has_status_effect(/datum/status_effect/chem/SGDF))// If they're ingested a little bit (10u minimum), then give them a little healing. src.unitCheck = FALSE - to_chat(M, "the cells fail to hold enough mass to generate a clone, instead diffusing into your system instead. you can fee") + to_chat(M, "the cells fail to hold enough mass to generate a clone, instead diffusing into your system.") M.adjustBruteLoss(-10, 0) M.adjustFireLoss(-10, 0) M.blood_volume += 100 + M.next_move_modifier = 1 if (M.nutrition < 1500) M.nutrition += 500 +//If the reaction explodes +/* +/datum/reagent/fermi/SDGF/FermiExplode(turf/open/T)//Spawns an angery teratoma!! Spooky..! be careful!! TODO: Add teratoma slime subspecies + //var/mob/living/simple_animal/slime/S = new(get_turf(location_created),"grey") + var/mob/living/simple_animal/slime/S = new(T,"grey")//should work, in theory + S.damage_coeff = list(BRUTE = 0.9 , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)//I dunno how slimes work cause fire is burny + S.name = "Living teratoma" + S.real_name = "Living teratoma"//horrifying!! + S.rabid = 1//Make them an angery boi, grr grr + to_chat("The cells clump up into a horrifying tumour.") +*/ +//Unobtainable, used in clone spawn. +/datum/reagent/fermi/SDGFheal + name = "synthetic-derived growth factor" + id = "SDGFheal" + metabolization_rate = 1 + +/datum/reagent/fermi/SDGFheal/on_mob_life(mob/living/carbon/M)//Used to heal the clone after splitting, the clone spawns damaged. (i.e. insentivies players to make more than required, so their clone doesn't have to be treated) + if(M.blood_volume < BLOOD_VOLUME_NORMAL) + M.blood_volume += 10 + M.adjustCloneLoss(-2, 0) + M.setBrainLoss(-1) + M.nutrition += 10 + ..() + +//Unobtainable, used if SDGF is impure but not too impure +/datum/reagent/fermi/SDGFtox + name = "synthetic-derived growth factor" + id = "SDGFtox" + description = "A chem that makes Fermis angry at you if you're reading this, how did you get this???" + metabolization_rate = 1 + +/datum/reagent/fermi/SDGFtox/on_mob_life(mob/living/carbon/M)//Damages the taker if their purity is low. Extended use of impure chemicals will make the original die. (thus can't be spammed unless you've very good) + M.blood_volume -= 10 + M.adjustCloneLoss(2, 0) + ..() + +//Fail state of SDGF /datum/reagent/fermi/SDZF - name = "synthetic-derived zombie factor" + name = "synthetic-derived growth factor" id = "SDZF" description = "A horribly peverse mass of Embryonic stem cells made real by the hands of a failed chemist. This message should never appear, how did you manage to get a hold of this?" color = "#60A584" // rgb: 96, 0, 255 - metabolization_rate = 0.25 * REAGENTS_METABOLISM - var/fermi_Zombie + metabolization_rate = 0.5 * REAGENTS_METABOLISM + var/startHunger /datum/reagent/fermi/SDZF/on_mob_life(mob/living/carbon/M) //If you're bad at fermichem, turns your clone into a zombie instead. message_admins("SGZF ingested") switch(current_cycle)//Pretends to be normal - if(10) - to_chat(M, "You feel the synethic cells rest uncomfortably within your body as they start to pulse and grow rapidly.") - if(11 to 19) - M.nutrition = M.nutrition + (M.nutrition/10) if(20) + to_chat(M, "You feel the synethic cells rest uncomfortably within your body as they start to pulse and grow rapidly.") + startHunger = M.nutrition + if(21 to 29) + M.nutrition = M.nutrition + (M.nutrition/10) + if(30) to_chat(M, "You feel the synethic cells grow and expand within yourself, bloating your body outwards.") - if(21 to 39) + if(31 to 49) M.nutrition = M.nutrition + (M.nutrition/5) - if(40) + if(50) to_chat(M, "The synethic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.") M.next_move_modifier = 4//If this makes you fast then please fix it, it should make you slow!! - if(41 to 63) + if(51 to 73) M.nutrition = M.nutrition + (M.nutrition/2) - if(64) + if(74) to_chat(M, "The cells begin to precipitate outwards of your body, but... something is wrong, the sythetic cells are beginnning to rot...") - if (M.nutrition < 20000) + if (M.nutrition < 20000) //whoever knows the maxcap, please let me know, this seems a bit low. M.nutrition = 20000 //https://www.youtube.com/watch?v=Bj_YLenOlZI - if(65 to 75) + if(75 to 85) M.adjustToxLoss(1, 0)// the warning! - if(76) + if(86) if (!holder.has_reagent("pen_acid"))//Counterplay is pent.) message_admins("Zombie spawned at [M.loc]") - M.nutrition -= 18500//YOU BEST BE RUNNING AWAY AFTER THIS YOU BADDIE + M.nutrition = startHunger - 500//YOU BEST BE RUNNING AWAY AFTER THIS YOU BADDIE M.next_move_modifier = 1 to_chat(M, "Your body splits away from the cell clone of yourself, your attempted clone birthing itself violently from you as it begins to shamble around, a terrifying abomination of science.") M.visible_message("[M] suddenly shudders, and splits into a funky smelling copy of themselves!") M.emote("scream") M.adjustToxLoss(30, 0) - //fermi_Zombie = new typepath(M.loc) var/mob/living/simple_animal/hostile/zombie/ZI = new(get_turf(M.loc)) ZI.damage_coeff = list(BRUTE = ((1 / volume)**0.25) , BURN = ((1 / volume)**0.1), TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) ZI.real_name = M.real_name//Give your offspring a big old kiss. ZI.name = M.real_name + ZI.desc = "[M]'s clone, gone horribly wrong." + ZI.zombiejob = null //ZI.updateappearance(mutcolor_update=1) - holder.remove_reagent("SGZF", 50) - else - to_chat(M, "The pentetic acid seems to have stopped the decay for now, clumping up the cells into a horrifying tumour.") - if(77 to INFINITY)//purges chemical fast, producing a "slime" for each one. Said slime is weak to fire. - M.nutrition -= 100 - var/mob/living/simple_animal/slime/S = new(get_turf(M.loc),"grey") - S.damage_coeff = list(BRUTE = ((1 / volume)**0.1) , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) - S.name = "Living teratoma" - S.real_name = "Living teratoma" - //S.updateappearance(mutcolor_update=1) - holder.remove_reagent("SGZF", 50) - M.adjustToxLoss(10, 0) - to_chat(M, "A large glob of the tumour suddenly splits itself from your body. You feel grossed out and slimey...") + holder.remove_reagent(src.id, 20) + else//easier to deal with + to_chat(M, "The pentetic acid seems to have stopped the decay for now, clumping up the cells into a horrifying tumour!") + M.nutrition = startHunger - 500 + var/mob/living/simple_animal/slime/S = new(get_turf(M.loc),"grey") //TODO: replace slime as own simplemob/add tumour slime cores for science/chemistry interplay + S.damage_coeff = list(BRUTE = ((1 / volume)**0.1) , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + S.name = "Living teratoma" + S.real_name = "Living teratoma"//horrifying!! + S.rabid = 1//Make them an angery boi + //S.updateappearance(mutcolor_update=1) + holder.remove_reagent(src.id, 20) + to_chat(M, "A large glob of the tumour suddenly splits itself from your body. You feel grossed out and slimey...") + if(87 to INFINITY)//purges chemical fast, producing a "slime" for each one. Said slime is weak to fire. TODO: turn tumour slime into real variant. + M.adjustToxLoss(1, 0) message_admins("Growth nucleation occuring (SDGF), step [current_cycle] of 20") ..() - -//Breast englargement +//breast englargement +//Honestly the most requested chems +//I'm not a very kinky person, sorry if it's not great +//I tried to make it interesting..!! /datum/reagent/fermi/BElarger - name = "Sucubus Draft" + name = "Sucubus milk" id = "BEenlager" description = "A volatile collodial mixture derived from milk that encourages mammary production via a potent estrogen mix." - color = "#60A584" // rgb: 96, 0, 255 + color = "#E60584" // rgb: 96, 0, 255 + taste_description = "a milky ice cream like flavour." overdose_threshold = 12 + metabolization_rate = 0.5 + var/mob/living/carbon/human/H + +/datum/reagent/fermi/BElarger/on_mob_add(mob/living/carbon/M) + var/mob/living/carbon/human/H = M + var/obj/item/organ/genital/breasts/B = H.getorganslot("breasts") + if(!B) + return + var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5) + B.prev_size = B.size + B.cached_size = sizeConv[B.size] + message_admins("init B size: [B.size], prev: [B.prev_size], cache = [B.cached_size], raw: [sizeConv[B.size]]") + +/datum/reagent/fermi/BElarger/on_mob_life(mob/living/carbon/M) //Increases breast size + var/mob/living/carbon/human/H = M + var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts") + if(!B) //If they don't have breasts, give them breasts. + message_admins("No breasts found!") + 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, "Your chest feels warm, tingling with newfound sensitivity.") + M.reagents.remove_reagent(src.id, 5) + B = nB + //If they have them, increase size. If size is comically big, limit movement and rip clothes. + //message_admins("Breast size: [B.size], [B.cached_size], [holder]") + B.cached_size = B.cached_size + 0.1 + 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, "Your breasts begin to strain against your clothes tightly!") + M.adjustOxyLoss(10, 0) + M.apply_damage(2, BRUTE, target) + B.update() + ..() + +/datum/reagent/fermi/BElarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders. + + 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") -/datum/reagent/fermi/BElarger/overdose_start(mob/living/M) //Turns you into a female if male and ODing if(M.gender == MALE) M.gender = FEMALE M.visible_message("[M] suddenly looks more feminine!", "You suddenly feel more feminine!") + if(P) + P.length = P.length - 0.1 + message_admins("lewdsnek size: [P.size], [P.cached_length], [holder]") + P.update() + if(T) + T.Remove(M) + if(!V) + var/obj/item/organ/genital/vagina/nV = new + nV.Insert(M) + V = nV + if(!W) + var/obj/item/organ/genital/womb/nW = new + nW.Insert(M) + W = nW + ..() + +//TODO: failing the reaction creates a penis instead. +/datum/reagent/fermi/PElarger // Due to popular demand...! + name = "Incubus draft" + id = "PElarger" + description = "A volatile collodial mixture derived from various masculine solutions that encourages a larger gentleman's package via a potent testosterone mix, formula derived from a collaboration from Fermicem corp and Doctor Ronald Hyatt, who is well known for his phallus palace." //The toxic masculinity thing is a joke because I thought it would be funny to include it in the reagents, but I don't think many would find it funny? + color = "#888888" // This is greyish..? + taste_description = "chinese dragon powder" + overdose_threshold = 12 //ODing makes you male and removes female genitals + metabolization_rate = 0.5 + + //var/mob/living/carbon/M + //var/mob/living/carbon/human/species/S + /* + var/obj/item/organ/genital/penis/P + var/obj/item/organ/genital/testicles/T + var/obj/item/organ/genital/vagina/V + var/obj/item/organ/genital/womb/W + var/obj/item/organ/genital/breasts/B + */ + var/mob/living/carbon/human/H + +/datum/reagent/fermi/PElarger/on_mob_life(mob/living/carbon/M) //Increases penis size, 5u = +1 inch. + var/mob/living/carbon/human/H = M + var/obj/item/organ/genital/penis/P = M.getorganslot("penis") + if(!P) + message_admins("No penis found!")//They do have a preponderance for escapism, or so I've heard. + var/obj/item/organ/genital/penis/nP = new + nP.Insert(M) + if(nP) + nP.length = 0.2 + to_chat(M, "Your groin feels warm, as you feel a newly forming bulge down below.")//OwO + nP.cached_length = 0.1 + nP.prev_size = 0.1 + M.reagents.remove_reagent(src.id, 5) + P = nP + + P.cached_length = P.cached_length + 0.1 + if (P.cached_length >= 20.5 && P.cached_length < 21) //too low? Yes, 20 is the max + if(H.w_uniform || H.wear_suit) + var/target = M.get_bodypart(BODY_ZONE_CHEST) + to_chat(M, "Your cock begin to strain against your clothes tightly!") + M.apply_damage(5, BRUTE, target) + + P.update() + ..() + +/datum/reagent/fermi/PElarger/overdose_process(mob/living/carbon/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders. + 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") + + message_admins("PE Breast status: [B]") if(M.gender == FEMALE) M.gender = MALE M.visible_message("[M] suddenly looks more masculine!", "You suddenly feel more masculine!") + + if(B) + B.cached_size = B.cached_size - 0.1 + message_admins("Breast size: [B.size], [B.cached_size], [holder]") + B.update() + if(V) + V.Remove(M) + if(W) + W.Remove(M) + if(!T) + var/obj/item/organ/genital/testicles/nT = new + nT.Insert(M) + T = nT + ..() + +/datum/reagent/fermi/astral // Gives you the ability to astral project for a moment! + name = "Astrogen" + id = "astral" + description = "An opalescent murky liquid that is said to distort your soul from your being." + color = "#A080H4" // rgb: , 0, 255 + taste_description = "velvety brambles" + metabolization_rate = 0//Removal is exponential, see code + overdose_threshold = 20 + addiction_threshold = 30 + addiction_stage1_end = 9999//Should never end. + var/mob/living/carbon/origin + var/mob/living/simple_animal/hostile/retaliate/ghost/G = null + var/ODing = FALSE + //var/Svol = volume + +/datum/reagent/fermi/astral/on_mob_life(mob/living/M) // Gives you the ability to astral project for a moment! + M.alpha = 255//Reset addiction + switch(current_cycle) + if(0)//Require a minimum + //var/mob/living/carbon/H = M + //M.alpha = 255 + origin = M + if (G == null) + G = new(get_turf(M.loc)) + G.attacktext = "raises the hairs on the neck of" + G.response_harm = "disrupts the concentration of" + G.response_disarm = "wafts" + G.loot = null + G.maxHealth = 5 + G.health = 5 + G.melee_damage_lower = 0 + G.melee_damage_upper = 0 + G.deathmessage = "disappears as if it was never really there to begin with" + G.incorporeal_move = 1 + G.alpha = 35 + G.name = "[M]'s astral projection" + M.mind.transfer_to(G) + holder.remove_reagent(src.id, current_cycle, FALSE) + ..() + +/datum/reagent/fermi/astral/on_mob_delete(mob/living/carbon/M) + G.mind.transfer_to(origin) + qdel(G) + if(ODing == TRUE) + M.Sleeping(10*volume, 0) + ODing = FALSE + ..() + +/datum/reagent/fermi/astral/overdose_process(mob/living/carbon/M) + ODing = TRUE + if (!G == null) + if(prob(70)) + to_chat(M, "The high conentration of Astrogen in your blood causes you to lapse your concentration for a moment, bringing your projection back to yourself!") + do_teleport(G, M.loc) + ..() + +//Okay so, this might seem a bit too good, but my counterargument is that it'll likely take all round to eventually kill you this way, then you have to be revived without a body. It takes approximately 60-80 minutes to die from this. +/datum/reagent/fermi/astral/addiction_act_stage1(mob/living/carbon/M) + if(prob(65)) + M.alpha = M.alpha - 1 + switch(M.alpha) + if(245) + to_chat(M, "You notice your body starting to disappear, maybe you took too much Astrogen...?") + M.alpha = M.alpha - 1 + if(220) + to_chat(M, "Your addiction is only getting worse as your body disappears. Maybe you should get some more, and fast?") + M.alpha = M.alpha - 1 + if(180) + to_chat(M, "You're starting to get scared as more and more of your body and consciousness begins to fade.") + M.alpha = M.alpha - 1 + if(120) + to_chat(M, "As you lose more and more of yourself, you start to think that maybe shedding your mortality isn't too bad.") + M.alpha = M.alpha - 1 + if(100) + to_chat(M, "You feel a substantial part of your soul flake off into the ethereal world, rendering yourself unclonable.") + M.alpha = M.alpha - 1 + M.add_trait(TRAIT_NOCLONE) + if(80) + to_chat(M, "You feel a thrill shoot through your body as what's left of your mind contemplates the forthcoming oblivion.") + M.alpha = M.alpha - 1 + if(45) + to_chat(M, "The last vestiges of your mind eagerly await your imminent annihilation.") + M.alpha = M.alpha - 1 + if(0 to 30) + to_chat(M, "Your body disperses from existence, as you become one with the universe.") + to_chat(M, "As your body disappears, your consciousness doesn't. Should you find a way back into the mortal coil, your memories of the afterlife remain with you. (At the cost of staying in character while dead.)")//Legalised IC OOK? I have a suspicion this won't make it past the review. At least it'll be presented as a neat idea! If this is unacceptable how about the player can retain living memories across lives if they die in this way only. + M.visible_message("[M] suddenly disappears, their body evaporating from existence, freeing [M] from their mortal coil.") + qdel(M) //Approx 60minutes till death from initial addiction + ..() + +/datum/reagent/fermi/enthrall + name = "MKUltra" + id = "enthral" + description = "Need a description." + color = "#A080H4" // rgb: , 0, 255 + taste_description = "synthetic chocolate, a base tone of alcohol, and high notes of roses" + //metabolization_rate = 0.5 + overdose_threshold = 100 //If this is too easy to get 100u of this, then double it please. + //addiction_threshold = 30 + //addiction_stage1_end = 9999//Should never end. + var/creatorID //ckey + var/creatorGender + var/creatorName + var/mob/living/creator + +/datum/reagent/fermi/enthrall/on_mob_add(mob/living/carbon/M) + ..() + if(!creatorID) + CRASH("Something went wrong in enthral creation") + else if(M.key == creatorID && creatorName == M.real_name) //same name AND same player - same instance of the player. (should work for clones?) + var/obj/item/organ/vocal_cords/Vc = M.getorganslot(ORGAN_SLOT_VOICE) + var/obj/item/organ/vocal_cords/nVc = new /obj/item/organ/vocal_cords/velvet + Vc.Remove(M) + nVc.Insert(M) + qdel(Vc) + to_chat(M, "You feel your vocal chords tingle as your voice comes out in a more sultry tone.") + creator = M + else + M.apply_status_effect(/datum/status_effect/chem/enthrall) + var/datum/status_effect/chem/enthrall/E = M.has_status_effect(/datum/status_effect/chem/enthrall) + E.enthrallID = creatorID + E.enthrallGender = creatorGender + E.master = creator + + +/datum/reagent/fermi/enthrall/on_mob_life(mob/living/carbon/M) + var/datum/status_effect/chem/enthrall/E = M.has_status_effect(/datum/status_effect/chem/enthrall) + E.enthrallTally += 1 + M.adjustBrainLoss(0.1) + ..() + +/datum/reagent/fermi/enthrall/overdose_start(mob/living/carbon/M) + M.add_trait(TRAIT_PACIFISM, "MKUltra") + var/datum/status_effect/chem/enthrall/E = M.has_status_effect(/datum/status_effect/chem/enthrall) + if (!M.has_status_effect(/datum/status_effect/chem/enthrall)) + M.apply_status_effect(/datum/status_effect/chem/enthrall) + E.enthrallID = creatorID + E.enthrallGender = creatorGender + E.master = creator + to_chat(M, "Your mind shatters under the volume of the mild altering chem inside of you, breaking all will and thought completely. Instead the only force driving you now is the instinctual desire to obey and follow [creatorName].") + M.slurring = 100 + M.confused = 100 + E.phase = 4 + E.mental_capacity = 0 + E.customTriggers = list() + +/datum/reagent/fermi/enthrall/overdose_process(mob/living/carbon/M) + M.adjustBrainLoss(0.2) + ..() + +//Requires player to be within vicinity of creator +//bonuses to mood +//gives creator a silver(velvet?) tongue +//Addiction is applied when creator is out of viewer +// + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/reagent/fermi/furranium + name = "Furranium" + id = "furranium" + description = "OwO whats this?" + color = "#H04044" // rgb: , 0, 255 + taste_description = "dewicious degenyewacy" + +/datum/reagent/fermi/furranium/on_mob_life(mob/living/carbon/M) + + switch(current_cycle) + if(1 to 9) + if(prob(20)) + to_chat(M, "Your tongue feels... fluffy") + if(10 to 20) + if(prob(20)) + to_chat(M, "You find yourself unable to supress the desire to meow!") + M.emote("nya") + if(prob(20)) + to_chat(M, "You find yourself unable to supress the desire to howl!") + M.emote("awoo") + if(prob(20)) + var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers + //for(var/victim in seen) + to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]") + if(21) + var/obj/item/organ/tongue/T = M.getorganslot(ORGAN_SLOT_TONGUE) + var/obj/item/organ/tongue/nT = new /obj/item/organ/tongue/OwO + T.Remove(M) + nT.Insert(M) + qdel(T) + if(22 to INFINITY) + if(prob(20)) + to_chat(M, "You find yourself unable to supress the desire to meow!") + M.emote("nya") + if(prob(20)) + to_chat(M, "You find yourself unable to supress the desire to howl!") + M.emote("awoo") + if(prob(20)) + var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers + //for(var/victim in seen) + to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]") + ..() + +/* +/mob/living/simple_animal/hostile/retaliate/ghost +incorporeal_move = 1 +name +alpha = 20 +reduce viewrange? +*/ + /* //Nanite removal +//Writen by Trilby!! /datum/reagent/fermi/naninte_b_gone name = "Naninte bain" id = "naninte_b_gone" description = "A rather simple toxin to small nano machines that will kill them off at a rapid rate well in system." color = "#5a7267" // rgb: 90, 114, 103 overdose_threshold = 25 + v/component/nanites/nan /datum/reagent/fermi/naninte_b_gone/on_mob_life(mob/living/carbon/C) - if(C./datum/component/nanites) - regen_rate = -5.0 - else + var/component/nanites/nane = C.GetComponent(/component/nanites) + if(isnull(nane)) return + nane.regen_rate = -5.0 /datum/reagent/fermi/naninte_b_gone/overdose_start(mob/living/carbon/C) - if(C./datum/component/nanites) - regen_rate = -7.5 - else + var/component/nanites/nane = C.GetComponent(/component/nanites) + if(isnull(nane)) return + nane.regen_rate = -7.5 +*/ + +/* + _________________________________________ +||Fermichem toxic / impure chems here. || +|| || +||_______________________________________|| */ diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm index d4cbf6847a..d8b80a9c91 100644 --- a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm +++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm @@ -23,6 +23,11 @@ FermiExplode = FALSE //If the chemical explodes in a special way ImpureChem = "toxin" //What chemical is produced with an inpure reaction +/datum/chemical_reaction/eigenstate/on_reaction(datum/reagents/holder) + var/location = get_turf(holder.my_atom) + var/datum/reagent/fermi/eigenstate/E = locate(/datum/reagent/fermi/eigenstate) in holder.reagent_list + E.location_created = location + //serum /datum/chemical_reaction/SDGF name = "synthetic-derived growth factor" @@ -31,22 +36,23 @@ required_reagents = list("plasma" = 1, "stable_plasma" = 1, "sugar" = 1) //required_reagents = list("stable_plasma" = 5, "slimejelly" = 5, "synthflesh" = 10, "blood" = 10) //FermiChem vars: - OptimalTempMin = 350 // Lower area of bell curve for determining heat based rate reactions - OptimalTempMax = 500 // Upper end for above - ExplodeTemp = 550 //Temperature at which reaction explodes - OptimalpHMin = 4 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) - OptimalpHMax = 9.5 // Higest value for above - ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase) - CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) - CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value) - CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value) - ThermicConstant = 20 //Temperature change per 1u produced - HIonRelease = 0.01 //pH change per 1u reaction - RateUpLim = 5 //Optimal/max rate possible if all conditions are perfect - FermiChem = TRUE//If the chemical uses the Fermichem reaction mechanics - FermiExplode = FALSE //If the chemical explodes in a special way - ImpureChem = "toxin" //What chemical is produced with an inpure reaction - + OptimalTempMin = 350 // Lower area of bell curve for determining heat based rate reactions + OptimalTempMax = 500 // Upper end for above + ExplodeTemp = 550 // Temperature at which reaction explodes + OptimalpHMin = 4 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 9.5 // Higest value for above + ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase) + CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) + CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value) + CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value) + ThermicConstant = 20 // Temperature change per 1u produced + HIonRelease = 0.01 // pH change per 1u reaction + RateUpLim = 5 // Optimal/max rate possible if all conditions are perfect + FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics + FermiExplode = FALSE // If the chemical explodes in a special way + ImpureChem = "SDGFTox" // What chemical is metabolised with an inpure reaction + InverseChemVal = 0.5 // If the impurity is below 0.5, replace ALL of the chem with InverseChem upon metabolising + InverseChem = "SDZF" // What chem is metabolised when purity is below InverseChemVal /datum/chemical_reaction/BElarger name = "" @@ -90,3 +96,43 @@ FermiChem = TRUE FermiExplode = FALSE ImpureChem = "carpotoxin" + +/datum/chemical_reaction/enthral + name = "need a name" + id = "enthral" + results = list("enthral" = 3) + required_reagents = list("plasma" = 1, "stable_plasma" = 1, "sugar" = 1) + required_catalysts = list("blood" = 1) + //required_reagents = list("stable_plasma" = 5, "slimejelly" = 5, "synthflesh" = 10, "blood" = 10) + //FermiChem vars: + OptimalTempMin = 350 // Lower area of bell curve for determining heat based rate reactions + OptimalTempMax = 500 // Upper end for above + ExplodeTemp = 550 // Temperature at which reaction explodes + OptimalpHMin = 4 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase) + OptimalpHMax = 9.5 // Higest value for above + ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase) + CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst) + CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value) + CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value) + ThermicConstant = 20 // Temperature change per 1u produced + HIonRelease = 0.01 // pH change per 1u reaction + RateUpLim = 5 // Optimal/max rate possible if all conditions are perfect + FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics + FermiExplode = FALSE // If the chemical explodes in a special way + //ImpureChem = "SDGFTox" // What chemical is metabolised with an inpure reaction + //InverseChemVal = 0.5 // If the impurity is below 0.5, replace ALL of the chem with InverseChem upon metabolising + //InverseChem = "SDZF" // What chem is metabolised when purity is below InverseChemVal + + +/datum/chemical_reaction/enthral/on_reaction(datum/reagents/holder) + var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list + var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in holder.reagent_list + if (B.["gender"] == "female") + E.creatorGender = "Mistress" + else + E.creatorGender = "Master" + E.creatorName = B.["real_name"] + E.creatorID = B.["ckey"] + var/mob/living/creator = holder + E.creator = creator + //var/enthrallID = B.get_blood_data() diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi index 2a7342553b..b2496f1fc1 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 937f38fb3c..b50b9e273f 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -274,6 +274,7 @@ #include "code\controllers\subsystem\vore.dm" #include "code\controllers\subsystem\vote.dm" #include "code\controllers\subsystem\weather.dm" +#include "code\controllers\subsystem\processing\chemistry.dm" #include "code\controllers\subsystem\processing\circuit.dm" #include "code\controllers\subsystem\processing\fastprocess.dm" #include "code\controllers\subsystem\processing\fields.dm"