diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 7af6fecce2..753ee75af3 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -86,6 +86,25 @@
#define SCREWYHUD_DEAD 2
#define SCREWYHUD_HEALTHY 3
+//Moods levels for humans
+#define MOOD_LEVEL_HAPPY4 15
+#define MOOD_LEVEL_HAPPY3 10
+#define MOOD_LEVEL_HAPPY2 6
+#define MOOD_LEVEL_HAPPY1 2
+#define MOOD_LEVEL_NEUTRAL 0
+#define MOOD_LEVEL_SAD1 -3
+#define MOOD_LEVEL_SAD2 -10
+#define MOOD_LEVEL_SAD3 -15
+#define MOOD_LEVEL_SAD4 -20
+
+//Beauty levels of areas for carbons
+#define BEAUTY_LEVEL_HORRID -50
+#define BEAUTY_LEVEL_BAD -25
+#define BEAUTY_LEVEL_GOOD 25
+#define BEAUTY_LEVEL_GREAT 50
+
+
+
//Nutrition levels for humans
#define NUTRITION_LEVEL_FAT 600
#define NUTRITION_LEVEL_FULL 550
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 854ea01114..57186c26d1 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -39,8 +39,11 @@
#define TRAIT_NOBREATH "no_breath"
#define TRAIT_ANTIMAGIC "anti_magic"
#define TRAIT_HOLY "holy"
+#define TRAIT_DEPRESSION "depression"
+#define TRAIT_JOLLY "jolly"
#define TRAIT_NOCRITDAMAGE "no_crit"
+
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_AGEUSIA "ageusia"
#define TRAIT_HEAVY_SLEEPER "heavy_sleeper"
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index b2bb939b11..54fb88ba88 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -369,7 +369,7 @@ Proc for attack log creation, because really why not
checked_health["health"] = health
return ..()
-/proc/do_after(mob/user, delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
+/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null)
if(!user)
return 0
var/atom/Tloc = null
@@ -392,6 +392,16 @@ Proc for attack log creation, because really why not
if (progress)
progbar = new(user, delay, target)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ switch(mood.mood) //Alerts do_after delay based on how happy you are
+ if(-INFINITY to MOOD_LEVEL_SAD2)
+ delay *= 1.25
+ if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4)
+ delay *= 0.95
+ if(MOOD_LEVEL_HAPPY4 to INFINITY)
+ delay *= 0.9
+
var/endtime = world.time + delay
var/starttime = world.time
. = 1
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 4ce615dd01..9a325dfa1a 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -103,6 +103,7 @@
#define ui_healthdoll "EAST-1:28,CENTER-2:13"
#define ui_health "EAST-1:28,CENTER-1:15"
#define ui_internal "EAST-1:28,CENTER:17"
+#define ui_mood "EAST-1:28,CENTER-3:10"
//borgs
#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index 65c4bd23c2..c579c7adab 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -106,6 +106,11 @@
layer = BLIND_LAYER
plane = FULLSCREEN_PLANE
+/obj/screen/fullscreen/depression
+ icon_state = "depression"
+ layer = FLASH_LAYER
+ plane = FULLSCREEN_PLANE
+
/obj/screen/fullscreen/curse
icon_state = "curse"
layer = CURSE_LAYER
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 5693e9c47e..e5de695789 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -43,6 +43,7 @@
var/obj/screen/healths
var/obj/screen/healthdoll
var/obj/screen/internals
+ var/obj/screen/mood
var/ui_style_icon = 'icons/mob/screen_midnight.dmi'
@@ -103,6 +104,7 @@
healths = null
healthdoll = null
internals = null
+ mood = null
lingchemdisplay = null
devilsouldisplay = null
lingstingdisplay = null
@@ -268,4 +270,4 @@
show_hud(HUD_STYLE_STANDARD,mymob)
/datum/hud/proc/update_locked_slots()
- return
\ No newline at end of file
+ return
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index b0468c74cb..455a0f20e1 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -289,6 +289,10 @@
healthdoll = new /obj/screen/healthdoll()
infodisplay += healthdoll
+ if(!CONFIG_GET(flag/disable_human_mood))
+ mood = new /obj/screen/mood()
+ infodisplay += mood
+
pull_icon = new /obj/screen/pull()
pull_icon.icon = ui_style
pull_icon.update_icon(mymob)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 1e574cd8aa..e582e3ec0b 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -538,6 +538,16 @@
name = "health doll"
screen_loc = ui_healthdoll
+/obj/screen/mood
+ name = "mood"
+ icon_state = "mood5"
+ screen_loc = ui_mood
+
+/obj/screen/mood/Click()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, usr)
+ if(mood)
+ mood.print_mood()
+
/obj/screen/splash
icon = 'icons/blank_title.png'
icon_state = ""
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 12a8196dd6..4ac9910336 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -47,8 +47,10 @@
/datum/config_entry/flag/force_random_names
/datum/config_entry/flag/humans_need_surnames
-
+
/datum/config_entry/flag/allow_ai // allow ai job
+
+/datum/config_entry/flag/disable_human_mood
/datum/config_entry/flag/disable_secborg // disallow secborg module to be chosen.
diff --git a/code/controllers/subsystem/moods.dm b/code/controllers/subsystem/moods.dm
new file mode 100644
index 0000000000..d1e58c7452
--- /dev/null
+++ b/code/controllers/subsystem/moods.dm
@@ -0,0 +1,4 @@
+PROCESSING_SUBSYSTEM_DEF(mood)
+ name = "Mood"
+ flags = SS_NO_INIT | SS_BACKGROUND
+ priority = 20
diff --git a/code/datums/brain_damage/mild.dm b/code/datums/brain_damage/mild.dm
index 87e0cb3457..9a523cb39f 100644
--- a/code/datums/brain_damage/mild.dm
+++ b/code/datums/brain_damage/mild.dm
@@ -43,6 +43,9 @@
/datum/brain_trauma/mild/dumbness/on_gain()
owner.add_trait(TRAIT_DUMB, TRAUMA_TRAIT)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner)
+ if(mood)
+ mood.add_event("dumb", /datum/mood_event/oblivious)
..()
/datum/brain_trauma/mild/dumbness/on_life()
@@ -56,6 +59,9 @@
/datum/brain_trauma/mild/dumbness/on_lose()
owner.remove_trait(TRAIT_DUMB, TRAUMA_TRAIT)
owner.derpspeech = 0
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner)
+ if(mood)
+ mood.clear_event("dumb")
..()
/datum/brain_trauma/mild/speech_impediment
@@ -211,4 +217,4 @@
to_chat(owner, "Your arm spasms!")
log_attack("[key_name(owner)] threw [I] due to a Muscle Spasm.")
owner.throw_item(pick(targets))
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
new file mode 100644
index 0000000000..2f0401302f
--- /dev/null
+++ b/code/datums/components/mood.dm
@@ -0,0 +1,122 @@
+/datum/component/mood
+ var/mood //Real happiness
+ var/shown_mood //Shown happiness, this is what others can see when they try to examine you, prevents antag checking by noticing traitors are always very happy.
+ var/mood_level //To track what stage of moodies they're on
+ var/mood_modifier = 1 //Modifier to allow certain mobs to be less affected by moodlets
+ var/datum/mood_event/list/mood_events = list()
+ var/mob/living/owner
+
+/datum/component/mood/Initialize()
+ if(!isliving(parent))
+ . = COMPONENT_INCOMPATIBLE
+ CRASH("Some good for nothing loser put a mood component on something that isn't even a living mob.")
+ START_PROCESSING(SSmood, src)
+ owner = parent
+
+/datum/component/mood/Destroy()
+ STOP_PROCESSING(SSmood, src)
+ return ..()
+
+/datum/component/mood/proc/print_mood()
+ var/msg = "*---------*\nYour current mood\n"
+ for(var/i in mood_events)
+ var/datum/mood_event/event = mood_events[i]
+ msg += event.description
+ to_chat(owner, msg)
+
+/datum/component/mood/proc/update_mood() //Called whenever a mood event is added or removed
+ mood = 0
+ shown_mood = 0
+ for(var/i in mood_events)
+ var/datum/mood_event/event = mood_events[i]
+ mood += event.mood_change
+ if(!event.hidden)
+ shown_mood += event.mood_change
+ mood *= mood_modifier
+ shown_mood *= mood_modifier
+
+ switch(mood)
+ if(-INFINITY to MOOD_LEVEL_SAD4)
+ mood_level = 1
+ if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3)
+ mood_level = 2
+ if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2)
+ mood_level = 3
+ if(MOOD_LEVEL_SAD2 to MOOD_LEVEL_SAD1)
+ mood_level = 4
+ if(MOOD_LEVEL_SAD1 to MOOD_LEVEL_HAPPY1)
+ mood_level = 5
+ if(MOOD_LEVEL_HAPPY1 to MOOD_LEVEL_HAPPY2)
+ mood_level = 6
+ if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3)
+ mood_level = 7
+ if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4)
+ mood_level = 8
+ if(MOOD_LEVEL_HAPPY4 to INFINITY)
+ mood_level = 9
+
+ if(owner.client && owner.hud_used)
+ owner.hud_used.mood.icon_state = "mood[mood_level]"
+
+/datum/component/mood/process() //Called on SSmood process
+ switch(mood)
+ if(-INFINITY to MOOD_LEVEL_SAD4)
+ owner.overlay_fullscreen("depression", /obj/screen/fullscreen/depression, 3)
+ if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3)
+ owner.overlay_fullscreen("depression", /obj/screen/fullscreen/depression, 2)
+ if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2)
+ owner.overlay_fullscreen("depression", /obj/screen/fullscreen/depression, 1)
+ if(MOOD_LEVEL_SAD2 to INFINITY)
+ owner.clear_fullscreen("depression")
+
+ if(owner.has_trait(TRAIT_DEPRESSION))
+ if(prob(0.1))
+ add_event("depression", /datum/mood_event/depression)
+ clear_event("jolly")
+ if(owner.has_trait(TRAIT_JOLLY))
+ if(prob(0.1))
+ add_event("jolly", /datum/mood_event/jolly)
+ clear_event("depression")
+
+/datum/component/mood/proc/add_event(category, type, param) //Category will override any events in the same category, should be unique unless the event is based on the same thing like hunger.
+ var/datum/mood_event/the_event
+ if(mood_events[category])
+ the_event = mood_events[category]
+ if(the_event.type != type)
+ clear_event(category)
+ return .()
+ else
+ return 0 //Don't have to update the event.
+ else
+ the_event = new type(src, param)
+
+ mood_events[category] = the_event
+ update_mood()
+
+ if(the_event.timeout)
+ addtimer(CALLBACK(src, .proc/clear_event, category), the_event.timeout)
+
+/datum/component/mood/proc/clear_event(category)
+ var/datum/mood_event/event = mood_events[category]
+ if(!event)
+ return 0
+
+ mood_events -= category
+ qdel(event)
+ update_mood()
+
+/datum/component/mood/proc/update_beauty(var/area/A)
+ if(A.outdoors) //if we're outside, we don't care.
+ clear_event("area_beauty")
+ return FALSE
+ switch(A.beauty)
+ if(-INFINITY to BEAUTY_LEVEL_HORRID)
+ add_event("area_beauty", /datum/mood_event/disgustingroom)
+ if(BEAUTY_LEVEL_HORRID to BEAUTY_LEVEL_BAD)
+ add_event("area_beauty", /datum/mood_event/grossroom)
+ if(BEAUTY_LEVEL_BAD to BEAUTY_LEVEL_GOOD)
+ clear_event("area_beauty")
+ if(BEAUTY_LEVEL_GOOD to BEAUTY_LEVEL_GREAT)
+ add_event("area_beauty", /datum/mood_event/niceroom)
+ if(BEAUTY_LEVEL_GREAT to INFINITY)
+ add_event("area_beauty", /datum/mood_event/greatroom)
diff --git a/code/datums/mood_events/drug_events.dm b/code/datums/mood_events/drug_events.dm
new file mode 100644
index 0000000000..5d585ab6b2
--- /dev/null
+++ b/code/datums/mood_events/drug_events.dm
@@ -0,0 +1,39 @@
+/datum/mood_event/drugs/high
+ mood_change = 6
+ description = "Woooow duudeeeeee...I'm tripping baaalls...\n"
+
+/datum/mood_event/drugs/smoked
+ description = "I have had a smoke recently.\n"
+ mood_change = 2
+ timeout = 3600
+
+/datum/mood_event/drugs/overdose
+ mood_change = -8
+ timeout = 3000
+
+/datum/mood_event/drugs/overdose/add_effects(drug_name)
+ description = "I think I took a bit too much of that [drug_name]\n"
+
+/datum/mood_event/drugs/withdrawal_light
+ mood_change = -2
+
+/datum/mood_event/drugs/withdrawal_light/add_effects(drug_name)
+ description = "I could use some [drug_name]\n"
+
+/datum/mood_event/drugs/withdrawal_medium
+ mood_change = -5
+
+/datum/mood_event/drugs/withdrawal_medium/add_effects(drug_name)
+ description = "I really need [drug_name]\n"
+
+/datum/mood_event/drugs/withdrawal_severe
+ mood_change = -8
+
+/datum/mood_event/drugs/withdrawal_severe/add_effects(drug_name)
+ description = "Oh god I need some [drug_name]\n"
+
+/datum/mood_event/drugs/withdrawal_critical
+ mood_change = -10
+
+/datum/mood_event/drugs/withdrawal_critical/add_effects(drug_name)
+ description = "[drug_name]! [drug_name]! [drug_name]!\n"
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
new file mode 100644
index 0000000000..afb58bf379
--- /dev/null
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -0,0 +1,115 @@
+/datum/mood_event/handcuffed
+ description = "I guess my antics have finally caught up with me..\n"
+ mood_change = -1
+
+/datum/mood_event/broken_vow //Used for when mimes break their vow of silence
+ description = "I have brought shame upon my name, and betrayed my fellow mimes by breaking our sacred vow...\n"
+ mood_change = -8
+
+/datum/mood_event/on_fire
+ description = "I'M ON FIRE!!!\n"
+ mood_change = -8
+
+/datum/mood_event/suffocation
+ description = "CAN'T... BREATHE...\n"
+ mood_change = -6
+
+/datum/mood_event/burnt_thumb
+ description = "I shouldn't play with lighters...\n"
+ mood_change = -1
+ timeout = 1200
+
+/datum/mood_event/cold
+ description = "It's way too cold in here.\n"
+ mood_change = -2
+
+/datum/mood_event/hot
+ description = "It's getting hot in here.\n"
+ mood_change = -2
+
+/datum/mood_event/creampie
+ description = "I've been creamed. Tastes like pie flavor.\n"
+ mood_change = -2
+ timeout = 1800
+
+/datum/mood_event/slipped
+ description = "I slipped. I should be more careful next time...\n"
+ mood_change = -3
+ timeout = 1800
+
+/datum/mood_event/eye_stab
+ description = "I used to be an adventurer like you, until I took a screwdriver to the eye.\n"
+ mood_change = -6
+ timeout = 2400
+
+/datum/mood_event/delam //SM delamination
+ description = "Those God damn engineers can't do anything right...\n"
+ mood_change = -6
+ timeout = 3000
+
+/datum/mood_event/depression
+ description = "I feel sad for no particular reason.\n"
+ mood_change = -6
+ timeout = 1200
+
+/datum/mood_event/shameful_suicide //suicide_acts that return SHAME, like sord
+ description = "I can't even end it all!\n"
+ mood_change = -10
+ timeout = 600
+
+/datum/mood_event/dismembered
+ description = "AHH! I WAS USING THAT LIMB!\n"
+ mood_change = -8
+ timeout = 3000
+
+/datum/mood_event/noshoes
+ description = "I am a disgrace to comedy everywhere!\n"
+ mood_change = -3
+
+/datum/mood_event/tased
+ description = "There's no \"z\" in \"taser\". It's in the zap.\n"
+ mood_change = -4
+ timeout = 1200
+
+/datum/mood_event/embedded
+ description = "Pull it out!\n"
+ mood_change = -6
+
+/datum/mood_event/table
+ description = "Someone threw me on a table!\n"
+ mood_change = -2
+ timeout = 1200
+
+/datum/mood_event/brain_damage
+ mood_change = -3
+
+/datum/mood_event/brain_damage/add_effects()
+ var/damage_message = pick_list_replacements("brain_damage_lines.json", "brain_damage")
+ description = "Hurr durr... [damage_message]\n"
+
+/datum/mood_event/hulk //Entire duration of having the hulk mutation
+ description = "HULK SMASH!\n"
+ mood_change = -4
+
+/datum/mood_event/epilepsy //Only when the mutation causes a seizure
+ description = "I should have paid attention to the epilepsy warning.\n"
+ mood_change = -3
+ timeout = 3000
+
+
+/datum/mood_event/grossroom
+ description = "This room is kind of dirty...\n"
+ mood_change = -3
+
+/datum/mood_event/disgustingroom
+ description = "This room is disgusting!\n"
+ mood_change = -5
+
+//These are unused so far but I want to remember them to use them later
+/datum/mood_event/cloned_corpse
+ description = "I recently saw my own corpse...\n"
+ mood_change = -6
+
+/datum/mood_event/surgery
+ description = "HE'S CUTTING ME OPEN!!\n"
+ mood_change = -8
diff --git a/code/datums/mood_events/generic_positive_events.dm b/code/datums/mood_events/generic_positive_events.dm
new file mode 100644
index 0000000000..f5c5bb9807
--- /dev/null
+++ b/code/datums/mood_events/generic_positive_events.dm
@@ -0,0 +1,71 @@
+/datum/mood_event/hug
+ description = "Hugs are nice.\n"
+ mood_change = 1
+ timeout = 1200
+
+/datum/mood_event/arcade
+ description = "I beat the arcade game!\n"
+ mood_change = 3
+ timeout = 3000
+
+/datum/mood_event/blessing
+ description = "I've been blessed.\n"
+ mood_change = 3
+ timeout = 3000
+
+/datum/mood_event/book_nerd
+ description = "I have recently read a book.\n"
+ mood_change = 3
+ timeout = 3000
+
+/datum/mood_event/pet_corgi
+ description = "Corgis are adorable! I can't stop petting them!\n"
+ mood_change = 3
+ timeout = 3000
+
+/datum/mood_event/honk
+ description = "Maybe clowns aren't so bad after all. Honk!\n"
+ mood_change = 2
+ timeout = 2400
+
+/datum/mood_event/perform_cpr
+ description = "It feels good to save a life.\n"
+ mood_change = 6
+ timeout = 3000
+
+/datum/mood_event/oblivious
+ description = "What a lovely day.\n"
+ mood_change = 3
+
+/datum/mood_event/happytable
+ description = "They want to play on the table!\n"
+ mood_change = 2
+ timeout = 1200
+
+/datum/mood_event/jolly
+ description = "I feel happy for no particular reason.\n"
+ mood_change = 6
+ timeout = 1200
+
+/datum/mood_event/focused
+ description = "I have a goal, and I will reach it, whatever it takes!\n" //Used for syndies, nukeops etc so they can focus on their goals
+ mood_change = 12
+ hidden = TRUE
+
+/datum/mood_event/revolution
+ description = "VIVA LA REVOLUTION!\n"
+ mood_change = 3
+ hidden = TRUE
+
+/datum/mood_event/cult
+ description = "I have seen the truth, praise the almighty one!\n"
+ mood_change = 40 //maybe being a cultist isnt that bad after all
+ hidden = TRUE
+
+/datum/mood_event/niceroom
+ description = "This room looks really pretty!\n"
+ mood_change = 4
+
+/datum/mood_event/greatroom
+ description = "This room is beautiful!\n"
+ mood_change = 7
diff --git a/code/datums/mood_events/mood_event.dm b/code/datums/mood_events/mood_event.dm
new file mode 100644
index 0000000000..6b4301b83a
--- /dev/null
+++ b/code/datums/mood_events/mood_event.dm
@@ -0,0 +1,19 @@
+/datum/mood_event
+ var/description ///For descriptions, use the span classes bold nicegreen, nicegreen, none, warning and boldwarning in order from great to horrible.
+ var/mood_change = 0
+ var/timeout = 0
+ var/hidden = FALSE//Not shown on examine
+ var/mob/owner
+
+/datum/mood_event/New(mob/M, param)
+ owner = M
+ add_effects(param)
+
+/datum/mood_event/Destroy()
+ remove_effects()
+
+/datum/mood_event/proc/add_effects(param)
+ return
+
+/datum/mood_event/proc/remove_effects()
+ return
diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm
new file mode 100644
index 0000000000..6059d2e7b6
--- /dev/null
+++ b/code/datums/mood_events/needs_events.dm
@@ -0,0 +1,54 @@
+//nutrition
+/datum/mood_event/nutrition/fat
+ description = "I'm so fat..\n" //muh fatshaming
+ mood_change = -4
+
+/datum/mood_event/nutrition/wellfed
+ description = "My belly feels round and full.\n"
+ mood_change = 6
+
+/datum/mood_event/nutrition/fed
+ description = "I have recently had some food.\n"
+ mood_change = 3
+
+/datum/mood_event/nutrition/hungry
+ description = "I'm getting a bit hungry.\n"
+ mood_change = -8
+
+/datum/mood_event/nutrition/starving
+ description = "I'm starving!\n"
+ mood_change = -15
+
+//Disgust
+/datum/mood_event/disgust/gross
+ description = "I saw something gross.\n"
+ mood_change = -2
+
+/datum/mood_event/disgust/verygross
+ description = "I think I'm going to puke...\n"
+ mood_change = -5
+
+/datum/mood_event/disgust/disgusted
+ description = "Oh god that's disgusting...\n"
+ mood_change = -8
+
+//Generic needs events
+/datum/mood_event/favorite_food
+ description = "I really enjoyed eating that.\n"
+ mood_change = 3
+ timeout = 2400
+
+/datum/mood_event/gross_food
+ description = "I really didn't like that food.\n"
+ mood_change = -2
+ timeout = 2400
+
+/datum/mood_event/disgusting_food
+ description = "That food was disgusting!\n"
+ mood_change = -4
+ timeout = 2400
+
+/datum/mood_event/nice_shower
+ description = "I have recently had a nice shower.\n"
+ mood_change = 2
+ timeout = 1800
diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm
index 418b783b94..fd0dd077b7 100644
--- a/code/datums/mutations/body.dm
+++ b/code/datums/mutations/body.dm
@@ -11,6 +11,9 @@
owner.visible_message("[owner] starts having a seizure!", "You have a seizure!")
owner.Unconscious(200)
owner.Jitter(1000)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner)
+ if(mood)
+ mood.add_event("epilepsy", /datum/mood_event/epilepsy)
addtimer(CALLBACK(src, .proc/jitter_less, owner), 90)
/datum/mutation/human/epilepsy/proc/jitter_less(mob/living/carbon/human/owner)
diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm
index 8397c3b064..b12efbc452 100644
--- a/code/datums/mutations/hulk.dm
+++ b/code/datums/mutations/hulk.dm
@@ -14,6 +14,9 @@
owner.add_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
owner.add_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
owner.update_body_parts()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner)
+ if(mood)
+ mood.add_event("hulk", /datum/mood_event/hulk)
/datum/mutation/human/hulk/on_attack_hand(mob/living/carbon/human/owner, atom/target, proximity)
if(proximity) //no telekinetic hulk attack
@@ -30,7 +33,10 @@
owner.remove_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
owner.remove_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
owner.update_body_parts()
-
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner)
+ if(mood)
+ mood.clear_event("hulk")
+
/datum/mutation/human/hulk/say_mod(message)
if(message)
message = "[uppertext(replacetext(message, ".", "!"))]!!"
diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm
index 538146b873..3ec2a87dc0 100644
--- a/code/datums/traits/good.dm
+++ b/code/datums/traits/good.dm
@@ -81,3 +81,26 @@
mob_trait = TRAIT_VORACIOUS
gain_text = "You feel HONGRY."
lose_text = "You no longer feel HONGRY."
+
+
+/datum/trait/jolly
+ name = "Jolly"
+ desc = "You sometimes just feel happy, for no reason at all."
+ value = 1
+ mob_trait = TRAIT_JOLLY
+
+
+/datum/trait/apathetic
+ name = "Apathetic"
+ desc = "You just don't care as much as other people, that's nice to have in a place like this, I guess."
+ value = 1
+
+/datum/trait/apathetic/add()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
+ if(mood)
+ mood.mood_modifier = 0.8
+
+/datum/trait/apathetic/remove()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, trait_holder)
+ if(mood)
+ mood.mood_modifier = 1 //Change this once/if species get their own mood modifiers.
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 9fd966eead..35205421ff 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -154,3 +154,12 @@
else if(prob(0.5) && dumb_thing)
to_chat(H, "You think of a dumb thing you said a long time ago and scream internally.")
dumb_thing = FALSE //only once per life
+
+/datum/trait/depression
+ name = "Depression"
+ desc = "You sometimes just hate life."
+ mob_trait = TRAIT_DEPRESSION
+ value = -1
+ gain_text = "You start feeling depressed."
+ lose_text = "You no longer feel depressed." //if only it were that easy!
+ medical_record_text = "Patient has a severe mood disorder causing them to experience sudden moments of sadness."
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 450d70508e..0f3bfb12b1 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -31,6 +31,9 @@
var/outdoors = FALSE //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
+ var/beauty = 0 //To see how clean/dirty this area is, only works with indoors areas.
+ var/areasize = 0 //Size of the area in tiles, only calculated for indoors areas.
+
var/power_equip = TRUE
var/power_light = TRUE
var/power_environ = TRUE
@@ -145,6 +148,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(!areas_in_z["[z]"])
areas_in_z["[z]"] = list()
areas_in_z["[z]"] += src
+ update_area_size()
return INITIALIZE_HINT_LATELOAD
@@ -497,6 +501,10 @@ GLOBAL_LIST_EMPTY(teleportlocs)
L.client.played = TRUE
addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, L)
+ if(mood)
+ mood.update_beauty(src)
+
/client/proc/ResetAmbiencePlayed()
played = FALSE
@@ -524,6 +532,13 @@ GLOBAL_LIST_EMPTY(teleportlocs)
blob_allowed = FALSE
addSorted()
+/area/proc/update_area_size()
+ if(outdoors)
+ return FALSE
+ areasize = 0
+ for(var/turf/T in src.contents)
+ areasize++
+
/area/AllowDrop()
CRASH("Bad op: area/AllowDrop() called")
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 90dc4f4f45..fbb5faedc2 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -67,7 +67,10 @@
return INITIALIZE_HINT_QDEL
Reset()
-/obj/machinery/computer/arcade/proc/prizevend()
+/obj/machinery/computer/arcade/proc/prizevend(mob/user)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.add_event("arcade", /datum/mood_event/arcade)
if(prob(0.0001)) //1 in a million
new /obj/item/gun/energy/pulse/prize(src)
SSmedals.UnlockMedal(MEDAL_PULSE, usr.client)
@@ -237,7 +240,7 @@
Reset()
obj_flags &= ~EMAGGED
else
- prizevend()
+ prizevend(usr)
SSblackbox.record_feedback("nested tally", "arcade_results", 1, list("win", (obj_flags & EMAGGED ? "emagged":"normal")))
@@ -1031,7 +1034,7 @@
message_admins("[key_name_admin(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.")
else
- prizevend()
+ prizevend(usr)
obj_flags &= ~EMAGGED
name = "The Orion Trail"
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index f23f13cca4..a3123159f5 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -4,6 +4,7 @@
var/list/random_icon_states = list()
var/blood_state = "" //I'm sorry but cleanable/blood code is ass, and so is blood_DNA
var/bloodiness = 0 //0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
+ var/beauty = 0
var/mergeable_decal = TRUE //when two of these are on a same tile or do we need to merge them into just one?
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
@@ -16,6 +17,7 @@
if(C != src && C.type == src.type && !QDELETED(C))
if (replace_decal(C))
return INITIALIZE_HINT_QDEL
+
if(LAZYLEN(diseases))
var/list/datum/disease/diseases_to_add = list()
for(var/datum/disease/D in diseases)
@@ -24,6 +26,11 @@
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
+/obj/effect/decal/cleanable/LateInitialize()
+ if(src.loc && isturf(src.loc))
+ var/area/A = get_area(src)
+ A.beauty += beauty / max(1, A.areasize) //Ensures that the effects scale with room size
+
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
return TRUE
@@ -90,3 +97,8 @@
return bloodiness
else
return 0
+
+/obj/effect/decal/cleanable/Destroy()
+ if(src.loc && isturf(src.loc))
+ var/area/A = get_area(src)
+ A.beauty -= beauty / max(1, A.areasize)
diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm
index 55d5d32ffc..79103c28aa 100644
--- a/code/game/objects/effects/decals/cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/cleanable/aliens.dm
@@ -8,6 +8,7 @@
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
bloodiness = MAX_SHOE_BLOODINESS
blood_state = BLOOD_STATE_XENO
+ beauty = -200
/obj/effect/decal/cleanable/xenoblood/Initialize()
. = ..()
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index 9d9d8d17a4..7b2c00a0b6 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -6,6 +6,7 @@
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
blood_state = BLOOD_STATE_HUMAN
bloodiness = MAX_SHOE_BLOODINESS
+ beauty = -200
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
C.add_blood_DNA(return_blood_DNA())
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index 3ff1bdc19f..e5253d4b85 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -3,6 +3,7 @@
desc = "Someone should clean that up."
icon = 'icons/obj/objects.dmi'
icon_state = "shards"
+ beauty = -150
/obj/effect/decal/cleanable/ash
name = "ashes"
@@ -10,6 +11,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "ash"
mergeable_decal = FALSE
+ beauty = -150
/obj/effect/decal/cleanable/ash/Initialize()
. = ..()
@@ -24,6 +26,7 @@
/obj/effect/decal/cleanable/ash/large
name = "large pile of ashes"
icon_state = "big_ash"
+ beauty = -150
/obj/effect/decal/cleanable/ash/large/Initialize()
. = ..()
@@ -34,6 +37,7 @@
desc = "Back to sand."
icon = 'icons/obj/shards.dmi'
icon_state = "tiny"
+ beauty = -20
/obj/effect/decal/cleanable/glass/Initialize()
. = ..()
@@ -47,17 +51,20 @@
desc = "Someone should clean that up."
icon_state = "dirt"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ beauty = -150
/obj/effect/decal/cleanable/flour
name = "flour"
desc = "It's still good. Four second rule!"
icon_state = "flour"
+ beauty = -100
/obj/effect/decal/cleanable/greenglow
name = "glowing goo"
desc = "Jeez. I hope that's not for lunch."
light_color = LIGHT_COLOR_GREEN
icon_state = "greenglow"
+ beauty = -100
/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
. = ..()
@@ -73,6 +80,7 @@
layer = WALL_OBJ_LAYER
icon_state = "cobweb1"
resistance_flags = FLAMMABLE
+ beauty = -150
/obj/effect/decal/cleanable/cobweb/cobweb2
icon_state = "cobweb2"
@@ -84,10 +92,12 @@
icon = 'icons/effects/effects.dmi'
icon_state = "molten"
mergeable_decal = FALSE
+ beauty = -250
/obj/effect/decal/cleanable/molten_object/large
name = "big gooey grey mass"
icon_state = "big_molten"
+ beauty = -200
//Vomit (sorry)
/obj/effect/decal/cleanable/vomit
@@ -96,6 +106,7 @@
icon = 'icons/effects/blood.dmi'
icon_state = "vomit_1"
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
+ beauty = -400
/obj/effect/decal/cleanable/vomit/attack_hand(mob/user)
if(ishuman(user))
@@ -127,12 +138,14 @@
gender = NEUTER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
+ beauty = -125
/obj/effect/decal/cleanable/plant_smudge
name = "plant smudge"
gender = NEUTER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_plant")
+ beauty = -125
/obj/effect/decal/cleanable/egg_smudge
name = "smashed egg"
@@ -140,6 +153,7 @@
gender = NEUTER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
+ beauty = -125
/obj/effect/decal/cleanable/pie_smudge //honk
name = "smashed pie"
@@ -147,6 +161,7 @@
gender = NEUTER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("smashed_pie")
+ beauty = -125
/obj/effect/decal/cleanable/chem_pile
name = "chemical pile"
@@ -154,6 +169,7 @@
gender = NEUTER
icon = 'icons/obj/objects.dmi'
icon_state = "ash"
+ beauty = -125
/obj/effect/decal/cleanable/shreds
name = "shreds"
@@ -161,6 +177,7 @@
icon_state = "shreds"
gender = PLURAL
mergeable_decal = FALSE
+ beauty = -125
/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion.
@@ -177,12 +194,14 @@
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "salt_pile"
gender = NEUTER
+ beauty = -125
/obj/effect/decal/cleanable/glitter
name = "generic glitter pile"
desc = "The herpes of arts and crafts."
icon = 'icons/effects/tile_effects.dmi'
gender = NEUTER
+ beauty = 300
/obj/effect/decal/cleanable/glitter/pink
name = "pink glitter"
@@ -200,4 +219,5 @@
name = "stabilized plasma"
desc = "A puddle of stabilized plasma."
icon_state = "flour"
- color = "#C8A5DC"
\ No newline at end of file
+ color = "#C8A5DC"
+ beauty = -200
diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm
index b0159818eb..b70b500bba 100644
--- a/code/game/objects/effects/decals/cleanable/robots.dm
+++ b/code/game/objects/effects/decals/cleanable/robots.dm
@@ -10,6 +10,7 @@
blood_state = BLOOD_STATE_OIL
bloodiness = MAX_SHOE_BLOODINESS
mergeable_decal = FALSE
+ beauty = -200
/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
set waitfor = 0
@@ -46,6 +47,7 @@
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
blood_state = BLOOD_STATE_OIL
bloodiness = MAX_SHOE_BLOODINESS
+ beauty = -125
/obj/effect/decal/cleanable/oil/Initialize()
. = ..()
@@ -57,4 +59,4 @@
/obj/effect/decal/cleanable/oil/slippery
/obj/effect/decal/cleanable/oil/slippery/Initialize()
- AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
\ No newline at end of file
+ AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm
index 31e0f1c540..75fe78959d 100644
--- a/code/game/objects/effects/decals/remains.dm
+++ b/code/game/objects/effects/decals/remains.dm
@@ -30,4 +30,4 @@
/obj/effect/decal/cleanable/robot_debris/old
name = "dusty robot debris"
- desc = "Looks like nobody has touched this in a while."
\ No newline at end of file
+ desc = "Looks like nobody has touched this in a while."
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 0cd102cb5a..aeb7acb651 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -531,6 +531,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
else
M.take_bodypart_damage(7)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("eye_stab", /datum/mood_event/eye_stab)
+
add_logs(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])")
M.adjust_blurriness(3)
diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm
index e3c74a4ddf..0383121308 100644
--- a/code/game/objects/items/blueprints.dm
+++ b/code/game/objects/items/blueprints.dm
@@ -191,6 +191,7 @@
FD.CalculateAffectingAreas()
to_chat(usr, "You rename the '[prevname]' to '[str]'.")
log_game("[key_name(usr)] has renamed [prevname] to [str]")
+ A.update_area_size()
interact()
return 1
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index e622026d21..f2b656a074 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -549,6 +549,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? "r_hand" : "l_hand"
user.apply_damage(5, BURN, hitzone)
user.visible_message("After a few attempts, [user] manages to light [src] - however, [user.p_they()] burn their finger in the process.", "You burn yourself while lighting the lighter!")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.add_event("burnt_thumb", /datum/mood_event/burnt_thumb)
else
set_lit(FALSE)
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index 28171186fe..376f003232 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -116,6 +116,11 @@
. = ..()
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
+/obj/item/weapon/bikehorn/attack(mob/living/carbon/M, mob/living/carbon/user)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("honk", /datum/mood_event/honk)
+
/obj/item/bikehorn/suicide_act(mob/user)
user.visible_message("[user] solemnly points the horn at [user.p_their()] temple! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index 875183f9d2..cea183d493 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -96,6 +96,9 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
H.visible_message("[user] heals [H] with the power of [deity_name]!")
to_chat(H, "May the power of [deity_name] compel you to be healed!")
playsound(src.loc, "punch", 25, 1, -1)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event("blessing", /datum/mood_event/blessing)
return 1
/obj/item/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user, heal_mode = TRUE)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index ad0b33f966..841312be3a 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -95,7 +95,17 @@
pushed_mob.visible_message("[user] pushes [pushed_mob] onto [src].", \
"[user] pushes [pushed_mob] onto [src].")
add_logs(user, pushed_mob, "pushed")
-
+ if(!ishuman(pushed_mob))
+ return
+ var/mob/living/carbon/human/H = pushed_mob
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ if(iscatperson(H)) //Catpeople are a bit dumb and think its fun to be on a table
+ mood.add_event("table", /datum/mood_event/happytable)
+ H.startTailWag()
+ addtimer(CALLBACK(H, /mob/living/carbon/human.proc/endTailWag), 30)
+ else
+ mood.add_event("table", /datum/mood_event/table)
/obj/structure/table/attackby(obj/item/I, mob/user, params)
if(!(flags_1 & NODECONSTRUCT_1))
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index ab9a6334a0..2213e56921 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -335,6 +335,9 @@
L.ExtinguishMob()
L.adjust_fire_stacks(-20) //Douse ourselves with water to avoid fire more easily
L.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, L)
+ if(mood)
+ mood.add_event("shower", /datum/mood_event/nice_shower)
if(iscarbon(L))
var/mob/living/carbon/M = L
. = TRUE
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index bcd597424d..e9276d777b 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -199,6 +199,9 @@
if(!(lube&SLIDE_ICE))
playsound(C.loc, 'sound/misc/slip.ogg', 50, 1, -3)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.add_event("slipped", /datum/mood_event/slipped)
for(var/obj/item/I in C.held_items)
C.accident(I)
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index f9582bdce8..8b603d109a 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -13,7 +13,8 @@ GLOBAL_LIST_EMPTY(antagonists)
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
var/list/objectives = list()
var/antag_memory = ""//These will be removed with antag datum
-
+ var/antag_moodlet //typepath of moodlet that the mob will gain with their status
+
//Antag panel properties
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
@@ -67,6 +68,7 @@ GLOBAL_LIST_EMPTY(antagonists)
if(!silent)
greet()
apply_innate_effects()
+ give_antag_moodies()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
@@ -88,6 +90,7 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/on_removal()
remove_innate_effects()
+ clear_antag_moodies()
if(owner)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
@@ -103,6 +106,20 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/farewell()
return
+/datum/antagonist/proc/give_antag_moodies()
+ if(!antag_moodlet)
+ return
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner.current)
+ if(mood)
+ mood.add_event("antag_moodlet", antag_moodlet)
+
+/datum/antagonist/proc/clear_antag_moodies()
+ if(!antag_moodlet)
+ return
+ GET_COMPONENT_FROM(mood, /datum/component/mood, owner.current)
+ if(mood)
+ mood.add_event("antag_moodlet")
+
//Returns the team antagonist belongs to if any.
/datum/antagonist/proc/get_team()
return
@@ -183,7 +200,7 @@ GLOBAL_LIST_EMPTY(antagonists)
edit_memory(usr)
owner.traitor_panel()
return
-
+
//Some commands might delete/modify this datum clearing or changing owner
var/datum/mind/persistent_owner = owner
@@ -231,4 +248,4 @@ GLOBAL_LIST_EMPTY(antagonists)
name = custom_name
else
return
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index d8371d3751..9df812822c 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -4,6 +4,7 @@
job_rank = ROLE_BROTHER
var/special_role = ROLE_BROTHER
var/datum/team/brother_team/team
+ antag_moodlet = /datum/mood_event/focused
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
@@ -151,4 +152,4 @@
add_objective(new/datum/objective/steal, TRUE)
/datum/team/brother_team/antag_listing_name()
- return "[name] blood brothers"
\ No newline at end of file
+ return "[name] blood brothers"
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index d6afa339d5..afbe823354 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -7,6 +7,7 @@
roundend_category = "changelings"
antagpanel_category = "Changeling"
job_rank = ROLE_CHANGELING
+ antag_moodlet = /datum/mood_event/focused
var/you_are_greet = TRUE
var/give_objectives = TRUE
@@ -542,4 +543,4 @@
return ..() + "([changelingID])"
/datum/antagonist/changeling/xenobio/antag_listing_name()
- return ..() + "(Xenobio)"
\ No newline at end of file
+ return ..() + "(Xenobio)"
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index 067801677b..f921b6b527 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -4,6 +4,7 @@
roundend_category = "clock cultists"
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
+ antag_moodlet = /datum/mood_event/cult
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
@@ -216,4 +217,4 @@
parts += ""
parts += printplayerlist(members - eminence)
- return "[parts.Join("
")]
"
\ No newline at end of file
+ return "[parts.Join("
")]
"
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 1c90834cbd..a31f29efe0 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -4,6 +4,7 @@
name = "Cultist"
roundend_category = "cultists"
antagpanel_category = "Cult"
+ antag_moodlet = /datum/mood_event/cult
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
var/datum/action/innate/cult/blood_magic/magic = new
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index b2fab75eb4..7a573e34d1 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -9,6 +9,7 @@
var/role = ERT_SEC
var/high_alert = FALSE
show_in_antagpanel = FALSE
+ antag_moodlet = /datum/mood_event/focused
/datum/antagonist/ert/on_gain()
update_name()
@@ -71,11 +72,11 @@
/datum/antagonist/ert/greet()
if(!ert_team)
return
-
+
var/leader = role == ERT_LEADER || role == DEATHSQUAD_LEADER
-
+
to_chat(owner, "You are the [name].")
-
+
var/missiondesc = "Your squad is being sent on a mission to [station_name()] by Nanotrasen's Security Division."
if(leader) //If Squad Leader
missiondesc += " Lead your squad to ensure the completion of the mission. Board the shuttle when your team is ready."
@@ -83,6 +84,6 @@
missiondesc += " Follow orders given to you by your squad leader."
if(role != DEATHSQUAD && role != DEATHSQUAD_LEADER)
missiondesc += "Avoid civilian casualites when possible."
-
+
missiondesc += "
Your Mission : [ert_team.mission.explanation_text]"
to_chat(owner,missiondesc)
diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm
index b55165e712..385c9c5f47 100644
--- a/code/modules/antagonists/ninja/ninja.dm
+++ b/code/modules/antagonists/ninja/ninja.dm
@@ -3,6 +3,7 @@
antagpanel_category = "Ninja"
job_rank = ROLE_NINJA
show_name_in_check_antagonists = TRUE
+ antag_moodlet = /datum/mood_event/focused
var/helping_station = FALSE
var/give_objectives = TRUE
var/give_equipment = TRUE
@@ -149,4 +150,4 @@
/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja)
var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
ninjahud.leave_hud(ninja)
- set_antag_hud(ninja, null)
\ No newline at end of file
+ set_antag_hud(ninja, null)
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 7b07b762c0..9b3fa4bed9 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -3,6 +3,7 @@
roundend_category = "syndicate operatives" //just in case
antagpanel_category = "NukeOp"
job_rank = ROLE_OPERATIVE
+ antag_moodlet = /datum/mood_event/focused
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
@@ -136,7 +137,7 @@
to_chat(owner.current, "The nuclear authorization code is: [code]")
else
to_chat(admin, "No valid nuke found!")
-
+
/datum/antagonist/nukeop/leader
name = "Nuclear Operative Leader"
nukeop_outfit = /datum/outfit/syndicate/leader
@@ -366,4 +367,4 @@
return common_part + disk_report
/datum/team/nuclear/is_gamemode_hero()
- return SSticker.mode.name == "nuclear emergency"
\ No newline at end of file
+ return SSticker.mode.name == "nuclear emergency"
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index e708cb9254..eeeee03663 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -6,6 +6,7 @@
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
antagpanel_category = "Revolution"
job_rank = ROLE_REV
+ antag_moodlet = /datum/mood_event/revolution
var/hud_type = "rev"
var/datum/team/revolution/rev_team
@@ -365,4 +366,4 @@
return common_part + heads_report
/datum/team/revolution/is_gamemode_hero()
- return SSticker.mode.name == "revolution"
\ No newline at end of file
+ return SSticker.mode.name == "revolution"
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index e5fdc18f32..c6aaee9c2c 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -3,6 +3,7 @@
roundend_category = "traitors"
antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
+ antag_moodlet = /datum/mood_event/focused
var/should_specialise = TRUE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = /datum/antagonist/traitor/AI
var/human_datum = /datum/antagonist/traitor/human
@@ -11,7 +12,7 @@
var/give_objectives = TRUE
var/should_give_codewords = TRUE
-
+
/datum/antagonist/traitor/human
show_in_antagpanel = FALSE
@@ -343,7 +344,7 @@
var/static/icon/badass = icon('icons/badass.dmi', "badass")
uplink_text += "[icon2html(badass, world)]"
result += uplink_text
-
+
result += objectives_text
var/special_role_text = lowertext(name)
@@ -361,4 +362,4 @@
The code responses were: [GLOB.syndicate_code_response]
"
/datum/antagonist/traitor/is_gamemode_hero()
- return SSticker.mode.name == "traitor"
\ No newline at end of file
+ return SSticker.mode.name == "traitor"
diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm
index c23d7fe5a5..ba89d2ed9f 100644
--- a/code/modules/antagonists/wizard/wizard.dm
+++ b/code/modules/antagonists/wizard/wizard.dm
@@ -3,6 +3,7 @@
roundend_category = "wizards/witches"
antagpanel_category = "Wizard"
job_rank = ROLE_WIZARD
+ antag_moodlet = /datum/mood_event/focused
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
var/allow_rename = TRUE
@@ -331,4 +332,4 @@
parts += ""
parts += printplayerlist(members - master_wizard.owner)
- return "[parts.Join("
")]
"
\ No newline at end of file
+ return "[parts.Join("
")]
"
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index a6b7156ea8..9471f0ab9e 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -21,6 +21,9 @@
if(damagetype & SHAME)
adjustStaminaLoss(200)
suiciding = FALSE
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.add_event("shameful_suicide", /datum/mood_event/shameful_suicide)
return
var/damage_mod = 0
for(var/T in list(BRUTELOSS, FIRELOSS, TOXLOSS, OXYLOSS))
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 0d8c00cad7..e5bc99fabf 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -81,6 +81,20 @@
. = ..()
AddComponent(/datum/component/squeak, list('sound/effects/clownstep1.ogg'=1,'sound/effects/clownstep2.ogg'=1), 50)
+/obj/item/clothing/shoes/clown_shoes/equipped(mob/user, slot)
+ . = ..()
+ if(user.mind && user.mind.assigned_role == "Clown")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.clear_event("noshoes")
+
+/obj/item/clothing/shoes/clown_shoes/dropped(mob/user)
+ . = ..()
+ if(user.mind && user.mind.assigned_role == "Clown")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.add_event("noshoes", /datum/mood_event/noshoes)
+
/obj/item/clothing/shoes/clown_shoes/jester
name = "jester shoes"
desc = "A court jesters shoes, updated with modern squeaking technology."
diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm
index 68ec168a1e..c777fea85b 100644
--- a/code/modules/events/brand_intelligence.dm
+++ b/code/modules/events/brand_intelligence.dm
@@ -75,4 +75,4 @@
rebel.shoot_inventory = 1
if(ISMULTIPLE(activeFor, 8))
- originMachine.speak(pick(rampant_speeches))
\ No newline at end of file
+ originMachine.speak(pick(rampant_speeches))
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index 67e8a6e913..4e38cb81d9 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -23,12 +23,21 @@
if(foodtype & H.dna.species.toxic_food)
to_chat(H,"What the hell was that thing?!")
H.adjust_disgust(25 + 30 * fraction)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event("toxic_food", /datum/mood_event/disgusting_food)
else if(foodtype & H.dna.species.disliked_food)
to_chat(H,"That didn't taste very good...")
H.adjust_disgust(11 + 15 * fraction)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event("gross_food", /datum/mood_event/gross_food)
else if(foodtype & H.dna.species.liked_food)
to_chat(H,"I love this taste!")
H.adjust_disgust(-5 + -2.5 * fraction)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event("fav_food", /datum/mood_event/favorite_food)
else
if(foodtype & H.dna.species.toxic_food)
to_chat(H, "You don't feel so good...")
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index 0139ab116c..6bc5edf096 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -459,4 +459,4 @@
. = O.attack(M, user, def_zone, FALSE)
update_icon()
-#undef PANCAKE_MAX_STACK
\ No newline at end of file
+#undef PANCAKE_MAX_STACK
diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm
index faffdf5383..1f755e24b2 100644
--- a/code/modules/food_and_drinks/food/snacks_pie.dm
+++ b/code/modules/food_and_drinks/food/snacks_pie.dm
@@ -56,6 +56,9 @@
if(!H.creamed) // one layer at a time
H.add_overlay(creamoverlay)
H.creamed = TRUE
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event("creampie", /datum/mood_event/creampie)
qdel(src)
/obj/item/reagent_containers/food/snacks/pie/cream/nostun
@@ -244,4 +247,4 @@
icon_state = "frostypie"
bonus_reagents = list("nutriment" = 4, "vitamin" = 6)
tastes = list("mint" = 1, "pie" = 1)
- foodtype = GRAIN | FRUIT | SUGAR
\ No newline at end of file
+ foodtype = GRAIN | FRUIT | SUGAR
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index d2f81e497e..778e16a831 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -316,6 +316,7 @@ h1.alert, h2.alert {color: #000000;}
.unconscious {color: #0000ff; font-weight: bold;}
.suicide {color: #ff5050; font-style: italic;}
.green {color: #03ff39;}
+.nicegreen {color: #14a833;}
.shadowling {color: #3b2769;}
.cult {color: #960000;}
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 92122411e4..b302701b24 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -206,6 +206,9 @@
if(dat)
user << browse("Penned by [author].
" + "[dat]", "window=book[window_size != null ? ";size=[window_size]" : ""]")
user.visible_message("[user] opens a book titled \"[title]\" and begins reading intently.")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.add_event("book_nerd", /datum/mood_event/book_nerd)
onclose(user, "book")
else
to_chat(user, "This book is completely blank!")
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index ddc4e2e9c1..8a73f8812e 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -738,12 +738,17 @@
//called when we get cuffed/uncuffed
/mob/living/carbon/proc/update_handcuffed()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
if(handcuffed)
drop_all_held_items()
stop_pulling()
throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed)
+ if(mood)
+ mood.add_event("handcuffed", /datum/mood_event/handcuffed)
else
clear_alert("handcuffed")
+ if(mood)
+ mood.clear_event("handcuffed")
update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
update_inv_handcuffed()
update_hud_handcuffed()
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 4995caaca0..6192d9ad44 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -266,6 +266,9 @@
else
M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \
"You hug [src] to make [p_them()] feel better!")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.add_event("hug", /datum/mood_event/hug)
AdjustStun(-60)
AdjustKnockdown(-60)
AdjustUnconscious(-60)
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 26fc9ce245..48df33345c 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -89,7 +89,21 @@
if(digitalcamo)
msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner.\n"
-
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ switch(mood.shown_mood)
+ if(-INFINITY to MOOD_LEVEL_SAD4)
+ msg += "[t_He] look[p_s()] depressed.\n"
+ if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3)
+ msg += "[t_He] look[p_s()] very sad.\n"
+ if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2)
+ msg += "[t_He] look[p_s()] a bit down.\n"
+ if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3)
+ msg += "[t_He] look[p_s()] quite happy.\n"
+ if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4)
+ msg += "[t_He] look[p_s()] very happy.\n"
+ if(MOOD_LEVEL_HAPPY4 to INFINITY)
+ msg += "[t_He] look[p_s()] ecstatic.\n"
msg += "*---------*"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 2061924951..8d8eead442 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -30,11 +30,17 @@
AddComponent(/datum/component/redirect, list(COMSIG_COMPONENT_CLEAN_ACT), CALLBACK(src, .proc/clean_blood))
+
+/mob/living/carbon/human/ComponentInitialize()
+ if(!CONFIG_GET(flag/disable_human_mood))
+ AddComponent(/datum/component/mood)
+
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
return ..()
+
/mob/living/carbon/human/OpenCraftingMenu()
handcrafting.ui_interact(src)
@@ -223,6 +229,9 @@
usr.visible_message("[usr] successfully rips [I] out of their [L.name]!","You successfully remove [I] from your [L.name].")
if(!has_embedded_objects())
clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, usr)
+ if(mood)
+ mood.clear_event("embeddedobject")
return
if(href_list["item"])
@@ -651,6 +660,9 @@
return
src.visible_message("[src] performs CPR on [C.name]!", "You perform CPR on [C.name].")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.add_event("perform_cpr", /datum/mood_event/perform_cpr)
C.cpr_time = world.time
add_logs(src, C, "CPRed")
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index c7d2541b08..06cf675427 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -144,6 +144,9 @@
I.forceMove(src)
L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.add_event("embedded", /datum/mood_event/embedded)
hitpush = FALSE
skipcatch = TRUE //can't catch the now embedded item
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index bf9a4492d6..246e615199 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -85,6 +85,19 @@
to_chat(src, "You don't feel like harming anybody.")
a_intent_change(INTENT_HELP)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if (getBrainLoss() >= 60 && stat == CONSCIOUS)
+ if(mood)
+ mood.add_event("brain_damage", /datum/mood_event/brain_damage)
+ if(prob(3))
+ if(prob(25))
+ emote("drool")
+ else
+ say(pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage"))
+ else
+ if(mood)
+ mood.clear_event("brain_damage")
+
/mob/living/carbon/human/handle_mutations_and_radiation()
if(!dna || !dna.species.handle_mutations_and_radiation(src))
..()
@@ -330,6 +343,9 @@
visible_message("[I] falls out of [name]'s [BP.name]!","[I] falls out of your [BP.name]!")
if(!has_embedded_objects())
clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.clear_event("embedded")
/mob/living/carbon/human/proc/handle_active_genes()
for(var/datum/mutation/human/HM in dna.mutations)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 8a78c1532e..97bb2ffb0a 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1121,6 +1121,16 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if (H.nutrition > 0 && H.stat != DEAD && !H.has_trait(TRAIT_NOHUNGER))
// THEY HUNGER
var/hunger_rate = HUNGER_FACTOR
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ switch(mood.mood) //Alerts do_after delay based on how happy you are
+ if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3)
+ hunger_rate *= 0.9
+ if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4)
+ hunger_rate *= 0.8
+ if(MOOD_LEVEL_HAPPY4 to INFINITY)
+ hunger_rate *= 0.7
+
if(H.satiety > 0)
H.satiety--
if(H.satiety < 0)
@@ -1154,14 +1164,31 @@ GLOBAL_LIST_EMPTY(roundstart_races)
to_chat(H, "You no longer feel vigorous.")
H.metabolism_efficiency = 1
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
switch(H.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
+ if(mood)
+ mood.add_event("nutrition", /datum/mood_event/nutrition/fat)
H.throw_alert("nutrition", /obj/screen/alert/fat)
- if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FULL)
+ if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
+ if(mood)
+ mood.add_event("nutrition", /datum/mood_event/nutrition/wellfed)
+ H.clear_alert("nutrition")
+ if( NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
+ if(mood)
+ mood.add_event("nutrition", /datum/mood_event/nutrition/fed)
+ H.clear_alert("nutrition")
+ if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
+ if(mood)
+ mood.clear_event("nutrition")
H.clear_alert("nutrition")
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
+ if(mood)
+ mood.add_event("nutrition", /datum/mood_event/nutrition/hungry)
H.throw_alert("nutrition", /obj/screen/alert/hungry)
- else
+ if(0 to NUTRITION_LEVEL_STARVING)
+ if(mood)
+ mood.add_event("nutrition", /datum/mood_event/nutrition/starving)
H.throw_alert("nutrition", /obj/screen/alert/starving)
/datum/species/proc/update_health_hud(mob/living/carbon/human/H)
@@ -1262,14 +1289,22 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(I.flags_2 & SLOWS_WHILE_IN_HAND_2)
. += I.slowdown
var/health_deficiency = (100 - H.health + H.staminaloss)
- var/hungry = (500 - H.nutrition) / 5 // So overeat would be 100 and default level would be 80
if(health_deficiency >= 40)
if(flight)
. += (health_deficiency / 75)
else
. += (health_deficiency / 25)
- if((hungry >= 70) && !flight) //Being hungry won't stop you from using flightpack controls/flapping your wings although it probably will in the wing case but who cares.
- . += hungry / 50
+
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood && !flight) //How can depression slow you down if you can just fly away from your problems?
+ switch(mood.mood)
+ if(-INFINITY to MOOD_LEVEL_SAD4)
+ . += 1.5
+ if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3)
+ . += 1
+ if(MOOD_LEVEL_SAD3 to MOOD_LEVEL_SAD2)
+ . += 0.5
+
if(H.has_trait(TRAIT_FAT))
. += (1.5 - flight)
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
@@ -1621,6 +1656,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(H.has_trait(TRAIT_NOBREATH))
return TRUE
+
/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H)
if(!environment)
return
@@ -1650,9 +1686,13 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.adjust_bodytemperature(natural*(1/(thermal_protection+1)) + min(thermal_protection * (loc_temp - H.bodytemperature) / BODYTEMP_HEAT_DIVISOR, BODYTEMP_HEATING_MAX))
// +/- 50 degrees from 310K is the 'safe' zone, where no damage is dealt.
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
if(H.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !H.has_trait(TRAIT_RESISTHEAT))
//Body temperature is too hot.
var/burn_damage
+ if(mood)
+ mood.clear_event("cold")
+ mood.add_event("hot", /datum/mood_event/hot)
switch(H.bodytemperature)
if(BODYTEMP_HEAT_DAMAGE_LIMIT to 400)
H.throw_alert("temp", /obj/screen/alert/hot, 1)
@@ -1670,7 +1710,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if (H.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) //40% for level 3 damage on humans
H.emote("scream")
H.apply_damage(burn_damage, BURN)
+
else if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !(GLOB.mutations_list[COLDRES] in H.dna.mutations))
+ if(mood)
+ mood.clear_event("hot")
+ mood.add_event("cold", /datum/mood_event/cold)
switch(H.bodytemperature)
if(200 to BODYTEMP_COLD_DAMAGE_LIMIT)
H.throw_alert("temp", /obj/screen/alert/cold, 1)
@@ -1684,6 +1728,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
H.clear_alert("temp")
+ if(mood)
+ mood.clear_event("cold")
+ mood.clear_event("hot")
var/pressure = environment.return_pressure()
var/adjusted_pressure = H.calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob.
@@ -1778,6 +1825,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
H.adjust_bodytemperature(BODYTEMP_HEATING_MAX + (H.fire_stacks * 12))
+
/datum/species/proc/CanIgniteMob(mob/living/carbon/human/H)
if(H.has_trait(TRAIT_NOFIRE))
return FALSE
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index e5c82f0ead..fec5ae0e63 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -144,6 +144,7 @@
//OXYGEN
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
if(prob(20))
emote("gasp")
@@ -156,6 +157,8 @@
adjustOxyLoss(3)
failed_last_breath = 1
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
+ if(mood)
+ mood.add_event("suffocation", /datum/mood_event/suffocation)
else //Enough oxygen
failed_last_breath = 0
@@ -163,6 +166,8 @@
adjustOxyLoss(-5)
oxygen_used = breath_gases[/datum/gas/oxygen][MOLES]
clear_alert("not_enough_oxy")
+ if(mood)
+ mood.clear_event("suffocation")
breath_gases[/datum/gas/oxygen][MOLES] -= oxygen_used
breath_gases[/datum/gas/carbon_dioxide][MOLES] += oxygen_used
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index eccdd5d2cf..1db31d5a2d 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -42,12 +42,17 @@
/mob/living/carbon/adjust_drugginess(amount)
druggy = max(druggy+amount, 0)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
if(druggy)
overlay_fullscreen("high", /obj/screen/fullscreen/high)
throw_alert("high", /obj/screen/alert/high)
+ if(mood)
+ mood.add_event("high", /datum/mood_event/drugs/high)
else
clear_fullscreen("high")
clear_alert("high")
+ if(mood)
+ mood.clear_event("high")
/mob/living/carbon/set_drugginess(amount)
druggy = max(amount, 0)
@@ -97,4 +102,3 @@
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
. = B.cure_all_traumas(resilience)
-
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index dcd3789360..b5a0ff369d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -952,6 +952,9 @@
"You're set on fire!")
new/obj/effect/dummy/fire(src)
throw_alert("fire", /obj/screen/alert/fire)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.add_event("on_fire", /datum/mood_event/on_fire)
update_fire()
return TRUE
return FALSE
@@ -963,6 +966,9 @@
for(var/obj/effect/dummy/fire/F in src)
qdel(F)
clear_alert("fire")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.clear_event("on_fire")
update_fire()
/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index a6e24f43dd..5a9ae07374 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -58,3 +58,4 @@
icon = 'icons/effects/blood.dmi'
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
+ beauty = -300
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 282a02494a..ae1681cbef 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -231,6 +231,9 @@
return
if(!item_to_add)
user.visible_message("[user] pets [src].","You rest your hand on [src]'s head for a moment.")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, user)
+ if(mood)
+ mood.add_event("pet_corgi", /datum/mood_event/pet_corgi)
return
if(user && !user.temporarilyRemoveItemFromInventory(item_to_add))
@@ -613,6 +616,9 @@
if(M && stat != DEAD) // Added check to see if this mob (the dog) is dead to fix issue 2454
new /obj/effect/temp_visual/heart(loc)
emote("me", 1, "yaps happily!")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("pet_corgi", /datum/mood_event/pet_corgi)
else
if(M && stat != DEAD) // Same check here, even though emote checks it as well (poor form to check it only in the help case)
emote("me", 1, "growls!")
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
index de8545d3f0..eb2b1be1d4 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
@@ -66,6 +66,7 @@
desc = "A small pool of sludge, containing trace amounts of leaper venom."
icon = 'icons/effects/tomatodecal.dmi'
icon_state = "tomato_floor1"
+ beauty = -200
/obj/structure/leaper_bubble
name = "leaper bubble"
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 017b1e7b2b..7a07ba5a7f 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -233,6 +233,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
if(M.z == z)
SEND_SOUND(M, 'sound/magic/charge.ogg')
to_chat(M, "You feel reality distort for a moment...")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("delam", /datum/mood_event/delam)
if(combined_gas > MOLE_PENALTY_THRESHOLD)
investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER)
if(T)
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
new file mode 100644
index 0000000000..2d7f8f5cce
--- /dev/null
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -0,0 +1,203 @@
+/obj/item/projectile/energy
+ name = "energy"
+ icon_state = "spark"
+ damage = 0
+ damage_type = BURN
+ flag = "energy"
+ is_reflectable = TRUE
+
+/obj/item/projectile/energy/chameleon
+ nodamage = TRUE
+
+/obj/item/projectile/energy/electrode
+ name = "electrode"
+ icon_state = "spark"
+ color = "#FFFF00"
+ nodamage = 1
+ knockdown = 100
+ stutter = 5
+ jitter = 20
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 7
+ tracer_type = /obj/effect/projectile/tracer/stun
+ muzzle_type = /obj/effect/projectile/muzzle/stun
+ impact_type = /obj/effect/projectile/impact/stun
+
+/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
+ . = ..()
+ if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - burst into sparks!
+ do_sparks(1, TRUE, src)
+ else if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ if(C.dna && C.dna.check_mutation(HULK))
+ C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
+ else if((C.status_flags & CANKNOCKDOWN) && !C.has_trait(TRAIT_STUNIMMUNE))
+ addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
+
+/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
+ do_sparks(1, TRUE, src)
+ ..()
+
+/obj/item/projectile/energy/net
+ name = "energy netting"
+ icon_state = "e_netting"
+ damage = 10
+ damage_type = STAMINA
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 10
+
+/obj/item/projectile/energy/net/Initialize()
+ . = ..()
+ SpinAnimation()
+
+/obj/item/projectile/energy/net/on_hit(atom/target, blocked = FALSE)
+ if(isliving(target))
+ var/turf/Tloc = get_turf(target)
+ if(!locate(/obj/effect/nettingportal) in Tloc)
+ new /obj/effect/nettingportal(Tloc)
+ ..()
+
+/obj/item/projectile/energy/net/on_range()
+ do_sparks(1, TRUE, src)
+ ..()
+
+/obj/effect/nettingportal
+ name = "DRAGnet teleportation field"
+ desc = "A field of bluespace energy, locking on to teleport a target."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "dragnetfield"
+ light_range = 3
+ anchored = TRUE
+
+/obj/effect/nettingportal/Initialize()
+ . = ..()
+ var/obj/item/device/radio/beacon/teletarget = null
+ for(var/obj/machinery/computer/teleporter/com in GLOB.machines)
+ if(com.target)
+ if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged)
+ teletarget = com.target
+
+ addtimer(CALLBACK(src, .proc/pop, teletarget), 30)
+
+/obj/effect/nettingportal/proc/pop(teletarget)
+ if(teletarget)
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, teletarget, 2)//teleport what's in the tile to the beacon
+ else
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, L, 15) //Otherwise it just warps you off somewhere.
+
+ qdel(src)
+
+/obj/effect/nettingportal/singularity_act()
+ return
+
+/obj/effect/nettingportal/singularity_pull()
+ return
+
+
+/obj/item/projectile/energy/trap
+ name = "energy snare"
+ icon_state = "e_snare"
+ nodamage = 1
+ knockdown = 20
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 4
+
+/obj/item/projectile/energy/trap/on_hit(atom/target, blocked = FALSE)
+ if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - drop a trap
+ new/obj/item/restraints/legcuffs/beartrap/energy(get_turf(loc))
+ else if(iscarbon(target))
+ var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target))
+ B.Crossed(target)
+ ..()
+
+/obj/item/projectile/energy/trap/on_range()
+ new /obj/item/restraints/legcuffs/beartrap/energy(loc)
+ ..()
+
+/obj/item/projectile/energy/trap/cyborg
+ name = "Energy Bola"
+ icon_state = "e_snare"
+ nodamage = 1
+ knockdown = 0
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 10
+
+/obj/item/projectile/energy/trap/cyborg/on_hit(atom/target, blocked = FALSE)
+ if(!ismob(target) || blocked >= 100)
+ do_sparks(1, TRUE, src)
+ qdel(src)
+ if(iscarbon(target))
+ var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target))
+ B.Crossed(target)
+ QDEL_IN(src, 10)
+ ..()
+
+/obj/item/projectile/energy/trap/cyborg/on_range()
+ do_sparks(1, TRUE, src)
+ qdel(src)
+
+/obj/item/projectile/energy/declone
+ name = "radiation beam"
+ icon_state = "declone"
+ damage = 20
+ damage_type = CLONE
+ irradiate = 10
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
+
+/obj/item/projectile/energy/dart //ninja throwing dart
+ name = "dart"
+ icon_state = "toxin"
+ damage = 5
+ damage_type = TOX
+ knockdown = 100
+ range = 7
+
+/obj/item/projectile/energy/bolt //ebow bolts
+ name = "bolt"
+ icon_state = "cbbolt"
+ damage = 8
+ damage_type = TOX
+ nodamage = 0
+ knockdown = 100
+ stutter = 5
+
+/obj/item/projectile/energy/bolt/halloween
+ name = "candy corn"
+ icon_state = "candy_corn"
+
+/obj/item/projectile/energy/bolt/large
+ damage = 20
+
+/obj/item/projectile/energy/tesla
+ name = "tesla bolt"
+ icon_state = "tesla_projectile"
+ impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
+ var/chain
+
+/obj/item/projectile/energy/tesla/fire(setAngle)
+ if(firer)
+ chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY)
+ ..()
+
+/obj/item/projectile/energy/tesla/Destroy()
+ qdel(chain)
+ return ..()
+
+/obj/item/projectile/energy/tesla/revolver
+ name = "energy orb"
+
+/obj/item/projectile/energy/tesla/revolver/on_hit(atom/target)
+ . = ..()
+ if(isliving(target))
+ tesla_zap(target, 3, 10000)
+ qdel(src)
+
+/obj/item/projectile/energy/tesla/cannon
+ name = "tesla orb"
+
+/obj/item/projectile/energy/tesla/cannon/on_hit(atom/target)
+ . = ..()
+ tesla_zap(target, 3, 10000, explosive = FALSE, stun_mobs = FALSE)
+ qdel(src)
diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm
index 01e87d26cd..8cf4dc6f41 100644
--- a/code/modules/projectiles/projectile/energy/net_snare.dm
+++ b/code/modules/projectiles/projectile/energy/net_snare.dm
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
/obj/item/projectile/energy/net
name = "energy netting"
icon_state = "e_netting"
@@ -96,3 +97,103 @@
/obj/item/projectile/energy/trap/cyborg/on_range()
do_sparks(1, TRUE, src)
qdel(src)
+=======
+/obj/item/projectile/energy/net
+ name = "energy netting"
+ icon_state = "e_netting"
+ damage = 10
+ damage_type = STAMINA
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 10
+
+/obj/item/projectile/energy/net/Initialize()
+ . = ..()
+ SpinAnimation()
+
+/obj/item/projectile/energy/net/on_hit(atom/target, blocked = FALSE)
+ if(isliving(target))
+ var/turf/Tloc = get_turf(target)
+ if(!locate(/obj/effect/nettingportal) in Tloc)
+ new /obj/effect/nettingportal(Tloc)
+ ..()
+
+/obj/item/projectile/energy/net/on_range()
+ do_sparks(1, TRUE, src)
+ ..()
+
+/obj/effect/nettingportal
+ name = "DRAGnet teleportation field"
+ desc = "A field of bluespace energy, locking on to teleport a target."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "dragnetfield"
+ light_range = 3
+ anchored = TRUE
+
+/obj/effect/nettingportal/Initialize()
+ . = ..()
+ var/obj/item/device/beacon/teletarget = null
+ for(var/obj/machinery/computer/teleporter/com in GLOB.machines)
+ if(com.target)
+ if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged)
+ teletarget = com.target
+
+ addtimer(CALLBACK(src, .proc/pop, teletarget), 30)
+
+/obj/effect/nettingportal/proc/pop(teletarget)
+ if(teletarget)
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, teletarget, 2)//teleport what's in the tile to the beacon
+ else
+ for(var/mob/living/L in get_turf(src))
+ do_teleport(L, L, 15) //Otherwise it just warps you off somewhere.
+
+ qdel(src)
+
+/obj/effect/nettingportal/singularity_act()
+ return
+
+/obj/effect/nettingportal/singularity_pull()
+ return
+
+/obj/item/projectile/energy/trap
+ name = "energy snare"
+ icon_state = "e_snare"
+ nodamage = 1
+ knockdown = 20
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 4
+
+/obj/item/projectile/energy/trap/on_hit(atom/target, blocked = FALSE)
+ if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - drop a trap
+ new/obj/item/restraints/legcuffs/beartrap/energy(get_turf(loc))
+ else if(iscarbon(target))
+ var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target))
+ B.Crossed(target)
+ ..()
+
+/obj/item/projectile/energy/trap/on_range()
+ new /obj/item/restraints/legcuffs/beartrap/energy(loc)
+ ..()
+
+/obj/item/projectile/energy/trap/cyborg
+ name = "Energy Bola"
+ icon_state = "e_snare"
+ nodamage = 1
+ knockdown = 0
+ hitsound = 'sound/weapons/taserhit.ogg'
+ range = 10
+
+/obj/item/projectile/energy/trap/cyborg/on_hit(atom/target, blocked = FALSE)
+ if(!ismob(target) || blocked >= 100)
+ do_sparks(1, TRUE, src)
+ qdel(src)
+ if(iscarbon(target))
+ var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target))
+ B.Crossed(target)
+ QDEL_IN(src, 10)
+ ..()
+
+/obj/item/projectile/energy/trap/cyborg/on_range()
+ do_sparks(1, TRUE, src)
+ qdel(src)
+>>>>>>> 5140cff... [reviewpls] Adds moodlets to the game - [Please give suggestions for trait additions in comments] (#35475)
diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm
index 598b64d025..3b04febae3 100644
--- a/code/modules/projectiles/projectile/energy/stun.dm
+++ b/code/modules/projectiles/projectile/energy/stun.dm
@@ -18,6 +18,9 @@
do_sparks(1, TRUE, src)
else if(iscarbon(target))
var/mob/living/carbon/C = target
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.add_event("tased", /datum/mood_event/tased)
if(C.dna && C.dna.check_mutation(HULK))
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
else if((C.status_flags & CANKNOCKDOWN) && !C.has_trait(TRAIT_STUNIMMUNE))
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 5735463af2..2a650f3381 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -303,6 +303,9 @@
need_mob_update += R.addiction_act_stage4(C)
if(40 to INFINITY)
to_chat(C, "You feel like you've gotten over your need for [R.name].")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.clear_event("[R.id]_addiction")
cached_addictions.Remove(R)
addiction_tick++
if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index 70bb594c8b..a1a65409a1 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -91,24 +91,39 @@
/datum/reagent/proc/overdose_start(mob/living/M)
to_chat(M, "You feel like you took too much of [name]!")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/overdose, name)
return
/datum/reagent/proc/addiction_act_stage1(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/withdrawal_light, name)
if(prob(30))
to_chat(M, "You feel like having some [name] right about now.")
return
/datum/reagent/proc/addiction_act_stage2(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/withdrawal_medium, name)
if(prob(30))
to_chat(M, "You feel like you need [name]. You just can't get enough.")
return
/datum/reagent/proc/addiction_act_stage3(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/withdrawal_severe, name)
if(prob(30))
to_chat(M, "You have an intense craving for [name].")
return
/datum/reagent/proc/addiction_act_stage4(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/withdrawal_critical, name)
if(prob(30))
to_chat(M, "You're not feeling good at all! You really need some [name].")
return
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index b07b3ece5c..adcf7996d6 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -3,6 +3,12 @@
id = "drug"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "bitterness"
+ var/trippy = TRUE //Does this drug make you trip?
+
+/datum/reagent/drug/on_mob_delete(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood && trippy)
+ mood.clear_event("[id]_high")
/datum/reagent/drug/space_drugs
name = "Space drugs"
@@ -23,7 +29,9 @@
/datum/reagent/drug/space_drugs/overdose_start(mob/living/M)
to_chat(M, "You start tripping hard!")
-
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("[id]_overdose", /datum/mood_event/drugs/overdose, name)
/datum/reagent/drug/space_drugs/overdose_process(mob/living/M)
if(M.hallucination < volume && prob(20))
@@ -38,11 +46,15 @@
color = "#60A584" // rgb: 96, 165, 132
addiction_threshold = 30
taste_description = "smoke"
+ trippy = FALSE
/datum/reagent/drug/nicotine/on_mob_life(mob/living/M)
if(prob(1))
var/smoke_message = pick("You feel relaxed.", "You feel calmed.","You feel alert.","You feel rugged.")
to_chat(M, "[smoke_message]")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood)
+ mood.add_event("smoked", /datum/mood_event/drugs/smoked, name)
M.AdjustStun(-20, 0)
M.AdjustKnockdown(-20, 0)
M.AdjustUnconscious(-20, 0)
@@ -57,6 +69,7 @@
taste_description = "mint"
reagent_state = LIQUID
color = "#80AF9C"
+ trippy = FALSE
/datum/reagent/drug/crank
name = "Crank"
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 3dcf29f15e..55d64ea36c 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -378,7 +378,7 @@
M.adjust_bodytemperature(5 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
..()
-/datum/reagent/mushroomhallucinogen
+/datum/reagent/drug/mushroomhallucinogen
name = "Mushroom Hallucinogen"
id = "mushroomhallucinogen"
description = "A strong hallucinogenic drug derived from certain species of mushroom."
diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm
index 28960fce31..d51f89be18 100644
--- a/code/modules/spells/spell_types/mime.dm
+++ b/code/modules/spells/spell_types/mime.dm
@@ -56,10 +56,15 @@
/obj/effect/proc_holder/spell/targeted/mime/speak/cast(list/targets,mob/user = usr)
for(var/mob/living/carbon/human/H in targets)
H.mind.miming=!H.mind.miming
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
if(H.mind.miming)
to_chat(H, "You make a vow of silence.")
+ if(mood)
+ mood.clear_event("vow")
else
to_chat(H, "You break your vow of silence.")
+ if(mood)
+ mood.add_event("vow", /datum/mood_event/broken_vow)
// These spells can only be gotten from the "Guide for Advanced Mimery series" for Mime Traitors.
diff --git a/code/modules/spells/spell_types/summonitem.dm b/code/modules/spells/spell_types/summonitem.dm
index ab7702fcce..d568aa67f4 100644
--- a/code/modules/spells/spell_types/summonitem.dm
+++ b/code/modules/spells/spell_types/summonitem.dm
@@ -83,6 +83,9 @@
to_chat(C, "The [item_to_retrieve] that was embedded in your [L] has mysteriously vanished. How fortunate!")
if(!C.has_embedded_objects())
C.clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.clear_event("embedded")
break
else
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 7af437ae86..2cf8389a6b 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -19,6 +19,9 @@
affecting.receive_damage(CLAMP(brute_dam/2, 15, 50), CLAMP(burn_dam/2, 0, 50)) //Damage the chest based on limb's existing damage
C.visible_message("[C]'s [src.name] has been violently dismembered!")
C.emote("scream")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.add_event("dismembered", /datum/mood_event/dismembered)
drop_limb()
if(dam_type == BURN)
@@ -101,6 +104,9 @@
I.forceMove(src)
if(!C.has_embedded_objects())
C.clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, C)
+ if(mood)
+ mood.add_event("embedded")
if(!special)
if(C.dna)
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 7ac387b4d8..2c90496eb6 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -121,6 +121,9 @@
I.forceMove(T)
clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ mood.clear_event("embedded")
/mob/living/carbon/proc/has_embedded_objects()
. = 0
diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm
index 1422c20c7b..d54f94b0be 100755
--- a/code/modules/surgery/organs/stomach.dm
+++ b/code/modules/surgery/organs/stomach.dm
@@ -36,21 +36,32 @@
H.blur_eyes(3) //We need to add more shit down here
H.adjust_disgust(-0.5 * disgust_metabolism)
-
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
switch(H.disgust)
if(0 to DISGUST_LEVEL_GROSS)
H.clear_alert("disgust")
+ if(mood)
+ mood.clear_event("disgust")
if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
H.throw_alert("disgust", /obj/screen/alert/gross)
+ if(mood)
+ mood.add_event("disgust", /datum/mood_event/disgust/gross)
if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
H.throw_alert("disgust", /obj/screen/alert/verygross)
+ if(mood)
+ mood.add_event("disgust", /datum/mood_event/disgust/verygross)
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
H.throw_alert("disgust", /obj/screen/alert/disgusted)
+ if(mood)
+ mood.add_event("disgust", /datum/mood_event/disgust/disgusted)
/obj/item/organ/stomach/Remove(mob/living/carbon/M, special = 0)
var/mob/living/carbon/human/H = owner
if(istype(H))
H.clear_alert("disgust")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.clear_event("disgust")
..()
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index 577541e6c4..8f3fad38f8 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -30,6 +30,9 @@
L.embedded_objects -= I
if(!H.has_embedded_objects())
H.clear_alert("embeddedobject")
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.clear_event("embedded")
if(objects > 0)
user.visible_message("[user] successfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].")
diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi
index 5a088e451f..2c234e9894 100644
Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index e22c35a6c4..cdf6df2dab 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -81,6 +81,7 @@ h1.alert, h2.alert {color: #000000;}
.unconscious {color: #0000ff; font-weight: bold;}
.suicide {color: #ff5050; font-style: italic;}
.green {color: #03ff39;}
+.nicegreen {color: #14a833;}
.shadowling {color: #3b2769;}
.cult {color: #960000;}
.cultlarge {color: #960000; font-weight: bold; font-size: 3;}
diff --git a/tgstation.dme b/tgstation.dme
index b1787c6712..f7b36ab728 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -222,6 +222,7 @@
#include "code\controllers\subsystem\medals.dm"
#include "code\controllers\subsystem\minimap.dm"
#include "code\controllers\subsystem\mobs.dm"
+#include "code\controllers\subsystem\moods.dm"
#include "code\controllers\subsystem\nightshift.dm"
#include "code\controllers\subsystem\npcpool.dm"
#include "code\controllers\subsystem\orbit.dm"
@@ -321,6 +322,7 @@
#include "code\datums\components\jousting.dm"
#include "code\datums\components\knockoff.dm"
#include "code\datums\components\material_container.dm"
+#include "code\datums\components\mood.dm"
#include "code\datums\components\ntnet_interface.dm"
#include "code\datums\components\paintable.dm"
#include "code\datums\components\rad_insulation.dm"
@@ -401,6 +403,11 @@
#include "code\datums\martial\psychotic_brawl.dm"
#include "code\datums\martial\sleeping_carp.dm"
#include "code\datums\martial\wrestling.dm"
+#include "code\datums\mood_events\drug_events.dm"
+#include "code\datums\mood_events\generic_negative_events.dm"
+#include "code\datums\mood_events\generic_positive_events.dm"
+#include "code\datums\mood_events\mood_event.dm"
+#include "code\datums\mood_events\needs_events.dm"
#include "code\datums\mutations\body.dm"
#include "code\datums\mutations\chameleon.dm"
#include "code\datums\mutations\cold_resistance.dm"