Skip to content

Commit

Permalink
Chemical addictions
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorDinamit committed Jul 16, 2023
1 parent 55bc70f commit db8adae
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 1 deletion.
3 changes: 3 additions & 0 deletions baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@
#include "code\controllers\evacuation\evacuation_predicate.dm"
#include "code\controllers\evacuation\evacuation_shuttle.dm"
#include "code\controllers\evacuation\~evac.dm"
#include "code\controllers\subsystems\addiction.dm"
#include "code\controllers\subsystems\ai.dm"
#include "code\controllers\subsystems\aifast.dm"
#include "code\controllers\subsystems\air.dm"
Expand Down Expand Up @@ -2871,6 +2872,8 @@
#include "code\modules\reagents\Chemistry-Sublimator.dm"
#include "code\modules\reagents\reagent_containers.dm"
#include "code\modules\reagents\reagent_dispenser.dm"
#include "code\modules\reagents\addiction\_addiction.dm"
#include "code\modules\reagents\addiction\alcohol.dm"
#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Core.dm"
#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Dispenser.dm"
#include "code\modules\reagents\Chemistry-Reagents\Chemistry-Reagents-Drinks.dm"
Expand Down
11 changes: 11 additions & 0 deletions code/__defines/chemistry.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,14 @@

#define HANDLE_REACTIONS(_reagents) SSchemistry.active_holders[_reagents] = TRUE
#define UNQUEUE_REACTIONS(_reagents) SSchemistry.active_holders -= _reagents

/// Minimum requirement for addiction buzz to be met
#define MIN_ADDICTION_REAGENT_AMOUNT 2
#define MAX_ADDICTION_POINTS 1000

/// Addiction start/ends
#define WITHDRAWAL_STAGE1_START_CYCLE 1
#define WITHDRAWAL_STAGE1_END_CYCLE 60
#define WITHDRAWAL_STAGE2_START_CYCLE 61
#define WITHDRAWAL_STAGE2_END_CYCLE 120
#define WITHDRAWAL_STAGE3_START_CYCLE 121
3 changes: 3 additions & 0 deletions code/__defines/lists.dm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } }
// Adds I to L, initalizing L if necessary
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
#define LAZYADDASSOC(L, K, V) if(!L) { L = list(); } L[K] += V;
/// This is used to add onto lazy assoc list when the value you're adding is a /list/. This one has extra safety over lazyaddassoc because the value could be null (and thus cant be used to += objects)
#define LAZYADDASSOCLIST(L, K, V) if(!L) { L = list(); } L[K] += list(V);
// Insert I into L at position X, initalizing L if necessary
#define LAZYINSERT(L, I, X) if(!L) { L = list(); } L.Insert(X, I);
// Adds I to L, initalizing L if necessary, if I is not already in L
Expand Down
5 changes: 5 additions & 0 deletions code/_helpers/medical_scans.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
reagent["scannable"] = R.scannable
scan["reagents"] += list(reagent)

scan["addictions"] = H.active_addictions

scan["external_organs"] = list()

for(var/obj/item/organ/external/E in H.organs)
Expand Down Expand Up @@ -266,6 +268,9 @@
if(other_reagent)
dat += "<tr><td colspan='2'><span class='average'>Warning: Unknown substance detected in subject's blood.</span></td></tr>"

for(var/datum/addiction/addiction_type as anything in scan["addictions"])
dat += "<tr><td colspan='2'><span class='average'>Subject is addicted to [initial(addiction_type.name)]</span></td></tr>"

//summary for the medically disinclined.
/*
<tr><td colspan='2'>You see a lot of numbers and abbreviations here, but you have no clue what any of this means.</td></tr>
Expand Down
19 changes: 19 additions & 0 deletions code/controllers/subsystems/addiction.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*!
This subsystem mostly exists to populate and manage the withdrawal singletons.
*/

SUBSYSTEM_DEF(addiction)
name = "Addiction"
flags = SS_NO_FIRE
/// Dictionary of addiction.type || addiction ref
var/list/all_addictions = list()

/datum/controller/subsystem/addiction/Initialize(timeofday)
InitializeAddictions()
return ..()

///Ran on initialize, populates the addiction dictionary
/datum/controller/subsystem/addiction/proc/InitializeAddictions()
for(var/type in subtypesof(/datum/addiction))
var/datum/addiction/ref = new type
all_addictions[type] = ref
14 changes: 14 additions & 0 deletions code/modules/mob/living/carbon/carbon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
R.clear_reagents()
set_nutrition(400)
set_hydration(400)
for(var/addiction_type in subtypesof(/datum/addiction))
RemoveAddictionPoints(addiction_type, MAX_ADDICTION_POINTS) //Remove the addiction!
..()

/mob/living/carbon/Move(NewLoc, direct)
Expand Down Expand Up @@ -514,3 +516,15 @@
to_chat(src, "<span class='warning'>You are no longer running on internals.</span>")
if(internals)
internals.icon_state = "internal[!!internal]"

/// Adds addiction points to the specified addiction
/mob/living/carbon/proc/AddAddictionPoints(type, amount)
LAZYSET(addiction_points, type, min(LAZYACCESS(addiction_points, type) + amount, MAX_ADDICTION_POINTS))
var/datum/addiction/affected_addiction = SSaddiction.all_addictions[type]
return affected_addiction.OnGainAddictionPoints(src)

/// Adds addiction points to the specified addiction
/mob/living/carbon/proc/RemoveAddictionPoints(type, amount)
LAZYSET(addiction_points, type, max(LAZYACCESS(addiction_points, type) - amount, 0))
var/datum/addiction/affected_addiction = SSaddiction.all_addictions[type]
return affected_addiction.OnLoseAddictionPoints(src)
5 changes: 5 additions & 0 deletions code/modules/mob/living/carbon/carbon_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@
var/stasis_value

var/player_triggered_sleeping = 0

/// Assoc list of addiction values, key is the type of withdrawal (as singleton type), and the value is the amount of addiction points (as number)
var/list/addiction_points
/// Assoc list of key active addictions and value amount of cycles that it has been active.
var/list/active_addictions
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/human/human_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,4 @@

var/list/descriptors

var/last_smelt = 0
var/last_smelt = 0
5 changes: 5 additions & 0 deletions code/modules/mob/living/carbon/life.dm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

handle_viruses()

// Handle addictions
for(var/key in addiction_points)
var/datum/addiction/addiction = SSaddiction.all_addictions[key]
addiction.ProcessAddiction(src)

. = 1

if(!client && (!mind || ghosted) && species)
Expand Down
6 changes: 6 additions & 0 deletions code/modules/reagents/Chemistry-Reagents.dm
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@

var/should_admin_log = FALSE

/// Assoc list with key type of addiction this reagent feeds, and value amount of addiction points added per unit of reagent metabolzied (which means * REM every life())
var/list/addiction_types = null

/datum/reagent/New(var/datum/reagents/holder)
if(!istype(holder))
CRASH("Invalid reagents holder: [log_info_line(holder)]")
Expand Down Expand Up @@ -98,6 +101,9 @@
if(volume > overdose_threshold)
overdose(M, alien)

for(var/addiction in addiction_types)
M.AddAddictionPoints(addiction, addiction_types[addiction] * REM)

//determine the metabolism rate
var/removed = metabolism
if(ingest_met && (location == CHEM_INGEST))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@
glass_desc = "A well-known alcohol with a variety of applications."
value = DISPENSER_REAGENT_VALUE

/datum/reagent/ethanol/New()
addiction_types = list(/datum/addiction/alcohol = 0.05 * strength)
return ..()

/datum/reagent/ethanol/touch_mob(var/mob/living/L, var/amount)
if(istype(L))
L.adjust_fire_stacks(amount / 15)
Expand Down
118 changes: 118 additions & 0 deletions code/modules/reagents/addiction/_addiction.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/// Base class for addiction, handles when you become addicted and what the effects of that are. By default you become addicted when you hit a certain threshold, and stop being addicted once you go below another one.
/datum/addiction
/// Name of this addiction
var/name = "Unknown Addiction"
/// Higher threshold, when you start being addicted
var/addiction_gain_threshold = 600
/// Lower threshold, when you stop being addicted
var/addiction_loss_threshold = 400
/// Messages for each stage of addictions.
var/list/withdrawal_stage_messages = list()
/// Rates at which you lose addiction (in units/second) if you are not on the drug at that time per stage
var/addiction_loss_per_stage = list(0.5, 0.5, 1, 1.5)

/// Called when you gain addiction points somehow. Takes a carbon mob as argument and sees if you gained the addiction
/datum/addiction/proc/OnGainAddictionPoints(mob/living/carbon/victim)
var/current_addiction_point_amount = victim.addiction_points[type]
if(current_addiction_point_amount < addiction_gain_threshold) //Not enough to become addicted
return
if(LAZYACCESS(victim.active_addictions, type)) //Already addicted
return
BecomeAddicted(victim)

///Called when you become addicted
/datum/addiction/proc/BecomeAddicted(mob/living/carbon/victim)
LAZYSET(victim.active_addictions, type, 1) // Start at first cycle.
log_game("[key_name(victim)] has become addicted to [name].")

/// Called when you lose addiction poitns somehow. Takes a mind as argument and sees if you lost the addiction
/datum/addiction/proc/OnLoseAddictionPoints(mob/living/carbon/victim)
var/current_addiction_point_amount = victim.addiction_points[type]
if(!LAZYACCESS(victim.active_addictions, type)) // Not addicted
return FALSE
if(current_addiction_point_amount > addiction_loss_threshold) // Not enough to stop being addicted
return FALSE
LoseAddiction(victim)
return TRUE

/datum/addiction/proc/LoseAddiction(mob/living/carbon/victim)
to_chat(victim, SPAN_NOTICE("You feel like you've gotten over your need for drugs."))
LAZYREMOVE(victim.active_addictions, type)


/datum/addiction/proc/ProcessAddiction(mob/living/carbon/victim, delta_time = 2)
var/current_addiction_cycle = LAZYACCESS(victim.active_addictions, type) // If this is null, we're not addicted
var/on_drug_of_this_addiction = FALSE
for(var/datum/reagent/possible_drug as anything in victim.reagents.reagent_list) // Go through the drugs in our system
for(var/addiction in possible_drug.addiction_types) // And check all of their addiction types
if(addiction == type && possible_drug.volume >= MIN_ADDICTION_REAGENT_AMOUNT) // If one of them matches, and we have enough of it in our system, we're not losing addiction
if(current_addiction_cycle)
LAZYSET(victim.active_addictions, type, 1) // Keeps withdrawal at first cycle.
on_drug_of_this_addiction = TRUE
return

var/withdrawal_stage
switch(current_addiction_cycle)
if(WITHDRAWAL_STAGE1_START_CYCLE to WITHDRAWAL_STAGE1_END_CYCLE)
withdrawal_stage = 1
if(WITHDRAWAL_STAGE2_START_CYCLE to WITHDRAWAL_STAGE2_END_CYCLE)
withdrawal_stage = 2
if(WITHDRAWAL_STAGE3_START_CYCLE to INFINITY)
withdrawal_stage = 3
else
withdrawal_stage = 0

if(!on_drug_of_this_addiction)
if(victim.RemoveAddictionPoints(type, addiction_loss_per_stage[withdrawal_stage + 1] * delta_time)) // If true was returned, we lost the addiction!
return

if(!current_addiction_cycle) // Dont do the effects if were not on drugs
return FALSE

switch(current_addiction_cycle)
if(WITHDRAWAL_STAGE1_START_CYCLE)
WithdrawalEntersStage1(victim)
if(WITHDRAWAL_STAGE2_START_CYCLE)
WithdrawalEntersStage2(victim)
if(WITHDRAWAL_STAGE3_START_CYCLE)
WithdrawalEntersStage3(victim)

///One cycle is 2 seconds
switch(withdrawal_stage)
if(1)
WithdrawalStage1Process(victim, delta_time)
if(2)
WithdrawalStage3Process(victim, delta_time)
if(3)
WithdrawalStage3Process(victim, delta_time)

LAZYADDASSOC(victim.active_addictions, type, 1 * delta_time) //Next cycle!

/// Called when addiction enters stage 1
/datum/addiction/proc/WithdrawalEntersStage1(mob/living/carbon/victim)
return

/// Called when addiction enters stage 2
/datum/addiction/proc/WithdrawalEntersStage2(mob/living/carbon/victim)
return

/// Called when addiction enters stage 3
/datum/addiction/proc/WithdrawalEntersStage3(mob/living/carbon/victim)
return


/// Called when addiction is in stage 1 every process
/datum/addiction/proc/WithdrawalStage1Process(mob/living/carbon/victim, delta_time)
if(prob(5))
to_chat(victim, SPAN_DANGER("[withdrawal_stage_messages[1]]"))

/// Called when addiction is in stage 2 every process
/datum/addiction/proc/WithdrawalStage2Process(mob/living/carbon/victim, delta_time)
if(prob(10))
to_chat(victim, SPAN_DANGER("[withdrawal_stage_messages[2]]"))


/// Called when addiction is in stage 3 every process
/datum/addiction/proc/WithdrawalStage3Process(mob/living/carbon/victim, delta_time)
if(prob(15))
to_chat(victim, SPAN_DANGER("[withdrawal_stage_messages[3]]"))
18 changes: 18 additions & 0 deletions code/modules/reagents/addiction/alcohol.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
///Alcohol
/datum/addiction/alcohol
name = "alcohol"
withdrawal_stage_messages = list("I could use a drink...", "Maybe the bar is still open?..", "God I need a drink!")

/datum/addiction/alcohol/WithdrawalStage1Process(mob/living/carbon/victim, delta_time)
. = ..()
victim.jitteriness = clamp(victim.jitteriness + 5 * delta_time, victim.jitteriness, 250)

/datum/addiction/alcohol/WithdrawalStage2Process(mob/living/carbon/victim, delta_time)
. = ..()
victim.jitteriness = clamp(victim.jitteriness + 10 * delta_time, victim.jitteriness, 250)
victim.adjust_hallucination(3, 3)

/datum/addiction/alcohol/WithdrawalStage3Process(mob/living/carbon/victim, delta_time)
. = ..()
victim.jitteriness = clamp(victim.jitteriness + 15 * delta_time, victim.jitteriness, 250)
victim.adjust_hallucination(5, 5)

0 comments on commit db8adae

Please sign in to comment.