[MIRROR] Reagent Addictions (#10888)

Co-authored-by: Will <7099514+Willburd@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2025-05-27 15:52:49 -07:00
committed by GitHub
parent ca7345cb67
commit dc9ccc60c2
30 changed files with 580 additions and 9 deletions

View File

@@ -1,11 +1,11 @@
// Helper macros to aid in optimizing lazy instantiation of lists.
// All of these are null-safe, you can use them without knowing if the list var is initialized yet
//Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
///Picks from the list, with some safeties, and returns the "default" arg if it fails
#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
// Ensures L is initailized after this point
#define LAZYINITLIST(L) if (!L) L = list()
#define LAZYINITLIST(L) if (!L) { L = list(); }
// Sets a L back to null iff it is empty
#define UNSETEMPTY(L) if (L && !length(L)) L = null
@@ -21,7 +21,7 @@
// Adds I to L, initalizing L if necessary, if I is not already in L
#define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I;
#define LAZYFIND(L, V) L ? L.Find(V) : 0
#define LAZYFIND(L, V) (L ? L.Find(V) : 0)
// Reads I from L safely - Works with both associative and traditional lists.
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null)
@@ -38,6 +38,9 @@
#define LAZYREMOVEASSOC(L, K, V) if(L) { if(L[K]) { L[K] -= V; if(!length(L[K])) L -= K; } if(!length(L)) L = null; }
#define LAZYACCESSASSOC(L, I, K) L ? L[I] ? L[I][K] ? L[I][K] : null : null : null
// Sets a list to null
#define LAZYNULL(L) L = null
// Null-safe L.Cut()
#define LAZYCLEARLIST(L) if(L) { L.Cut(); L = null; }

View File

@@ -266,6 +266,8 @@
#define REAGENT_ID_MENTHOL "menthol"
#define REAGENT_EARTHSBLOOD "Earthsblood"
#define REAGENT_ID_EARTHSBLOOD "earthsblood"
#define REAGENT_ASUSTENANCE "Artificial Sustenance"
#define REAGENT_ID_ASUSTENANCE "a_sustenance"
// Virology

View File

@@ -0,0 +1,25 @@
#define CE_WITHDRAWL "withdrawl" // Withdrawl symptoms
#define ADDICT_NORMAL 1
#define ADDICT_SLOW 2
#define ADDICT_FAST 3
#define ADDICT_POISON 4
#define ADDICT_ALL 5
GLOBAL_LIST_INIT(reagent_addictive_standard,list(REAGENT_ID_AMBROSIAEXTRACT,REAGENT_ID_TALUMQUEM,REAGENT_ID_METHYLPHENIDATE))
GLOBAL_LIST_INIT(reagent_addictive_slow,list(REAGENT_ID_TRAMADOL,REAGENT_ID_OXYCODONE,REAGENT_ID_TRICORDRAZINE,REAGENT_ID_ASUSTENANCE,REAGENT_ID_ETHANOL,REAGENT_ID_NICOTINE,REAGENT_ID_COFFEE))
GLOBAL_LIST_INIT(reagent_addictive_fast,list(REAGENT_ID_HYPERZINE,REAGENT_ID_BLISS))
GLOBAL_LIST_INIT(reagent_addictive_poison,list())
/proc/get_addictive_reagents(var/addict_type)
RETURN_TYPE(/list)
switch(addict_type)
if(ADDICT_NORMAL)
return GLOB.reagent_addictive_standard // Most reagents go here
if(ADDICT_SLOW)
return GLOB.reagent_addictive_slow // Booze, Cigs
if(ADDICT_FAST)
return GLOB.reagent_addictive_fast // Bliss, hyperzine, hardcore drugs
if(ADDICT_POISON)
return GLOB.reagent_addictive_poison // Poisons that use handle_addiction() for unique longterm poisoning
return GLOB.reagent_addictive_standard + GLOB.reagent_addictive_fast + GLOB.reagent_addictive_slow + GLOB.reagent_addictive_poison

View File

@@ -13,6 +13,9 @@
integer = FALSE
default = 1.0
/datum/config_entry/flag/can_addict_during_round
default = FALSE
// FIXME: Unused
///datum/config_entry/flag/revival_pod_plants
// default = TRUE

View File

@@ -1092,10 +1092,10 @@ SUBSYSTEM_DEF(internal_wiki)
SSinternal_wiki.add_icon(data, initial(beaker_path.icon), initial(beaker_path.icon_state), R.color)
// Get internal data
data["description"] = R.description
/* Downstream features
data["addictive"] = 0
if(R.id in addictives)
data["addictive"] = (R.id in fast_addictives) ? 2 : 1
if(R.id in get_addictive_reagents(ADDICT_ALL))
data["addictive"] = TRUE
/* Downstream features
data["industrial_use"] = R.industrial_use
data["supply_points"] = R.supply_conversion_value ? R.supply_conversion_value : 0
var/value = R.supply_conversion_value * REAGENTS_PER_SHEET * SSsupply.points_per_money
@@ -1111,9 +1111,9 @@ SUBSYSTEM_DEF(internal_wiki)
/datum/internal_wiki/page/chemical/get_print()
var/body = ""
body += "<b>Description: </b>[data["description"]]<br>"
/* Downstream features
if(data["addictive"])
body += "<b>DANGER, [data["addictive"] > 1 ? "highly " : ""]addictive.</b><br>"
body += "<b>DANGER, addictive.</b><br>"
/* Downstream features
if(data["industrial_use"])
body += "<b>Industrial Use: </b>[data["industrial_use"]]<br>"
var/tank_size = CARGOTANKER_VOLUME

View File

@@ -308,6 +308,29 @@
dat += span_warning("Anatomical irregularities detected in subject.")
dat += "<br>"
//CHOMPedit end
// Addictions
if(H.get_addiction_to_reagent(REAGENT_ID_ASUSTENANCE) > 0)
dat += span_warning("Biologically unstable, requires [REAGENT_ASUSTENANCE] to function properly.")
dat += "<br>"
for(var/addic in H.get_all_addictions())
if(H.get_addiction_to_reagent(addic) > 0 && (advscan >= 2 || H.get_addiction_to_reagent(addic) <= 120)) // high enough scanner upgrade detects addiction even if not almost withdrawling
var/datum/reagent/R = SSchemistry.chemical_reagents[addic]
if(R.id == REAGENT_ID_ASUSTENANCE)
continue
if(advscan >= 1)
// Shows multiple
if(advscan >= 2 && H.get_addiction_to_reagent(addic) <= 80)
dat += span_warning("Experiencing withdrawls from [R.name], [REAGENT_INAPROVALINE] treatment recomended.")
dat += "<br>"
else
dat += span_warning("Chemical dependance detected: [R.name].")
dat += "<br>"
else
// Shows single
dat += span_warning("Chemical dependance detected.")
dat += "<br>"
break
// Appendix
for(var/obj/item/organ/internal/appendix/a in H.internal_organs)
var/severity = ""
if(a.inflamed > 3)

View File

@@ -244,6 +244,7 @@
M.client.prefs.copy_to(new_character)
new_character.dna.ResetUIFrom(new_character)
new_character.sync_organ_dna()
new_character.sync_addictions()
new_character.key = M.key
new_character.mind.loaded_from_ckey = picked_ckey
new_character.mind.loaded_from_slot = picked_slot

View File

@@ -315,6 +315,7 @@
prob(2);/obj/item/selectable_item/chemistrykit/size,
prob(2);/obj/item/selectable_item/chemistrykit/gender,
prob(2);/obj/item/clothing/gloves/bluespace/emagged,
prob(2);/obj/item/reagent_containers/glass/beaker/vial/sustenance,
prob(1);/obj/item/clothing/suit/storage/vest/heavy/merc,
prob(1);/obj/item/nif/bad,
prob(1);/obj/item/radio_jammer,

View File

@@ -525,6 +525,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character.dna.ResetUIFrom(new_character)
new_character.sync_dna_traits(TRUE) // Traitgenes Sync traits to genetics if needed
new_character.sync_organ_dna()
new_character.sync_addictions() // These are addicitions our profile wants... May as well give them!
new_character.initialize_vessel()
if(inhabit)
new_character.key = player_key

View File

@@ -0,0 +1,162 @@
// Addictions
// Addictions work using a combined counter var. If a reagent is in the list returned by get_addictive_reagents(), it will be added to the addiction_counters[] assoc list by its id.
// If it is present in your body, and you are NOT addicted, it will count DOWNWARD. When it reaches the "addiction proc" you will become addicted. By default you will become addicted at
// ADDICTION_PROC negative points. FASTADDICT_PROC and SLOWADDICT_PROC are also used depending on the reagent's addiction speed. This is to prevent booze being as addictive as bliss.
// If you are addicted to a chem, and have it present in your body, the counter will quickly climb back up to ADDICTION_PEAK. Refreshing your addiction entirely.
// Once the addiction proc is reached you will become addicted. The counter will be set to ADDICTION_PEAK and begin counting DOWNWARD. Each addicted reagent has a handle_addiction() proc. The default
// implimentation of it will perform various effects once you are under 100 points of addiction. Such as vomiting, organ damage, and other bad effects for not feeding the addiction. Check that
// code for exact logic. Inaprovaline is intended to suppress withdrawl effects. Reagents may override the handle_addiction proc to have their own special handling. Like reagents that kill you if you
// do not feed their withdrawls. The handle_addiction proc also handles if you become cured of your addiction! If it returns 0, it will end your addiction.
#define ADDICTION_PROC -4000
#define SLOWADDICT_PROC -8000
#define FASTADDICT_PROC -1000
#define POISONADDICT_PROC -100
#define ADDICTION_PEAK 300
/mob/living/carbon/proc/sync_addictions()
SHOULD_NOT_OVERRIDE(TRUE)
if(!species)
return
if(!species.traits)
return
// Rebuild addictions from traits
LAZYCLEARLIST(addictions)
LAZYCLEARLIST(addiction_counters)
for(var/TR in species.traits)
var/datum/trait/T = GLOB.all_traits[TR]
if(!T)
continue
if(!T.addiction)
continue
addict_to_reagent(T.addiction, TRUE)
/mob/living/proc/handle_addictions()
PROTECTED_PROC(TRUE)
// Empty so it can be overridden
/mob/living/carbon/handle_addictions()
// Don't process during vore stuff... It was originally just absorbed, but lets give some mercy to rp focused servers.
if(isbelly(loc))
return
// All addictions start at 0.
var/list/addict = list()
for(var/datum/reagent/R in bloodstr.reagent_list)
var/reagentid = R.id
if(istype(SSchemistry.chemical_reagents[reagentid], /datum/reagent/ethanol))
reagentid = REAGENT_ID_ETHANOL
if(reagentid in get_addictive_reagents(ADDICT_ALL))
addict.Add(reagentid)
// Only needed for alcohols, will interfere with pills if you detect other things!
for(var/datum/reagent/R in ingested.reagent_list)
var/reagentid = R.id
if(istype(SSchemistry.chemical_reagents[reagentid], /datum/reagent/ethanol))
reagentid = REAGENT_ID_ETHANOL
if(istype(SSchemistry.chemical_reagents[reagentid], /datum/reagent/drink/coffee))
reagentid = REAGENT_ID_COFFEE
if(reagentid in get_addictive_reagents(ADDICT_ALL))
addict.Add(reagentid)
for(var/A in addict)
if(!LAZYFIND(addictions,A))
LAZYADD(addictions,A)
LAZYSET(addiction_counters,A,0)
if(LAZYACCESS(addiction_counters,A) <= 0)
// Build addiction until it procs
if(LAZYFIND(addiction_counters, A))
addiction_counters[A] -= rand(1,3)
if(LAZYACCESS(addiction_counters,A) < SLOWADDICT_PROC)
LAZYSET(addiction_counters,A,SLOWADDICT_PROC)
// Check for addition
if(A in get_addictive_reagents(ADDICT_SLOW))
// Slowest addictions for some medications
if(LAZYACCESS(addiction_counters,A) <= SLOWADDICT_PROC)
addict_to_reagent(A, FALSE)
if(A in get_addictive_reagents(ADDICT_FAST))
// quickly addict to these drugs, bliss, oxyco etc
if(LAZYACCESS(addiction_counters,A) <= FASTADDICT_PROC)
addict_to_reagent(A, FALSE)
else
// slower addiction over a longer period, cigs and painkillers mostly
if(LAZYACCESS(addiction_counters,A) <= ADDICTION_PROC)
addict_to_reagent(A, FALSE)
else
// satiating addiction we already have
if(LAZYACCESS(addiction_counters,A) < ADDICTION_PEAK)
if(LAZYACCESS(addiction_counters,A) < 100)
LAZYSET(addiction_counters,A,100)
var/datum/reagent/RR = SSchemistry.chemical_reagents[A]
var/message = RR.addiction_refresh_message()
if(message)
to_chat(src, message)
if(LAZYFIND(addiction_counters, A))
addiction_counters[A] += rand(8,13)
// For all counters above 100, count down
// For all under 0, count up to 0 randomly, reducing initial addiction buildup if you didn't proc it
if(LAZYLEN(addictions))
var/C = pick(addictions)
// return to normal... we didn't haven't been addicted yet, but we shouldn't become addicted instantly next time if it's been a few hours!
if(LAZYACCESS(addiction_counters,C) < 0)
if(prob(15) && LAZYFIND(addiction_counters, C))
addiction_counters[C] += 1
// proc reagent's withdrawl
var/datum/reagent/RE = SSchemistry.chemical_reagents[C]
var/addict_counter_before = LAZYACCESS(addiction_counters,C)
if(LAZYACCESS(addiction_counters,C) > 0)
LAZYSET(addiction_counters,C,RE.handle_addiction(src,species.reagent_tag)) // withdrawl can modify the value however it deems fit as you are affected by it
// remove if finished
if(LAZYACCESS(addiction_counters,C) == 0)
var/message = RE.addiction_cure_message()
if(addict_counter_before > 0 && message) // Only show cure message if we were addicted to it prior!
to_chat(src, message)
LAZYREMOVE(addictions,C)
LAZYREMOVE(addiction_counters,C)
/mob/living/carbon/proc/addict_to_reagent(var/reagentid, var/round_start)
PRIVATE_PROC(TRUE)
SHOULD_NOT_OVERRIDE(TRUE)
if(isSynthetic()) // Should this be allowed? I guess you can roleplay Bender as an FBP? Trait in the future?
return
// Check if serverconfig allows addiction during the round. Otherwise only allow spawning with addictions
var/allow_addiction = round_start || CONFIG_GET(flag/can_addict_during_round)
if(!allow_addiction)
return
if(!LAZYFIND(addictions,reagentid))
LAZYADD(addictions,reagentid)
LAZYSET(addiction_counters,reagentid,ADDICTION_PEAK)
/mob/living/carbon/proc/get_addiction_to_reagent(var/reagentid) // returns counter's value or 0
SHOULD_NOT_OVERRIDE(TRUE)
return LAZYACCESS(addiction_counters,reagentid)
/mob/living/carbon/proc/refresh_all_addictions()
SHOULD_NOT_OVERRIDE(TRUE)
if(!addiction_counters)
return
for(var/reagentid in addiction_counters)
LAZYSET(addiction_counters,reagentid,ADDICTION_PEAK)
/mob/living/carbon/proc/clear_all_addictions() // This is probably not a good idea to call as some addictions are intended to be uncurable, like artificial sustenance.
SHOULD_NOT_OVERRIDE(TRUE)
LAZYCLEARLIST(addictions)
LAZYCLEARLIST(addiction_counters)
/mob/living/carbon/proc/get_all_addictions()
RETURN_TYPE(/list)
SHOULD_NOT_OVERRIDE(TRUE)
var/list/addict = list()
if(addiction_counters)
for(var/key in addiction_counters)
addict.Add(key)
return addict
#undef ADDICTION_PROC
#undef SLOWADDICT_PROC
#undef FASTADDICT_PROC
#undef POISONADDICT_PROC
#undef ADDICTION_PEAK

View File

@@ -24,6 +24,9 @@
var/does_not_breathe = 0 //Used for specific mobs that can't take advantage of the species flags (changelings)
VAR_PROTECTED/list/addictions = null // contains currently addicted chem reagent IDs
VAR_PROTECTED/list/addiction_counters = null // contains counters by reagent ID
//these two help govern taste. The first is the last time a taste message was shown to the plaer.
//the second is the message in question.
var/last_taste_time = 0

View File

@@ -761,3 +761,59 @@
cost = 0
category = 0
custom_only = FALSE
// Addictions
/datum/trait/neutral/addiction_alcohol
name = "Addiction - Alcohol"
desc = "You have become chemically dependant to any alcoholic drink, and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_ETHANOL
custom_only = FALSE
hidden = TRUE //Disabled on Virgo
/datum/trait/neutral/addiction_bliss
name = "Addiction - " + REAGENT_BLISS
desc = "You have become chemically dependant to " + REAGENT_BLISS + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_BLISS
custom_only = FALSE
hidden = TRUE //Disabled on Virgo
/datum/trait/neutral/addiction_coffee
name = "Addiction - " + REAGENT_COFFEE
desc = "You have become chemically dependant to " + REAGENT_COFFEE + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_COFFEE
custom_only = FALSE
/datum/trait/neutral/addiction_hyper
name = "Addiction - " + REAGENT_HYPERZINE
desc = "You have become chemically dependant to " + REAGENT_HYPERZINE + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_HYPERZINE
custom_only = FALSE
hidden = TRUE //Disabled on Virgo
/datum/trait/neutral/addiction_nicotine
name = "Addiction - " + REAGENT_NICOTINE
desc = "You have become chemically dependant to " + REAGENT_NICOTINE + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_NICOTINE
custom_only = FALSE
/datum/trait/neutral/addiction_oxy
name = "Addiction - " + REAGENT_OXYCODONE
desc = "You have become chemically dependant to " + REAGENT_OXYCODONE + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_OXYCODONE
custom_only = FALSE
hidden = TRUE //Disabled on Virgo
/datum/trait/neutral/addiction_painkiller
name = "Addiction - Pain Killers"
desc = "You have become chemically dependant to " + REAGENT_TRAMADOL + ", and need to regularly consume it or suffer withdrawals."
addiction = REAGENT_ID_TRAMADOL
custom_only = FALSE
hidden = TRUE //Disabled on Virgo
/datum/trait/neutral/addiction_asustenance
name = "Unstable Vat Grown Body"
desc = "You are chemically dependant to " + REAGENT_ASUSTENANCE + ", and need to regularly consume it or your body decays."
addiction = REAGENT_ID_ASUSTENANCE
custom_only = FALSE
hidden = TRUE //Disabled on Virgo

View File

@@ -34,6 +34,7 @@
var/mutation = 0 // Mutation to give (or 0)
var/disability = 0 // Disability to give (or 0)
var/sdisability = 0 // SDisability to give (or 0)
var/addiction = null // Addiction reagent, null otherwise
var/activation_message = null // If not null, shows a message when activated as a gene
var/deactivation_message = null // If not null, shows a message when deactivated as a gene
var/list/primitive_expression_messages=list() // Monkey's custom emote when they have this gene!

View File

@@ -76,6 +76,7 @@
if(handle_regular_status_updates()) // Status & health update, are we dead or alive etc.
handle_disabilities() // eye, ear, brain damages
handle_addictions() // Dwugs
handle_statuses() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
update_canmove()

View File

@@ -434,6 +434,7 @@
new_character.dna.b_type = client.prefs.b_type
new_character.sync_dna_traits(TRUE) // Traitgenes Sync traits to genetics if needed
new_character.sync_organ_dna()
new_character.sync_addictions() // Handle round-start addictions
new_character.initialize_vessel()
for(var/lang in client.prefs.alternate_languages)

View File

@@ -20,6 +20,11 @@
else if(is_broken())
owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
// General organ damage from withdraw, kidneys do a lot of the work
if(prob(70) && owner.chem_effects[CE_WITHDRAWL])
take_damage(owner.chem_effects[CE_WITHDRAWL] * 0.05 * PROCESS_ACCURACY, prob(1)) // Chance to warn them
owner.adjustToxLoss(owner.chem_effects[CE_WITHDRAWL] * 0.3 * PROCESS_ACCURACY)
/obj/item/organ/internal/kidneys/handle_organ_proc_special()
. = ..()

View File

@@ -43,6 +43,15 @@
if(filter_effect < 3)
owner.adjustToxLoss(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY)
// General organ damage from withdraw
if(prob(20) && owner.chem_effects[CE_WITHDRAWL])
take_damage(owner.chem_effects[CE_WITHDRAWL] * 0.05 * PROCESS_ACCURACY, prob(1)) // Chance to warn them
if(filter_effect < 2) //Withdrawls intensified
owner.adjustToxLoss(owner.chem_effects[CE_WITHDRAWL] * 0.2 * PROCESS_ACCURACY)
if(filter_effect < 3)
owner.adjustToxLoss(owner.chem_effects[CE_WITHDRAWL] * 0.1 * PROCESS_ACCURACY)
/obj/item/organ/internal/liver/handle_germ_effects()
. = ..() //Up should return an infection level as an integer
if(!.) return

View File

@@ -40,6 +40,11 @@
if(src.damage < 0)
src.damage = 0
// General organ damage from withdraw
if(prob(20) && owner.chem_effects[CE_WITHDRAWL])
take_damage(owner.chem_effects[CE_WITHDRAWL] * 0.05 * PROCESS_ACCURACY, prob(1)) // Chance to warn them
owner.adjustToxLoss(owner.chem_effects[CE_WITHDRAWL] * 0.2 * PROCESS_ACCURACY)
/obj/item/organ/internal/spleen/handle_germ_effects()
. = ..() //Up should return an infection level as an integer
if(!.) return

View File

@@ -85,6 +85,9 @@
SSinternal_wiki.add_icon(subdata, initial(beaker_path.icon), initial(beaker_path.icon_state), R.color)
// Get internal data
subdata["description"] = R.description
subdata["addictive"] = 0
if(R.id in get_addictive_reagents(ADDICT_ALL))
subdata["addictive"] = TRUE
subdata["flavor"] = R.taste_description
subdata["allergen"] = SSinternal_wiki.assemble_allergens(R.allergen_type)
subdata["beakerAmount"] = found_reagents[ID]

View File

@@ -1248,3 +1248,10 @@
result = REAGENT_ID_PROTEIN
required_reagents = list(REAGENT_ID_ENZYME = 1, REAGENT_ID_SPIDERTOXIN = 1, REAGENT_ID_SIFSAP = 1)
result_amount = 1
/decl/chemical_reaction/instant/artificial_sustenance
name = REAGENT_ASUSTENANCE
id = REAGENT_ID_ASUSTENANCE
result = REAGENT_ID_ASUSTENANCE
required_reagents = list(REAGENT_ID_NUTRIMENT = 1, REAGENT_ID_MUTAGEN = 1, REAGENT_ID_PHORON = 1)
result_amount = 1

View File

@@ -431,3 +431,7 @@
matter = list(MAT_WOOD = 50)
drop_sound = 'sound/items/drop/wooden.ogg'
pickup_sound = 'sound/items/pickup/wooden.ogg'
/obj/item/reagent_containers/glass/beaker/vial/sustenance
name = "vial (artificial sustenance)"
prefill = list(REAGENT_ID_ASUSTENANCE = 30)

View File

@@ -214,6 +214,75 @@
to_chat(usr, span_notice("The solution dissolves the ink on the book."))
return
/datum/reagent/ethanol/handle_addiction(var/mob/living/carbon/M, var/alien)
// A copy of the base with withdrawl, but with much less effects, such as vomiting.
var/current_addiction = M.get_addiction_to_reagent(id)
var/realistic_addiction = FALSE //DEFAULT set to FALSE. Toggle to TRUE for a more realistic addiction with potentially fatal side effects.
// slow degrade
if(prob(8))
current_addiction -= 1
// withdrawl mechanics
if(!(CE_STABLE in M.chem_effects)) //Without stabilization effects
if(current_addiction <= 60)
M.pulse = PULSE_2FAST
if(prob(2))
if(current_addiction < 90 && prob(10))
to_chat(M, span_warning("[pick("You feel miserable.","You feel nauseous.","You get a raging headache.")]"))
M.adjustHalLoss(7)
M.make_jittery(25) //Restlessness.
else if(current_addiction <= 20)
to_chat(M, span_danger("You feel absolutely awful. You need some some liquor. Now."))
if(realistic_addiction && prob(20)) //1 in 5 on a 1 in 50, so 1 in 250 chance. DTs
to_chat(src, span_red("You have a seizure!"))
for(var/mob/O in viewers(M, null))
if(O == src)
continue
O.show_message(span_danger("[M] starts having a seizure!"), 1)
M.Paralyse(10)
M.make_jittery(1000)
else if(current_addiction <= 50)
to_chat(M, span_warning("You're really craving some alcohol. You feel nauseated."))
if(realistic_addiction)
M.emote("vomit")
M.AdjustConfused(10) // Disorientation.
else if(current_addiction <= 100)
to_chat(M, span_notice("You're feeling the need for some booze."))
// effects
if(current_addiction < 60 && prob(20)) // 1 in 50 x 1 in 5 = 1 in 250
M.emote(pick("pale","shiver","twitch"))
M.drop_item() //Hand tremors
if(realistic_addiction)
M.add_chemical_effect(CE_WITHDRAWL, rand(4,10) * REM)
else //Stabilization effects
if(current_addiction <= 60)
M.pulse = PULSE_FAST
if(prob(2))
if(current_addiction < 90 && prob(10))
to_chat(M, span_warning("[pick("You feel a light throbbing in your head.","Your stomach feels upset.","Your .")]"))
M.adjustHalLoss(3)
M.make_jittery(10) //Restlessness.
else if(current_addiction <= 20)
to_chat(M, span_warning("You feel nauseated."))
if(realistic_addiction)
M.emote("vomit")
M.AdjustConfused(10) // Disorientation.
else if(current_addiction <= 50)
to_chat(M, span_warning("Your head throbs and the room spins."))
if(realistic_addiction)
M.AdjustConfused(3) // Disorientation.
else if(current_addiction <= 100)
to_chat(M, span_notice("A drink would be nice."))
// effects
if(current_addiction < 60 && prob(5)) // 1 in 50 x 1 in 20 = 1 in 1000
M.emote(pick("pale","shiver","twitch"))
M.drop_item() //Hand tremors
if(current_addiction <= 0) //safety
current_addiction = 0
return current_addiction
/datum/reagent/ethanol/addiction_cure_message()
return span_notice("You feel your symptoms end, you no longer feel the craving for alcohol.")
/datum/reagent/fluorine
name = REAGENT_FLUORINE
id = REAGENT_ID_FLUORINE

View File

@@ -210,6 +210,37 @@
color = "#181818"
high_messages = FALSE
/datum/reagent/drugs/nicotine/handle_addiction(var/mob/living/carbon/M, var/alien)
// A copy of the base with withdrawl, but with much less effects, such as vomiting.
var/current_addiction = M.get_addiction_to_reagent(id)
// slow degrade
if(prob(8))
current_addiction -= 1
// withdrawl mechanics
if(prob(2))
if(!(CE_STABLE in M.chem_effects)) //Without stabilization effects
if(current_addiction < 90 && prob(10))
to_chat(M, span_warning("[pick("You feel miserable.","You feel nauseous.","You get a raging headache.")]"))
M.adjustHalLoss(5)
else if(current_addiction <= 20)
to_chat(M, span_danger("You feel absolutely awful. You need some [name]. Now."))
if(prob(10)) //1 in 10 on top of a 1 in 50, so thats a 1 in 500 chance. Seems low enough to not be disruptive.
M.emote("vomit")
else if(current_addiction <= 50)
to_chat(M, span_warning("You're really craving some [name]."))
else if(current_addiction <= 100)
to_chat(M, span_notice("You're feeling the need for some [name]."))
// effects
if(current_addiction < 60 && prob(20))
M.emote(pick("pale","shiver","twitch", "cough"))
else
if(current_addiction < 90 && prob(10))
to_chat(M, span_warning("[pick("You feel a slight craving for some [name].","Your stomach feels slightly upset.","You feel a slight pain in your head.")]"))
if(current_addiction <= 0) //safety
current_addiction = 0
return current_addiction
/*///////////////////////////////////////////////////////////////////////////
/// PSYCHIATRIC DRUGS /////
/// /////

View File

@@ -1634,6 +1634,28 @@
//M.apply_effect(3, STUTTER) //VOREStation Edit end
M.make_jittery(5)
/datum/reagent/drink/coffee/handle_addiction(var/mob/living/carbon/M, var/alien)
// A copy of the base with withdrawl, but with much less effects, no vomiting and sometimes halloss
var/current_addiction = M.get_addiction_to_reagent(id)
// slow degrade
if(prob(8))
current_addiction -= 1
// withdrawl mechanics
if(prob(2))
if(current_addiction < 90 && prob(10))
to_chat(M, span_warning("[pick("You feel miserable.","You feel sluggish.","You get a small headache.")]"))
M.adjustHalLoss(2)
else if(current_addiction <= 50)
to_chat(M, span_warning("You're really craving some [name]."))
else if(current_addiction <= 100)
to_chat(M, span_notice("You're feeling the need for some [name]."))
// effects
if(current_addiction < 60 && prob(20))
M.emote(pick("pale","shiver","twitch"))
if(current_addiction <= 0) //safety
current_addiction = 0
return current_addiction
/datum/reagent/drink/coffee/icecoffee
name = REAGENT_ICECOFFEE
id = REAGENT_ID_ICECOFFEE

View File

@@ -1425,3 +1425,64 @@
M.druggy = max(M.druggy, 20)
M.hallucination = max(M.hallucination, 3)
M.adjustBrainLoss(1 * removed) //your life for your mind. The Earthmother's Tithe.
// Vat clone stablizer
/datum/reagent/acid/artificial_sustenance
name = REAGENT_ASUSTENANCE
id = REAGENT_ID_ASUSTENANCE
description = "A drug used to stablize vat grown bodies. Often used to control the lifespan of biological experiments." // Who else remembers Cybersix?
taste_description = "burning metal"
reagent_state = LIQUID
color = "#31d422"
overdose = 15
overdose_mod = 1.2
scannable = 1
/datum/reagent/acid/artificial_sustenance/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
// You need me...
if(M.get_addiction_to_reagent(REAGENT_ID_ASUSTENANCE))
return
// Continue to acid damage, no changes on injection or splashing, as this is meant to be edible only to those pre-addicted to it! Not a snowflake acid that doesn't hurt you!
. = ..()
/datum/reagent/acid/artificial_sustenance/handle_addiction(var/mob/living/carbon/M, var/alien)
// A copy of the base with withdrawl, but with death, and different messages
var/current_addiction = M.get_addiction_to_reagent(id)
// slow degrade
if(prob(2))
current_addiction -= 1
// withdrawl mechanics
if(prob(2))
if(current_addiction <= 40)
to_chat(M, span_danger("You're dying for some [name]!"))
else if(current_addiction <= 60)
to_chat(M, span_warning("You're really craving some [name]."))
else if(current_addiction <= 100)
to_chat(M, span_notice("You're feeling the need for some [name]."))
// effects
if(current_addiction < 60 && prob(20))
M.emote(pick("pale","shiver","twitch"))
// Agony and death!
if(current_addiction <= 20)
if(prob(12))
M.adjustToxLoss( rand(1,4) )
M.adjustBruteLoss( rand(1,4) )
M.adjustOxyLoss( rand(1,4) )
// proc side effect
if(current_addiction <= 30)
if(prob(3))
M.Weaken(2)
M.emote("vomit")
M.add_chemical_effect(CE_WITHDRAWL, rand(9,14) * REM)
else if(current_addiction <= 40)
if(prob(3))
M.emote("vomit")
M.add_chemical_effect(CE_WITHDRAWL, rand(5,9) * REM)
else if(current_addiction <= 50)
if(prob(2))
M.emote("vomit")
// Sustenance requirements cannot be escaped!
if(current_addiction <= 0)
current_addiction = 40
return current_addiction

View File

@@ -0,0 +1,64 @@
/datum/reagent/proc/handle_addiction(var/mob/living/carbon/M, var/alien)
// overridable proc for custom withdrawl behaviors, standard is chills, cravings, vomiting, weakness and CE_WITHDRAWL organ damage
if(alien == IS_DIONA)
return 0
var/current_addiction = M.get_addiction_to_reagent(id)
// slow degrade
if(prob(8))
current_addiction -= 1
// withdrawl mechanics
if(current_addiction < 10)
if(prob(2))
M.Weaken(1)
else if(current_addiction > 10)
if(CE_STABLE in M.chem_effects) // Inaprovaline can be used to treat addiction
if(prob(1))
switch(rand(1,3))
if(1)
to_chat(M, span_notice("You feel sluggish."))
if(2)
to_chat(M, span_notice("You feel awful."))
if(3)
to_chat(M, span_notice("Everything feels sore."))
// effects
if(current_addiction < 100 && prob(10))
M.emote(pick("pale","shiver","twitch"))
if(current_addiction <= 60)
if(prob(1))
M.Weaken(2)
if(prob(5) && prob(1))
M.emote("vomit")
else
// send a message to notify players
if(prob(2))
if(current_addiction <= 40)
to_chat(M, span_danger("You're dying for some [name]!"))
else if(current_addiction <= 60)
to_chat(M, span_warning("You're really craving some [name]."))
else if(current_addiction <= 100)
to_chat(M, span_notice("You're feeling the need for some [name]."))
// effects
if(current_addiction < 100 && prob(20))
M.emote(pick("pale","shiver","twitch"))
// proc side effect
if(current_addiction <= 30)
if(prob(3))
M.Weaken(2)
M.emote("vomit")
M.add_chemical_effect(CE_WITHDRAWL, rand(2,4) * REM)
else if(current_addiction <= 50)
if(prob(3))
M.emote("vomit")
M.add_chemical_effect(CE_WITHDRAWL, rand(1,3) * REM)
else if(current_addiction <= 70)
if(prob(2))
M.emote("vomit")
if(current_addiction <= 0) //safety
current_addiction = 0
return current_addiction
/datum/reagent/proc/addiction_cure_message()
return span_notice("You feel your symptoms end, you no longer feel the craving for [name].")
/datum/reagent/proc/addiction_refresh_message()
return span_notice("You feel rejuvenated as the [name] rushes through you.")

View File

@@ -157,6 +157,7 @@
new_character.dna.ResetUIFrom(new_character)
new_character.sync_dna_traits(TRUE) // Traitgenes Sync traits to genetics if needed
new_character.sync_organ_dna()
new_character.sync_addictions() // These are addicitions our profile wants... May as well give them!
new_character.initialize_vessel()
if(ghost.mind)
ghost.mind.transfer_to(new_character)

View File

@@ -146,6 +146,7 @@ Please do not abuse this ability.
new_character.dna.ResetUIFrom(new_character)
new_character.sync_dna_traits(TRUE) // Traitgenes Sync traits to genetics if needed
new_character.sync_organ_dna()
new_character.sync_addictions()
new_character.initialize_vessel()
new_character.key = player_key
if(new_character.mind)

View File

@@ -69,6 +69,9 @@ FOOTSTEP_VOLUME 45
## Whether or not humans show an area message when they die.
SHOW_HUMAN_DEATH_MESSAGE
## If chemicals and drinks can give addictions during a round. Otherwise they are only accessible through traits or exotic effects.
#CAN_ADDICT_DURING_ROUND
## Alert level descriptions
ALERT_DESC_GREEN All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced.

View File

@@ -33,6 +33,7 @@
#include "code\__defines\_reagents_ch.dm"
#include "code\__defines\_tick.dm"
#include "code\__defines\action.dm"
#include "code\__defines\addictions.dm"
#include "code\__defines\admin.dm"
#include "code\__defines\admin_ch.dm"
#include "code\__defines\admin_verb.dm"
@@ -3250,6 +3251,7 @@
#include "code\modules\mob\living\bot\mulebot_vr.dm"
#include "code\modules\mob\living\bot\secbot.dm"
#include "code\modules\mob\living\bot\SLed209bot.dm"
#include "code\modules\mob\living\carbon\addictions.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
#include "code\modules\mob\living\carbon\carbon_defense.dm"
@@ -4328,6 +4330,7 @@
#include "code\modules\reagents\reagents\virology.dm"
#include "code\modules\reagents\reagents\vore_ch.dm"
#include "code\modules\reagents\reagents\vore_vr.dm"
#include "code\modules\reagents\reagents\withdrawl.dm"
#include "code\modules\recycling\conveyor2.dm"
#include "code\modules\recycling\disposal-construction.dm"
#include "code\modules\recycling\disposal.dm"