diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 43ec1a16539..30df240005d 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -23,6 +23,10 @@
#define MODE_WHISPER "whisper"
#define MODE_WHISPER_CRIT "whispercrit"
+//Caustic Edit - Add Absorbed Psay mode
+#define MODE_PSAY "absorbed"
+//Caustic Edit End
+
#define MODE_SING "%"
#define MODE_DEPARTMENT "department"
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index e40f47da6f5..6d4f5ccbd79 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -339,7 +339,7 @@
if(T)
var/mob/target
for(var/mob/M in T)
- if(M.invisibility || M == src)
+ if(M.invisibility || M == src || M.stat == DEAD || isbelly(M.loc)) //Caustic Edit - Lets not target dead mobs, nor mobs that are in a belly! This must be how that's been happening?
continue
target = M
break
diff --git a/code/controllers/subsystem/rogue/fog_event/mobs/fog_wolf.dm b/code/controllers/subsystem/rogue/fog_event/mobs/fog_wolf.dm
index e341abddd47..fdf9d60d585 100644
--- a/code/controllers/subsystem/rogue/fog_event/mobs/fog_wolf.dm
+++ b/code/controllers/subsystem/rogue/fog_event/mobs/fog_wolf.dm
@@ -29,6 +29,8 @@
dodgetime = 30
faction = list(FACTION_REVENANTS, FACTION_WOLFS)
+ AIStatus = AI_OFF
+ can_have_ai = FALSE
ai_controller = /datum/ai_controller/volf
base_intents = list(/datum/intent/simple/bite/volf)
melee_cooldown = WOLF_ATTACK_SPEED
diff --git a/code/datums/dungeon_generator/dungeon_templates/rooms/common.dm b/code/datums/dungeon_generator/dungeon_templates/rooms/common.dm
index 01541893138..43aa9a41bea 100644
--- a/code/datums/dungeon_generator/dungeon_templates/rooms/common.dm
+++ b/code/datums/dungeon_generator/dungeon_templates/rooms/common.dm
@@ -426,7 +426,7 @@
east_offset = 18
south_offset = 26
-/datum/map_template/dungeon/room/hoblingoblin
+/*/datum/map_template/dungeon/room/hoblingoblin //Caustic Edit - Lets try commenting this out and seeing if it stops the errors...
mappath = "_maps/dungeon_generator/room/hoblingoblin.dmm"
id = "hoblin_goblin"
width = 24
@@ -435,7 +435,7 @@
north_offset = 11
south_offset = 11
east_offset = 11
- west_offset = 11
+ west_offset = 11*/
/datum/map_template/dungeon/room/bathhouse_custom
width = 20
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index 5bba5cfc8db..add0fabf349 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -260,7 +260,7 @@
. = message
if(message_muffled && iscarbon(user))
var/mob/living/carbon/C = user
- if(C.silent)
+ if(C.silent || C.muffled) //Caustic Edit - Account for Belly Muffling emotes!
. = message_muffled
if(!muzzle_ignore && HAS_TRAIT(C, TRAIT_MUTE) && emote_type == EMOTE_AUDIBLE)
. = message_muffled
@@ -327,6 +327,10 @@
return target
/datum/emote/proc/is_emote_muffled(mob/living/carbon/H) //ONLY for audible emote use
+ //Caustic Edit - Account for Belly Muffling
+ if(H.muffled)
+ return FALSE
+ //Caustic Edit End
if(H.mouth?.muteinmouth)
return FALSE
for(var/obj/item/grabbing/grab in H.grabbedby)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 1d91d4540cb..41913f4cb2c 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -18,6 +18,7 @@
var/verb_ask = "asks"
var/verb_exclaim = "exclaims"
var/verb_whisper = "whispers"
+ var/verb_thinks = "thinks" //Caustic Edit - Added to account for Psay and absorbed players!
var/verb_sing = "sings"
var/verb_yell = "yells"
var/speech_span
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 68dfb585313..23c0ddc1fbc 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -46,7 +46,7 @@
if(!istype(M))
return FALSE
- if(check_loc && M.loc != loc)
+ if(check_loc && !Adjacent(M)) //M.loc != loc //Caustic Edit - Lets see if we can't just tweak this to allow for 1-tile-away buckles?
return FALSE
if((!can_buckle && !force) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src)
@@ -74,7 +74,7 @@
else if(isliving(M.pulledby))
M.reset_offsets("pulledby")
- if(!check_loc && M.loc != loc)
+ if(M.loc != loc) //Caustic Edit - Removed this check !check_loc && - so it'll just always check and move the player if needed.
M.forceMove(loc)
M.buckling = null
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 557f2c98841..bc9964d7240 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -85,7 +85,7 @@
continue
- var/is_muffled = (M in muffled_listeners)
+ var/is_muffled = (M.muffled || (M in muffled_listeners)) //Caustic Edit - Account for belly Muffling in sound effects! Neat?
if(M.playsound_local(turf_source, soundin, vol, vary, frequency, falloff, channel, pressure_affected, S, repeat, is_muffled))
. += M
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 312b6bd349f..ee1199f0f75 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -227,6 +227,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["audio_preload"] >> audio_preload
S["rp_guidance"] >> rp_guidance
+
+ if(!rp_guidance)
+ rp_guidance = 3 //Reset it to default if it's somehow null.
///Caustic edit end
// Custom hotkeys
S["key_bindings"] >> key_bindings
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index 5b9d7442853..ed7cf1c9063 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -383,19 +383,41 @@ All foods are distributed among various categories. Use common sense.
eater.add_stress(/datum/stressevent/noble_desperate)
if(eat_effect != /datum/status_effect/debuff/rotfood && eat_effect != /datum/status_effect/debuff/burnedfood && eat_effect != /datum/status_effect/debuff/uncookedfood)
apply_effect = FALSE
- if (FARE_POOR to FARE_NEUTRAL)
+ //Caustic Edit - If a noble is being fed, it will act as if it's 1 tier better! ... The worst case though is always bad.
+ if (FARE_POOR)
eater.add_stress(/datum/stressevent/noble_bland_food)
if (prob(25))
to_chat(eater, span_red("This is rather bland. I deserve better food than this..."))
if(eat_effect != /datum/status_effect/debuff/rotfood && eat_effect != /datum/status_effect/debuff/burnedfood && eat_effect != /datum/status_effect/debuff/uncookedfood)
apply_effect = FALSE
+ if (FARE_NEUTRAL)
+ if (isliving(src.loc))
+ eater.remove_stress(/datum/stressevent/noble_bland_food)
+ if (prob(25))
+ to_chat(eater, span_red("This food is plain, but to be fed... That makes up for it."))
+ else
+ eater.add_stress(/datum/stressevent/noble_bland_food)
+ if (prob(25))
+ to_chat(eater, span_red("This is rather bland. I deserve better food than this..."))
+ if(eat_effect != /datum/status_effect/debuff/rotfood && eat_effect != /datum/status_effect/debuff/burnedfood && eat_effect != /datum/status_effect/debuff/uncookedfood)
+ apply_effect = FALSE
if (FARE_FINE)
- eater.remove_stress(/datum/stressevent/noble_bland_food)
+ if (isliving(src.loc))
+ eater.remove_stress(/datum/stressevent/noble_bland_food)
+ eater.add_stress(/datum/stressevent/noble_lavish_food)
+ if (prob(25))
+ to_chat(eater, span_green("Ah, a fine meal, and doted on like this? Exquisite."))
+ else
+ eater.remove_stress(/datum/stressevent/noble_bland_food)
if (FARE_LAVISH)
eater.remove_stress(/datum/stressevent/noble_bland_food)
eater.add_stress(/datum/stressevent/noble_lavish_food)
if (prob(25))
- to_chat(eater, span_green("Ah, food fit for my title."))
+ if (isliving(src.loc))
+ to_chat(eater, span_green("Oh! This is exellent! To be fed the most lavish of meals..."))
+ else
+ to_chat(eater, span_green("Ah, food fit for my title."))
+ //Caustic Edit End
// yeomen and courtiers are also used to a better quality of life but are way less picky
if (human_eater.is_burgher() || human_eater.is_courtier())
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 9d71f818814..d3864dcd2e6 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -1044,7 +1044,7 @@
showassess = TRUE
if((!obscure_name || client?.prefs.masked_examine) && (flavortext || headshot_link || ooc_notes))
- . += "Examine closer [showassess ? " | Assess" : ""]"
+ . += "Examine closer [showassess ? "| Assess " : ""]| Character Directory"
/// Rumours & Gossip
if(length(rumour) || length(noble_gossip))
diff --git a/code/modules/mob/living/carbon/human/examine_tgui.dm b/code/modules/mob/living/carbon/human/examine_tgui.dm
index aa4df94d908..b013491c340 100644
--- a/code/modules/mob/living/carbon/human/examine_tgui.dm
+++ b/code/modules/mob/living/carbon/human/examine_tgui.dm
@@ -34,6 +34,38 @@
ui = new(user, src, "ExaminePanel")
ui.open()
+//Caustic Edit - Grabbing the OV Character Ad addition to the Examine Panel!
+/datum/examine_panel/proc/get_character_ad()
+ if(ishuman(holder))
+ var/raw_character_ad = holder.client?.prefs?.directory_ad
+ if(isnull(raw_character_ad))
+ raw_character_ad = holder.mind?.directory_ad
+ if(raw_character_ad)
+ return parsemarkdown_basic(html_encode(raw_character_ad), hyperlink = TRUE)
+ else if(pref?.directory_ad)
+ return parsemarkdown_basic(html_encode(pref.directory_ad), hyperlink = TRUE)
+
+ return ""
+
+/proc/refresh_character_ad_examine_panels(mob/living/carbon/human/holder_mob, datum/preferences/holder_prefs, datum/mind/holder_mind)
+ for(var/datum/tgui/ui as anything in SStgui.all_uis)
+ if(!istype(ui?.src_object, /datum/examine_panel))
+ continue
+
+ var/datum/examine_panel/panel = ui.src_object
+ var/panel_matches_character = FALSE
+
+ if(holder_mob && panel.holder == holder_mob)
+ panel_matches_character = TRUE
+ else if(holder_prefs && (panel.pref == holder_prefs || panel.holder?.client?.prefs == holder_prefs))
+ panel_matches_character = TRUE
+ else if(holder_mind && panel.holder?.mind == holder_mind)
+ panel_matches_character = TRUE
+
+ if(panel_matches_character)
+ ui.send_update()
+//Caustic Edit End
+
/datum/examine_panel/familiar/ui_static_data(mob/user) //altered and condensed version used for familiars. sorry
var/flavor_text
@@ -92,6 +124,7 @@
/datum/examine_panel/familiar/ui_data(mob/user)
var/list/data = list(
+ "character_ad" = "", //Casutic Edit - Adding in the Character Ad addition to the Examine Panel from OV
"is_playing" = is_playing,
)
return data
@@ -202,6 +235,7 @@
/datum/examine_panel/ui_data(mob/user)
var/list/data = list(
+ "character_ad" = get_character_ad(), //Casutic Edit - Adding in the Character Ad addition to the Examine Panel from OV
"is_playing" = is_playing,
)
return data
diff --git a/code/modules/mob/living/carbon/human/human_topic.dm b/code/modules/mob/living/carbon/human/human_topic.dm
index 969eee26421..5723061a5d5 100644
--- a/code/modules/mob/living/carbon/human/human_topic.dm
+++ b/code/modules/mob/living/carbon/human/human_topic.dm
@@ -16,6 +16,12 @@ GLOBAL_VAR_INIT(year_integer, text2num(year)) // = 2013???
mob_examine_panel.viewing = usr
mob_examine_panel.ui_interact(usr)
return
+
+ if(href_list["task"] == "open_directory")
+ if(!ismob(usr) || !usr.client)
+ return
+ usr.client.show_character_directory()
+ return
if(href_list["inspect_limb"] && (observer_privilege || usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY)))
var/list/msg = list()
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 3b118ebeb23..b956eb2d8ec 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -778,14 +778,13 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
/mob/living/proc/handle_swimming()
var/turf/T = get_turf(src)
var/area/A = get_area(src)
-
-
- var/is_on_water = istype(T, /turf/open/water)
- var/is_on_new_water = istype(T, /turf/open/water/transparent)
-
- var/is_true_swimming = is_swimming || is_underwater || istype(A, /area/underwater) || is_on_new_water
- var/is_area_underwater = istype(A, /area/underwater)
+ //Caustic Edit - If the mob is in a Belly, we are not swimming!
+ var/is_on_water = (istype(T, /turf/open/water) && !isbelly(loc))
+ var/is_on_new_water = (istype(T, /turf/open/water/transparent) && !isbelly(loc))
+ var/is_area_underwater = (istype(A, /area/underwater) && !isbelly(loc))
+ var/is_true_swimming = is_swimming || is_underwater || is_area_underwater || is_on_new_water
+ //Caustic Edit End
var/sw_skill = get_skill_level(/datum/skill/misc/swimming)
var/new_max_breath = (STACON * 5) + (sw_skill * 5)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 0f317a4cd53..dd1e153d7e7 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -86,7 +86,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/static/list/unconscious_allowed_modes = list(MODE_CHANGELING = TRUE, MODE_ALIEN = TRUE)
var/talk_key = get_key(message)
- var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE, MODE_SING = TRUE)
+ var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE, MODE_PSAY = TRUE, MODE_SING = TRUE) //Caustic Edit - Add Psay here so it doesn't trim the first character of your message!
var/ic_blocked = FALSE
if(client && !forced && CHAT_FILTER_CHECK(message))
@@ -208,6 +208,14 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
last_words = message
message_mode = MODE_WHISPER_CRIT
succumbed = TRUE
+ //Caustic Edit - Add in an attempt at the Psay message channel?
+ else if(message_mode == MODE_PSAY) //For now this just gets logged as a whisper
+ message_range = 0
+ var/whisper_log_type = npc_speech ? LOG_NPC_SAY : LOG_WHISPER
+ src.log_talk(message, whisper_log_type)
+ send_thoughts(message, message_range, src, bubble_type, spans, language, message_mode, original_message)
+ return
+ //Caustic Edit End
else
var/log_type = npc_speech ? LOG_NPC_SAY : LOG_SAY
src.log_talk(message, log_type, forced_by=forced)
@@ -263,6 +271,31 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
+//Caustic Edit - Add Psay for absorbed players and their pred!
+/mob/living/proc/send_thoughts(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode, original_message)
+ var/list/listening = list()
+ var/mob/living/pred
+ if(absorbed && isbelly(loc))
+ var/obj/belly/bloc = loc
+ pred = bloc.owner
+ else
+ pred = src
+
+ if(pred.client)
+ listening |= pred
+
+ for(var/obj/belly/B in pred.vore_organs)
+ for(var/mob/living/M in B.contents)
+ if(M.client && M.absorbed)
+ listening |= M
+
+ log_seen(src, null, listening, original_message, SEEN_LOG_SAY)
+
+ var/rendered = compose_message(src, message_language, message, , spans, message_mode)
+ for(var/mob/living/thinker in listening)
+ thinker.show_message(rendered)
+//Caustic Edit End
+
/mob/living/proc/send_speech_sign(message, message_range = 6, obj/source = src, bubble_type = bubble_icon, list/spans, datum/language/message_language=null, message_mode, original_message)
var/static/list/eavesdropping_modes = list(MODE_WHISPER = TRUE, MODE_WHISPER_CRIT = TRUE)
var/eavesdrop_range = 0
@@ -495,7 +528,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
continue
if(!(M.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off
continue
- if(!is_in_zweb(src.z,tocheck.z))
+ var/turf/tocheck_turf = get_turf(tocheck) //Caustic Edit - Change it so whispers can be sent regardless of something/someone being in a container!
+ if(!is_in_zweb(speaker_turf.z,tocheck_turf.z))
continue
listening |= M
the_dead[M] = TRUE
@@ -521,7 +555,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
listener_has_ceiling = FALSE
if(!hearall)
if((!Zs_too && !isobserver(AM)) || message_mode == MODE_WHISPER)
- if(AM.z != src.z)
+ if(listener_turf.z != speaker_turf.z) //Caustic Edit - This should fix whispers not comparing the actual TILES.
continue
if(Zs_too && listener_turf.z != speaker_turf.z && !Zs_all)
if(!Zs_yell && !HAS_TRAIT(AM, TRAIT_KEENEARS) && !hearall)
@@ -540,12 +574,14 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(!speaker_has_ceiling && isliving(AM))
var/mob/living/M = AM
for(var/mob/living/MH in viewers(world.view, speaker_ceiling))
- if(M == MH && MH.z == speaker_ceiling?.z)
+ var/turf/MH_turf = get_turf(MH)
+ if(M == MH && MH_turf.z == speaker_ceiling?.z) //Caustic Edit - This should fix whispers not comparing the actual TILES.
speaker_obstructed = FALSE
if(!listener_has_ceiling)
for(var/mob/living/ML in viewers(world.view, listener_ceiling))
- if(ML == src && ML.z == listener_ceiling?.z)
+ var/turf/ML_turf = get_turf(ML)
+ if(ML == src && ML_turf.z == listener_ceiling?.z) //Caustic Edit - This should fix whispers not comparing the actual TILES.
listener_obstructed = FALSE
if(listener_obstructed && speaker_obstructed)
continue
@@ -663,6 +699,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
/mob/living/proc/radio(message, message_mode, list/spans, language)
switch(message_mode)
+ if(MODE_PSAY) //Caustic Edit - Add in Psay here so that it also becomes Italics like whispers
+ return ITALICS
if(MODE_WHISPER)
return ITALICS
if(MODE_R_HAND)
@@ -686,6 +724,8 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
. = verb_whisper
else if(message_mode == MODE_WHISPER_CRIT)
. = "[verb_whisper] in [p_their()] last breath"
+ else if(message_mode == MODE_PSAY) //Caustic Edit - Add in accounting for Psay and the 'thinks' action
+ . = verb_thinks
else if(stuttering)
. = "stammers"
else if(derpspeech)
diff --git a/code/modules/mob/living/simple_animal/friendly/familiars.dm b/code/modules/mob/living/simple_animal/friendly/familiars.dm
index a81bbbf15a4..bd2056c8bab 100644
--- a/code/modules/mob/living/simple_animal/friendly/familiars.dm
+++ b/code/modules/mob/living/simple_animal/friendly/familiars.dm
@@ -174,7 +174,7 @@
if((valid_headshot_link(src, prefs.familiar_headshot_link[planar_origin], TRUE)) && (user.client?.prefs.chatheadshot))
ret.Insert(2, "
")
if(prefs.familiar_flavortext_display[planar_origin] || prefs.familiar_headshot_link[planar_origin] || prefs.familiar_ooc_notes_display[planar_origin])
- ret.Insert(ret.len-1, "Examine closer")
+ ret.Insert(ret.len-1, "Examine closer | Character Directory")
return ret
// mobility/utility focused. innocuous. can fly, and brew potions, but not much else
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/primordial.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/primordial.dm
index 5868ee8de72..0a905e03970 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/primordial.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/primordial.dm
@@ -101,6 +101,9 @@
retreat_health = 0
food = 0
next_ability_use
+
+ AIStatus = AI_OFF
+ can_have_ai = FALSE
ai_controller = /datum/ai_controller/flame_primordial
/mob/living/simple_animal/hostile/retaliate/rogue/primordial/fire/ability(turf/target_location, mob/living/user)
@@ -183,6 +186,8 @@
retreat_health = 0
food = 0
+ AIStatus = AI_OFF
+ can_have_ai = FALSE
ai_controller = /datum/ai_controller/water_primordial
/mob/living/simple_animal/hostile/retaliate/rogue/primordial/water/ability(turf/target_location, mob/living/user)
@@ -294,6 +299,8 @@
retreat_health = 0
food = 0
+ AIStatus = AI_OFF
+ can_have_ai = FALSE
ai_controller = /datum/ai_controller/air_primordial
/mob/living/simple_animal/hostile/retaliate/rogue/primordial/air/ability(turf/target_location, mob/living/user)
diff --git a/code/modules/mob/living/simple_animal/simple_animal_topic.dm b/code/modules/mob/living/simple_animal/simple_animal_topic.dm
index c53b4b777ce..ec8f9716255 100644
--- a/code/modules/mob/living/simple_animal/simple_animal_topic.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal_topic.dm
@@ -36,4 +36,10 @@
mob_examine_panel.viewing = usr
mob_examine_panel.ui_interact(usr)
return
+
+ if(href_list["task"] == "open_directory")
+ if(!ismob(usr) || !usr.client)
+ return
+ usr.client.show_character_directory()
+ return
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index b2768c8d7e3..4a80be505d0 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -147,8 +147,10 @@
*/
/mob/proc/get_message_mode(message)
var/key = copytext_char(message, 1, 2)
- if(key == "#")
- return MODE_WHISPER
+ if(key == "$" || (forced_psay && absorbed)) //Caustic Edit - Account for the absorbed and muffled effects from vorestuffs. Muffled forces a whisper! Psay is limited to absorbed mobs and the pred!
+ return MODE_PSAY
+ else if(key == "#" || muffled)
+ return MODE_WHISPER //Caustic Edit End
else if(key == ";")
return MODE_HEADSET
else if(key == "%")
diff --git a/interface/interface.dm b/interface/interface.dm
index ce8f00f4fc7..7d1a76ad29c 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -228,22 +228,20 @@ Hotkey-Mode: (hotkey-mode must be on)
if(!ishuman(mob))
return
var/mob/living/carbon/human/C = mob
- var/has_old_ad = FALSE
- if(LAZYACCESS(GLOB.roleplay_ads,C.mobid))
- to_chat(C, span_info(LAZYACCESS(GLOB.roleplay_ads,C.mobid)))
- has_old_ad = TRUE
- var/msg = input("Set an advertisement for what kind of roleplay you are looking to engage in. Others will be able to see it with the Roleplay Ad (View) command. Do not abuse this. Leave empty and press OK to remove your roleplay ad.", "I LOVE TO ROLEPLAY") as message|null
+ //Caustic Edit - Grabbing the OV edit to move the RP ads into the Examine Panel and Character Directory!
+ var/current_ad = get_character_ad_value(C, C.client?.prefs, C.mind)
+ if(current_ad)
+ to_chat(C, span_info(current_ad))
+ var/msg = input("Set an advertisement for what kind of roleplay you are looking to engage in. Others will be able to see it with the Roleplay Ad (View) command. Do not abuse this. Leave empty and press OK to remove your roleplay ad.", "I LOVE TO ROLEPLAY", current_ad) as message|null
+ if(isnull(msg))
+ return
+ set_character_ad_value(C, C.client?.prefs, C.mind, msg, TRUE)
if(msg)
- LAZYSET(GLOB.roleplay_ads,C.mobid,"[C.real_name] - [msg]
")
to_chat(C, span_info("Roleplay ad set."))
log_game("[C] has set their Roleplay Ad to '[msg]'.")
- for(var/client/advertisee in (GLOB.clients - src))
- if(!(advertisee.prefs.toggles & ROLEPLAY_ADS))
- continue
- to_chat(advertisee, span_info("[C.real_name] has set a roleplay ad."))
- else if(has_old_ad)
- LAZYREMOVE(GLOB.roleplay_ads,C.mobid)
+ else
to_chat(C, span_info("Roleplay ad removed."))
+ //Caustic Edit End
/client/verb/changefps()
set category = "OPTIONS"
diff --git a/modular_causticcove/code/__DEFINES/vore_liquid_defines.dm b/modular_causticcove/code/__DEFINES/vore_liquid_defines.dm
index db8da5cf02e..1dad76cadc9 100644
--- a/modular_causticcove/code/__DEFINES/vore_liquid_defines.dm
+++ b/modular_causticcove/code/__DEFINES/vore_liquid_defines.dm
@@ -140,3 +140,5 @@
#define REAGENT_NUMBENZYME "Numbing Enzyme"
#define REAGENT_ID_NUMBENZYME "numbenzyme"
+
+#define REAGENT_ID_POPPYMILK /datum/reagent/consumable/poppy_milk
diff --git a/modular_causticcove/code/datums/loadout.dm b/modular_causticcove/code/datums/loadout.dm
index cd6c07e0484..d33fd63f6a5 100644
--- a/modular_causticcove/code/datums/loadout.dm
+++ b/modular_causticcove/code/datums/loadout.dm
@@ -116,3 +116,9 @@
name = "Artificer's cap"
path = /obj/item/clothing/head/roguetown/articap
+//Reform Gem option in the Loadout!
+
+/datum/loadout_item/reform_gem
+ name = "Reform Gem"
+ path = /obj/item/reformation_gem
+ cost = 0 //Make it free to grab! It's a scene tool after all.
diff --git a/modular_causticcove/code/datums/spontaneous_vore.dm b/modular_causticcove/code/datums/spontaneous_vore.dm
index 35f709c4b39..6c84e7ce232 100644
--- a/modular_causticcove/code/datums/spontaneous_vore.dm
+++ b/modular_causticcove/code/datums/spontaneous_vore.dm
@@ -83,10 +83,11 @@
if(!destination_belly)
return
if(source.stat != DEAD && source.trash_catching)
- if(source.adminbus_trash || /*is_type_in_list(O, GLOB.edible_trash) &&*/ O.trash_eatable && !is_type_in_list(O, GLOB.item_vore_blacklist)) //Caustic - It's still in here if we need a check for a whitelist for stuff ate, but... technically people have been doing that with all items so far. Maybe it's fine to keep it that way?
- source.visible_message(span_warning("[O] is thrown directly into [source]'s [lowertext(destination_belly.name)]!"))
- destination_belly.nom_atom(O)
- return COMSIG_CANCEL_HITBY
+ if(length(destination_belly.contents) < 6) //Lets add a limiter to how many items can be in one belly, sure someone can abuse it by making many... but that's a player issue we can deal with.
+ if(source.adminbus_trash || destination_belly.validate_item_size(O) ||/*is_type_in_list(O, GLOB.edible_trash) &&*/ O.trash_eatable && !is_type_in_list(O, GLOB.item_vore_blacklist)) //Caustic - Trash Eatable was unused really, we'd otherwise have to go through and add it in to all items.
+ source.visible_message(span_warning("[O] is thrown directly into [source]'s [lowertext(destination_belly.name)]!"))
+ destination_belly.nom_atom(O)
+ return COMSIG_CANCEL_HITBY
//Throwing a prey into a pred takes priority. After that it checks to see if the person being thrown is a pred.
if(isliving(hitby))
diff --git a/modular_causticcove/code/modules/baycode_port_helpers/baycode_port_helpers.dm b/modular_causticcove/code/modules/baycode_port_helpers/baycode_port_helpers.dm
index 45d10ede507..ef4e1d218ca 100644
--- a/modular_causticcove/code/modules/baycode_port_helpers/baycode_port_helpers.dm
+++ b/modular_causticcove/code/modules/baycode_port_helpers/baycode_port_helpers.dm
@@ -199,7 +199,7 @@ GLOBAL_LIST_EMPTY(icon_state_lists)
return health
/mob/living/carbon/human/getActualFuckingHealth()
- return health //getMaxHealth() - ((getBruteLoss() + getFireLoss() + getToxLoss() + getOxyLoss()))
+ return getMaxHealth() - getCloneLoss() //getMaxHealth() - ((getBruteLoss() + getFireLoss() + getToxLoss() + getOxyLoss()))
/mob/living/proc/nutrition_percent()
return 100 * nutrition / maxnutrition
diff --git a/modular_causticcove/code/modules/character_directory/character_directory.dm b/modular_causticcove/code/modules/character_directory/character_directory.dm
index 9010b6da571..4acb4fbed69 100644
--- a/modular_causticcove/code/modules/character_directory/character_directory.dm
+++ b/modular_causticcove/code/modules/character_directory/character_directory.dm
@@ -1,5 +1,37 @@
GLOBAL_DATUM(character_directory, /datum/character_directory)
+/proc/get_character_ad_value(mob/living/carbon/human/character, datum/preferences/prefs, datum/mind/mind)
+ var/current_ad = prefs?.directory_ad
+ if(isnull(current_ad))
+ current_ad = mind?.directory_ad
+ if(isnull(current_ad))
+ current_ad = character?.client?.prefs?.directory_ad
+ if(isnull(current_ad))
+ current_ad = character?.mind?.directory_ad
+ return current_ad
+
+/proc/set_character_ad_value(mob/living/carbon/human/character, datum/preferences/prefs, datum/mind/mind, new_value, notify_roleplay_viewers = FALSE)
+ if(prefs)
+ prefs.directory_ad = new_value
+ prefs.save_character()
+ if(mind)
+ mind.directory_ad = new_value
+
+ if(character)
+ if(new_value)
+ var/formatted_ad = parsemarkdown_basic(html_encode(new_value), hyperlink = TRUE)
+ LAZYSET(GLOB.roleplay_ads, character.mobid, "[html_encode(character.real_name)] - [formatted_ad]
")
+
+ if(notify_roleplay_viewers)
+ for(var/client/advertisee in (GLOB.clients - character.client))
+ if(!(advertisee.prefs.toggles & ROLEPLAY_ADS))
+ continue
+ to_chat(advertisee, span_info("[character.real_name] has set a roleplay ad."))
+ else
+ LAZYREMOVE(GLOB.roleplay_ads, character.mobid)
+
+ refresh_character_ad_examine_panels(character, prefs || character?.client?.prefs, mind || character?.mind)
+
/client/verb/show_character_directory()
set name = "Character Directory"
set category = "OOC"
@@ -96,6 +128,16 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
var/ooc_notes_style = null*/
var/gendertag = null
var/sexualitytag = null
+ var/rpguidance = "Unset"
+ switch(C.prefs.rp_guidance)
+ if(0) //Discourages Conflict
+ rpguidance = "Alternatives Preferred"
+ if(1) //Encourages Conflict
+ rpguidance = "Mechanics Willing"
+ if(2) //Same as normal. This can be changed in the future however if people wish. Encourages Conflict + Hunted.
+ rpguidance = "Mechanics Willing"
+ if(3)
+ rpguidance = "Neutral"
//var/eventtag = GLOB.vantag_choices_list[VANTAG_NONE]
var/flavor_text = null
var/custom_link = null
@@ -106,14 +148,14 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
if (C.mob?.mind) //could use ternary for all three but this is more efficient
tag = C.mob.mind.directory_tag || "Unset"
erptag = C.mob.mind.directory_erptag || "Unset"
- character_ad = C.mob.mind.directory_ad
+ character_ad = get_character_ad_value(C.mob, C.prefs, C.mob.mind)
gendertag = C.mob.mind.directory_gendertag || "Unset"
sexualitytag = C.mob.mind.directory_sexualitytag || "Unset"
//eventtag = GLOB.vantag_choices_list[C.mob.mind.vantag_preference]
else
tag = C.prefs.directory_tag || "Unset"
erptag = C.prefs.directory_erptag || "Unset"
- character_ad = C.prefs.directory_ad
+ character_ad = get_character_ad_value(null, C.prefs, null)
gendertag = C.prefs.directory_gendertag || "Unset"
sexualitytag = C.prefs.directory_sexualitytag || "Unset"
//eventtag = GLOB.vantag_choices_list[C.prefs.vantag_preference]
@@ -180,8 +222,11 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
// But if we can't find the name, they must be using a non-compatible mob type currently.
if(!name)
continue
+ if(character_ad)
+ character_ad = parsemarkdown_basic(html_encode(character_ad), hyperlink = TRUE)
directory_mobs.Add(list(list(
+ "ckey" = C.ckey,
"name" = name,
"species" = species,
/*"ooc_notes_favs" = ooc_notes_favs,
@@ -191,6 +236,7 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
"ooc_notes_style" = ooc_notes_style,*/
"gendertag" = gendertag,
"sexualitytag" = sexualitytag,
+ "rpguidance" = rpguidance,
//"eventtag" = eventtag,
"ooc_notes" = ooc_notes,
"tag" = tag,
@@ -219,9 +265,35 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
ui.user.setClickCooldown(10)
update_static_data(ui.user, ui)
return TRUE
+ else if(action == "openExamine")
+ return open_character_examine(ui.user, params["ckey"], params["open_ad"])
else
return check_for_mind_or_prefs(ui.user, action, params["overwrite_prefs"])
+/datum/character_directory/proc/open_character_examine(mob/user, target_ckey, open_ad = FALSE)
+ if(!user || !target_ckey)
+ return FALSE
+
+ var/client/target_client = GLOB.directory[target_ckey]
+ if(!target_client)
+ to_chat(user, span_warning("That character is no longer available. Try refreshing the directory."))
+ return FALSE
+
+ var/datum/examine_panel/character_examine_panel
+ if(ishuman(target_client.mob))
+ character_examine_panel = new(target_client.mob)
+ character_examine_panel.holder = target_client.mob
+ else if(target_client.prefs)
+ character_examine_panel = new
+ character_examine_panel.pref = target_client.prefs
+ else
+ to_chat(user, span_warning("That character does not currently have profile data available."))
+ return FALSE
+
+ character_examine_panel.viewing = user
+ character_examine_panel.ui_interact(user)
+ return TRUE
+
/datum/character_directory/proc/check_for_mind_or_prefs(mob/user, action, overwrite_prefs)
if (!user.client)
return
@@ -251,7 +323,7 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
to_chat(user, span_notice("You are now [!visible ? "shown" : "not shown"] in the directory."))
return set_for_mind_or_prefs(user, action, !visible, can_set_prefs, can_set_mind)
if ("editAd")
- var/current_ad = (can_set_mind ? user.mind.directory_ad : null) || (can_set_prefs ? user.client.prefs.directory_ad : null)
+ var/current_ad = get_character_ad_value(user, can_set_prefs ? user.client.prefs : null, can_set_mind ? user.mind : null)
var/new_ad = tgui_input_text(user, "Change your character ad", "Character Ad", current_ad, MAX_MESSAGE_LEN, TRUE, prevent_enter = TRUE)
if(isnull(new_ad))
return
@@ -304,11 +376,7 @@ GLOBAL_LIST_EMPTY(chardirectory_photos)
user.mind.show_in_directory = new_value
return TRUE
if ("editAd")
- if (can_set_prefs)
- user.client.prefs.directory_ad = new_value
- user.client.prefs.save_character()
- if (can_set_mind)
- user.mind.directory_ad = new_value
+ set_character_ad_value(user, can_set_prefs ? user.client.prefs : null, can_set_mind ? user.mind : null, new_value)
return TRUE
/*if ("setEventTag")
if (can_set_prefs)
diff --git a/modular_causticcove/code/modules/vore/eating/bellymodes_datum_vr.dm b/modular_causticcove/code/modules/vore/eating/bellymodes_datum_vr.dm
index 758a24d3b7a..6ca66dda0e0 100644
--- a/modular_causticcove/code/modules/vore/eating/bellymodes_datum_vr.dm
+++ b/modular_causticcove/code/modules/vore/eating/bellymodes_datum_vr.dm
@@ -47,7 +47,7 @@ GLOBAL_LIST_INIT(digest_modes, list())
if(!L)
return
- //Parasitic digestion immunity hook, used to be a synx istype check but this is more optimized.
+ //Parasitic digestion immunity hook, used to be a synx istype check but this is more optimized.
if(L.parasitic)
if(isliving(L))
var/paratox = B.digest_brute+B.digest_burn
@@ -61,30 +61,39 @@ GLOBAL_LIST_INIT(digest_modes, list())
// Deal digestion damage (and feed the pred)
var/old_health = L.getActualFuckingHealth()
- var/old_brute = L.getBruteLoss()
- var/old_burn = L.getFireLoss()
- var/old_oxy = L.getOxyLoss()
- var/old_tox = L.getToxLoss()
+ //var/old_brute = L.getBruteLoss()
+ //var/old_burn = L.getFireLoss()
+ //var/old_oxy = L.getOxyLoss()
+ //var/old_tox = L.getToxLoss()
var/old_clone = L.getCloneLoss()
+
L.adjustBruteLoss(B.digest_brute)
L.adjustFireLoss(B.digest_burn)
- L.adjustOxyLoss(B.digest_oxy)
- L.adjustToxLoss(B.digest_tox)
- L.adjustCloneLoss(B.digest_clone)
-
- if(old_brute > (L.maxHealth * 4.5) || old_burn > (L.maxHealth * 4.5)) //Bandaid Patch for unkillable mobs? Potentially just set the OxyLoss to 200 for one tick, which WILL kill them.
- L.adjustOxyLoss(200, forced = TRUE)
+ //L.adjustOxyLoss(B.digest_oxy)
+ //L.adjustToxLoss(B.digest_tox)
+ //L.adjustCloneLoss(B.digest_clone)
+
+ //if(old_brute > (L.maxHealth * 4.5) || old_burn > (L.maxHealth * 4.5)) //Bandaid Patch for unkillable mobs? Potentially just set the OxyLoss to 200 for one tick, which WILL kill them.
+ // L.adjustOxyLoss(200, forced = TRUE)
+ if(B.digest_brute > 1 || B.digest_burn > 1)
+ var/clone_dam = ((B.digest_brute + B.digest_burn) / B.digest_max) * 10 //At Max Digest, it will kill in 200/10 process ticks
+ L.adjustCloneLoss(clone_dam)
+ if(L.getCloneLoss() >= (L.maxHealth * 2) && !HAS_TRAIT(src, TRAIT_NODEATH))
+ L.death()
+ L.cure_blind(UNCONSCIOUS_BLIND)
//L.attempt_multishock(SHOCKFLAG_DIGESTION) //I don't believe this is in this codebase?
// Send a message when a prey-thing enters hard crit.
if(iscarbon(L) && old_health > 0 && L.getActualFuckingHealth() <= 0)
to_chat(B.owner, span_notice("You feel [L] go still within your [lowertext(B.name)]."))
- var/actual_brute = L.getBruteLoss() - old_brute
- var/actual_burn = L.getFireLoss() - old_burn
- var/actual_oxy = L.getOxyLoss() - old_oxy
- var/actual_tox = L.getToxLoss() - old_tox
+
+ //var/actual_brute = L.getBruteLoss() - old_brute
+ //var/actual_burn = L.getFireLoss() - old_burn
+ //var/actual_oxy = L.getOxyLoss() - old_oxy
+ //var/actual_tox = L.getToxLoss() - old_tox
var/actual_clone = L.getCloneLoss() - old_clone
- var/damage_gain = (actual_brute + actual_burn + actual_oxy/2 + actual_tox + actual_clone*2)*(B.nutrition_percent / 100)
+ //var/damage_gain = (actual_brute + actual_burn + actual_oxy/2 + actual_tox + actual_clone*2)*(B.nutrition_percent / 100)
+ var/damage_gain = (actual_clone*2)*(B.nutrition_percent / 100)
if(B.slow_digestion)
damage_gain = damage_gain * 0.5
var/offset = (1 + ((L.weight - 137) / 137)) // 130 pounds = .95 140 pounds = 1.02
@@ -95,7 +104,7 @@ GLOBAL_LIST_INIT(digest_modes, list())
consider_healthbar(L, old_health, B.owner)
if(offset && damage_gain > 0) // If any different than default weight, multiply the % of offset.
- if(B.show_liquids && B.reagent_mode_flags & DM_FLAG_REAGENTSDIGEST && B.reagents.total_volume < B.reagents.maximum_volume) //digestion producing reagents
+ if(B.reagent_mode_flags & DM_FLAG_REAGENTSDIGEST && B.reagents.total_volume < B.reagents.maximum_volume) //digestion producing reagents //Check previously had B.show_liquids && at the start?
B.owner_adjust_nutrition(offset * (3 * damage_gain / difference) * L.get_digestion_nutrition_modifier() * B.owner.get_digestion_efficiency_modifier()) //Uncertain if balanced fairly, can adjust by multiplier for the cost of reagent, dont go below 1 or else it will result in more nutrition than normal - Jack
B.digest_nutri_gain += offset * (1.5 * damage_gain / difference) * L.get_digestion_nutrition_modifier() * B.owner.get_digestion_efficiency_modifier() //for transfering nutrition value over to GenerateBellyReagents_digesting()
B.GenerateBellyReagents_digesting()
@@ -118,7 +127,7 @@ GLOBAL_LIST_INIT(digest_modes, list())
B.steal_nutrition(L)
if(L.nutrition < 100)
B.absorb_living(L)
- if(B.show_liquids && B.reagent_mode_flags & DM_FLAG_REAGENTSABSORB && B.reagents.total_volume < B.reagents.maximum_volume) //absorption reagent production
+ if(B.reagent_mode_flags & DM_FLAG_REAGENTSABSORB && B.reagents.total_volume < B.reagents.maximum_volume) //absorption reagent production //Check previously had B.show_liquids && at the start?
B.GenerateBellyReagents_absorbed() //A bonus for pred, I know for a fact prey is usually at zero nutrition when absorption finally happens
consider_healthbar(L, old_nutrition, B.owner)
return list("to_update" = TRUE)
@@ -188,21 +197,34 @@ GLOBAL_LIST_INIT(digest_modes, list())
var/oldstat = L.stat
if(L.stat == DEAD || !L.permit_healbelly) //healpref check
return null // Can't heal the dead with healbelly
+
//var/mob/living/carbon/human/H = L
- if(B.owner.nutrition > 90 && (L.getActualFuckingHealth() < L.getMaxHealth()))
- L.adjustBruteLoss(-2.5)
- L.adjustFireLoss(-2.5)
- L.adjustToxLoss(-5)
- L.adjustOxyLoss(-5)
- L.adjustCloneLoss(-1.25)
- B.owner.adjust_nutrition(-2)
- if(B.health_impacts_size)
- B.owner.handle_belly_update()
+ if(B.owner.nutrition > 90)
+ var/heal_actions = 0
+ if(L.health < L.getMaxHealth())
+ L.adjustBruteLoss(-2.5)
+ L.adjustFireLoss(-2.5)
+ L.adjustToxLoss(-5)
+ L.adjustOxyLoss(-5)
+ L.adjustCloneLoss(-1.25)
+ heal_actions += 1
if(L.nutrition <= 400)
L.adjust_nutrition(1)
- else if(B.owner.nutrition > 90 && (L.nutrition <= 400))
- B.owner.adjust_nutrition(-1)
- L.adjust_nutrition(1)
+ heal_actions += 1
+ if(L.blood_volume < BLOOD_VOLUME_NORMAL)
+ L.blood_volume = min(L.blood_volume+2.5, BLOOD_VOLUME_NORMAL)
+ heal_actions += 1
+ var/list/wCount = L.get_wounds()
+ if(length(wCount))
+ L.heal_wounds(2.5)
+ L.update_damage_overlays()
+ heal_actions += 1
+
+ if(heal_actions > 0)
+ B.owner.adjust_nutrition(-heal_actions)
+ if(B.health_impacts_size)
+ B.owner.handle_belly_update()
+
if(L.stat != oldstat)
return list("to_update" = TRUE)
diff --git a/modular_causticcove/code/modules/vore/eating/bellymodes_vr.dm b/modular_causticcove/code/modules/vore/eating/bellymodes_vr.dm
index 3a587f77732..79bc6803a38 100644
--- a/modular_causticcove/code/modules/vore/eating/bellymodes_vr.dm
+++ b/modular_causticcove/code/modules/vore/eating/bellymodes_vr.dm
@@ -188,14 +188,14 @@
L.Stun(5)
//Thickbelly flag
- if((mode_flags & DM_FLAG_THICKBELLY) && !L.muffled) //Caustic - This likely should function like a gag?
+ if((mode_flags & DM_FLAG_THICKBELLY) && !L.muffled) //Caustic - Now forces whispers on say!
L.muffled = TRUE
//Fix muffled sometimes being sticky.
else if(!(mode_flags & DM_FLAG_THICKBELLY) && L.muffled)
L.muffled = FALSE
//Force psay
- if((mode_flags & DM_FLAG_FORCEPSAY) && !L.forced_psay && L.absorbed) //Caustic - This might be 'private say' in any case of PSAY, so subtle 'says'
+ if((mode_flags & DM_FLAG_FORCEPSAY) && !L.forced_psay && L.absorbed) //Caustic - Now has it's own private "thinking" chat between all prey and the pred who absorbed them!
L.forced_psay = TRUE
//Fix forcepsay sometimes being sticky.
else if(!(mode_flags & DM_FLAG_FORCEPSAY) && L.forced_psay)
@@ -210,9 +210,9 @@
var/mob/living/carbon/human/H = L
//Numbing flag
- if(mode_flags & DM_FLAG_NUMBING) //Caustic - I don't think we have this in actually. Might need to make a reagent with an effect?
- if(H.reagents.get_reagent_amount(REAGENT_ID_NUMBENZYME) < 2)
- H.reagents.add_reagent(REAGENT_ID_NUMBENZYME,4)
+ if(mode_flags & DM_FLAG_NUMBING) //Caustic - Attempting to use Poppymilk as a numbing substitution.
+ if(H.reagents.get_reagent_amount(REAGENT_ID_POPPYMILK) < 2)
+ H.reagents.add_reagent(REAGENT_ID_POPPYMILK, 4)
//Worn items flag
if(mode_flags & DM_FLAG_AFFECTWORN && H.contaminate_pref)
@@ -354,7 +354,7 @@
if(L.nutrition >= 100)
var/oldnutrition = (L.nutrition * 0.05)
L.nutrition = (L.nutrition * 0.95)
- if(show_liquids && reagent_mode_flags & DM_FLAG_REAGENTSDRAIN && reagents.total_volume < reagents.maximum_volume) // draining reagent production //Added to this proc now since it's used for draining
+ if(reagent_mode_flags & DM_FLAG_REAGENTSDRAIN && reagents.total_volume < reagents.maximum_volume) // draining reagent production //Added to this proc now since it's used for draining //Check previously had show_liquids && at the start
owner_adjust_nutrition(oldnutrition * 0.75) //keeping the price static, due to how much nutrition can flunctuate
GenerateBellyReagents_absorbing() //Dont need unique proc so far
else
diff --git a/modular_causticcove/code/modules/vore/eating/inbelly_spawn.dm b/modular_causticcove/code/modules/vore/eating/inbelly_spawn.dm
index 878d1a6a23b..8be72021ca7 100644
--- a/modular_causticcove/code/modules/vore/eating/inbelly_spawn.dm
+++ b/modular_causticcove/code/modules/vore/eating/inbelly_spawn.dm
@@ -2,6 +2,10 @@
if(!potential_prey || !istype(potential_prey)) // Did our prey cease to exist?
return
+ if(!potential_prey.started_as_observer) //Lets check this, just to be sure no one spawns over and over this way... You gotta at least go to the main menu and observe to in-belly spawn.
+ to_chat(potential_prey, span_notice("In order to In-Belly Spawn, you need to join the round as an observer. Please don't attempt to use this as a free respawn!"))
+ return
+
// Are we cool with this prey spawning in at all?
var/answer = tgui_alert(src, "[potential_prey.client.prefs.real_name] wants to spawn in one of your bellies. Do you accept?", "Inbelly Spawning", list("Yes", "No"))
if(answer != "Yes")
@@ -86,7 +90,13 @@
joined_area.on_joining_game(new_character)
new_character.update_fov_angles()
+ new_character.after_creation()
+
GLOB.chosen_names += new_character.real_name
+ new_character.islatejoin = TRUE
+ SSticker.minds += new_character.mind //Is this what is needed to handle skill gain?
+ GLOB.joined_player_list += new_character.ckey
+ update_wretch_slots()
new_character.regenerate_icons()
new_character.update_transform()
@@ -95,11 +105,29 @@
if(absorbed)
target_belly.absorb_living(new_character) // Glorp.
- log_admin("[prey] (as [new_character.real_name] has spawned inside one of [pred]'s bellies.") // Log it. Avoid abuse.
- message_admins("[prey] (as [new_character.real_name] has spawned inside one of [pred]'s bellies.", 1)
+ log_admin("[prey] (as [new_character.real_name]) has spawned inside one of [pred]'s bellies.") // Log it. Avoid abuse.
+ message_admins("[prey] (as [new_character.real_name]) has spawned inside one of [pred]'s bellies.", 1)
return new_character // incase its ever needed
+/mob/dead/observer
+ var/enable_inbelly_spawn_attempts = FALSE
+
+/mob/dead/observer/verb/ToggleInBellySpawnAttempts()
+ set name = "Toggle In-Belly Spawn"
+ set desc = "Toggles the ability to attempt to In-Belly spawn on someone on Middle Mouse Click. Defaults to off to not cause any accidents!"
+ set category = "VORE"
+
+ enable_inbelly_spawn_attempts = !enable_inbelly_spawn_attempts
+ to_chat(src, span_notice("In-Belly spawn attempts [enable_inbelly_spawn_attempts ? "enabled! Middle-Mouse click on your pred to request a spawn (if they have it set up!) This is generally for ease of continuing a scene, you will spawn without any gear or stats and skills." : "disabled! Middle-Mouse clicks will revert to their usual actions."]"))
+
+/mob/dead/observer/MiddleClickOn(atom/A, params)
+ if(enable_inbelly_spawn_attempts && isliving(A))
+ var/mob/living/alive = A
+ alive.inbelly_spawn_prompt(src)
+ else
+ . = ..()
+
/*/mob/living/proc/soulcatcher_spawn_prompt(mob/observer/dead/prey, req_time) //We don't have soulcatchers or NIFs
if(tgui_alert(src, "[prey.name] wants to join into your Soulcatcher.","Soulcatcher Request",list("Deny", "Allow"), timeout=1 MINUTES) != "Allow")
to_chat(prey, span_warning("[src] has denied your request."))
diff --git a/modular_causticcove/code/modules/vore/eating/living_vr.dm b/modular_causticcove/code/modules/vore/eating/living_vr.dm
index ae263dcb7bf..6d86c1b1fbf 100644
--- a/modular_causticcove/code/modules/vore/eating/living_vr.dm
+++ b/modular_causticcove/code/modules/vore/eating/living_vr.dm
@@ -818,11 +818,15 @@
if(!I)
to_chat(src, span_notice("You are not holding anything."))
return
+
+ if(length(vore_selected.contents) >= 6) //Lets add a limiter to how many items can be in one belly, sure someone can abuse it by making many... but that's a player issue we can deal with.
+ to_chat(src, span_notice("Your [vore_selected.name] is already filled with objects!"))
+ return
//if(I.) //Caustic - Potential Whitelist can go here.
- if(!(I.grid_height <= world.icon_size || I.grid_height <= world.icon_size))
- to_chat(src,span_warning("You can't eat such a large thing !"))//yet <-- YET???
+ if(!vore_selected.validate_item_size(I))
+ to_chat(src,span_warning("You can't eat such a large thing !"))//yet //Yeah, it was 'yet' :P I just made it allow a bit bigger stuff.
return
if(do_after(src, 10 SECONDS)){
@@ -847,6 +851,20 @@
trash_catching = !trash_catching
to_chat(src, span_warning("Trash catching [trash_catching ? "enabled" : "disabled"]."))
+/obj/belly/proc/validate_item_size(var/obj/item/I)
+ var/can_nom = FALSE
+ if(I.grid_height <= world.icon_size && I.grid_width <= (world.icon_size * 2))
+ can_nom = TRUE
+
+ if(I.grid_height <= (world.icon_size * 2) && I.grid_width <= world.icon_size)
+ can_nom = TRUE
+
+ if(!can_nom && I.smeltresult && item_digest_mode == IM_SMELTING)
+ to_chat(src.owner, span_warning("With your [name] roaring to smelt something, you start to smelt down the [I]..."))
+ can_nom = TRUE
+
+ return can_nom
+
/*
/mob/living/proc/eat_minerals() //Actual eating abstracted so the user isn't given a prompt due to an argument in this verb.
set name = "Eat Minerals"
diff --git a/modular_causticcove/code/modules/vore/eating/vore_procs.dm b/modular_causticcove/code/modules/vore/eating/vore_procs.dm
index 684bc8cc70f..90b76bf1769 100644
--- a/modular_causticcove/code/modules/vore/eating/vore_procs.dm
+++ b/modular_causticcove/code/modules/vore/eating/vore_procs.dm
@@ -175,6 +175,8 @@
return FALSE
if(!prey.mind) //A quick check for if the Prey has no mind datum, it likely wasn't controlled by a player ever, so we don't need to check prefs.
+ if(prey.cmode && prey.stat == CONSCIOUS) //If they are in combat mode, which all AI mobs are, then they have to be not actively concious to be Nom'd. Should stop combat-noms.
+ return FALSE
return TRUE
if(!prey.devourable)
diff --git a/modular_causticcove/code/modules/vore/slosh.dm b/modular_causticcove/code/modules/vore/slosh.dm
index 4c8fee2b898..0ba6787fa6d 100644
--- a/modular_causticcove/code/modules/vore/slosh.dm
+++ b/modular_causticcove/code/modules/vore/slosh.dm
@@ -37,7 +37,6 @@
/datum/element/slosh/proc/choose_vorefootstep(mob/living/source)
if(step_count++ >= 5)
-
vore_organs_reagents = list()
var/highest_vol = 0
@@ -45,7 +44,7 @@
var/total_volume = B.reagents.total_volume
vore_organs_reagents += total_volume
- if(B.show_liquids && B.vorefootsteps_sounds && highest_vol < total_volume)
+ if(B.vorefootsteps_sounds && highest_vol < total_volume) //Whyyyy did this have B.show_liquids && at the start???
highest_vol = total_volume
if(highest_vol < 20)
@@ -64,12 +63,12 @@
handle_vorefootstep(source)
/datum/element/slosh/proc/handle_vorefootstep(mob/living/source)
- if(!CONFIG_GET(number/vorefootstep_volume) || !vore_footstep_volume)
+ if(!vore_footstep_volume) //!CONFIG_GET(number/vorefootstep_volume) || -- Commenting this out for now. Lets ... just go with the Vore Footstep Volume itself, basically?
return
var/S = pick(GLOB.slosh)
if(!S) return
- var/volume = CONFIG_GET(number/vorefootstep_volume) * (vore_footstep_volume/100)
+ var/volume = 100 * (vore_footstep_volume/100) //CONFIG_GET(number/vorefootstep_volume) * (vore_footstep_volume/100)
/*if(ishuman(source))
var/mob/living/carbon/human/human_source = source
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx
index 6b7ca45fb5d..9c2627f2be2 100644
--- a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx
+++ b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx
@@ -8,14 +8,15 @@ import type { mobEntry } from './types';
export const CharacterDirectoryList = (props: {
directory: mobEntry[];
- onOverlay: React.Dispatch>;
+ onOpenAd: (name: string, ad: string) => void;
}) => {
const { act } = useBackend();
- const { onOverlay, directory } = props;
+ const { directory, onOpenAd } = props;
const [sortId, setSortId] = useState('name');
const [sortOrder, setSortOrder] = useState(true);
+ const [hoveredAction, setHoveredAction] = useState(null);
return (
- Photo
+
+ Photo
+
- Vore Tag
+ Gender
- Gender
+ Sexuality
- Sexuality
+ ERP Tag
- ERP Tag
+ Vore Tag
+
+
+ RP Guidance
+
+ RP Ad
+
View
@@ -92,55 +107,98 @@ export const CharacterDirectoryList = (props: {
const i = sortOrder ? 1 : -1;
return a[sortId].localeCompare(b[sortId]) * i;
})
- .map((character, i) => (
-
-
- {character.photo ? (
-
-
-
-
-
- ) : null}
-
-
- {character.name}
-
-
- {character.species}
-
- {character.tag}
-
- {character.gendertag}
-
-
- {character.sexualitytag}
-
- {character.erptag}
-
-
-
-
- ))}
+ .map((character, i) => {
+ const hasCharacterAd = !!character.character_ad?.trim();
+ const adActionId = `${character.ckey}-ad`;
+ const viewActionId = `${character.ckey}-view`;
+
+ return (
+
+
+ {character.photo ? (
+
+
+
+
+
+ ) : null}
+
+
+ {character.name}
+
+
+ {character.species}
+
+
+ {character.tag}
+
+
+ {character.gendertag}
+
+
+ {character.sexualitytag}
+
+
+ {character.erptag}
+
+
+ {character.rpguidance}
+
+
+
+
+
+
+ );
+ })
+ }
);
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx
index 09b1663df21..614c9d10875 100644
--- a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx
+++ b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx
@@ -1,3 +1,4 @@
+// Old/redundant in-directory description renderer retained for reference.
import { Box, Button, Section, Table } from 'tgui-core/components';
import { MarkdownSpoilerText } from '../common/SpoilerText';
import { getTagColor } from './constants';
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx
index a4524e6078c..bb25162f894 100644
--- a/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx
+++ b/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx
@@ -1,11 +1,13 @@
-import { useState } from 'react';
+import { useMemo, useState } from 'react';
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Box, Button, LabeledList, Section, Stack } from 'tgui-core/components';
import { CharacterDirectoryList } from './CharacterDirectoryList';
-import { ViewCharacter } from './CharacterDirectoryViewCharacter';
-import type { Data, mobEntry } from './types';
+import type { Data } from './types';
+
+const CHARACTER_DIRECTORY_WINDOW_WIDTH = Math.round(816 * 1.15);
+const CHARACTER_DIRECTORY_WINDOW_HEIGHT = Math.round(722 * 1.15);
export const CharacterDirectory = (props) => {
const { act, data } = useBackend();
@@ -19,109 +21,186 @@ export const CharacterDirectory = (props) => {
directory,
} = data;
- const [overlay, setOverlay] = useState(null);
const [overwritePrefs, setOverwritePrefs] = useState(true);
+ const [directoryAd, setDirectoryAd] = useState(null);
+ const [directoryAdName, setDirectoryAdName] = useState('');
+ const directoryAdHTML = useMemo(() => ({
+ __html: directoryAd || '',
+ }), [directoryAd]);
+ const closeDirectoryAd = () => {
+ setDirectoryAd(null);
+ setDirectoryAdName('');
+ };
return (
-
+
+ {/*
+ Old/redundant in-directory description overlay retained for reference.
+ We now open the shared Examine Panel instead so directory views match
+ in-person "Examine closer" rendering.
+
{(overlay && (
)) || (
- <>
-
-
-
- Save to current preferences slot:
-
-
-
-
-
-
- }
- >
-
-
-
-
-
+ */}
+
+
+
+
+ Save to current preferences slot:
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setDirectoryAdName(name);
+ setDirectoryAd(ad);
+ }}
+ />
+
+ {/*
)}
+ */}
+ {!!directoryAd?.trim() && (
+
+
+ Close
+
+ }
+ >
+
+
+
+
+
+ )}
);
};
diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/types.ts b/tgui/packages/tgui/interfaces/CharacterDirectory/types.ts
index 58bd11778c8..57a828c3b6c 100644
--- a/tgui/packages/tgui/interfaces/CharacterDirectory/types.ts
+++ b/tgui/packages/tgui/interfaces/CharacterDirectory/types.ts
@@ -11,6 +11,7 @@ export type Data = {
};
export type mobEntry = {
+ ckey: string;
name: string;
species: string;
ooc_notes_favs: string;
@@ -20,6 +21,7 @@ export type mobEntry = {
ooc_notes_style: BooleanLike;
gendertag: string;
sexualitytag: string;
+ rpguidance: string;
eventtag: string;
ooc_notes: string;
tag: string;
diff --git a/tgui/packages/tgui/interfaces/ExaminePanel.tsx b/tgui/packages/tgui/interfaces/ExaminePanel.tsx
index ff4f3bc2813..cbc1c7fc2ea 100644
--- a/tgui/packages/tgui/interfaces/ExaminePanel.tsx
+++ b/tgui/packages/tgui/interfaces/ExaminePanel.tsx
@@ -1,5 +1,5 @@
-import { useState } from 'react';
-import { Button, Stack } from 'tgui-core/components';
+import { useEffect, useMemo, useState } from 'react';
+import { Box, Button, Section, Stack } from 'tgui-core/components';
import { useBackend } from '../backend';
import { PageButton } from '../components/PageButton';
@@ -14,9 +14,20 @@ enum Page {
export const ExaminePanel = (props) => {
const { act, data } = useBackend();
- const { is_vet, is_donator, character_name, is_playing, has_song, img_gallery, nsfw_img_gallery, examine_theme } = data;
+ const { is_donator, is_vet, character_name, is_playing, has_song, img_gallery, nsfw_img_gallery, examine_theme, character_ad } = data;
const [currentPage, setCurrentPage] = useState(Page.FlavorText);
+ const [showCharacterAd, setShowCharacterAd] = useState(false);
const hasAnyGalleryImages = img_gallery.length > 0 || nsfw_img_gallery.length > 0;
+ const hasCharacterAd = !!character_ad?.trim();
+ const characterAdHTML = useMemo(() => ({
+ __html: `${character_ad || ''}`,
+ }), [character_ad]);
+
+ useEffect(() => {
+ if (showCharacterAd && !hasCharacterAd) {
+ setShowCharacterAd(false);
+ }
+ }, [showCharacterAd, hasCharacterAd]);
let pageContents;
@@ -51,6 +62,18 @@ export const ExaminePanel = (props) => {
/>
)}
);
diff --git a/tgui/packages/tgui/interfaces/ExaminePanelData.ts b/tgui/packages/tgui/interfaces/ExaminePanelData.ts
index 34c52f53e8d..062e4b1339d 100644
--- a/tgui/packages/tgui/interfaces/ExaminePanelData.ts
+++ b/tgui/packages/tgui/interfaces/ExaminePanelData.ts
@@ -17,4 +17,5 @@ export type ExaminePanelData = {
is_donator: boolean;
// is_naked: boolean; // Caustic Edit: Removes naked requirement to view NSFW flavortext
examine_theme: string | null;
+ character_ad: string;
};
diff --git a/tgui/packages/tgui/interfaces/ExaminePanelPages.tsx b/tgui/packages/tgui/interfaces/ExaminePanelPages.tsx
index bcb3ba4ff2f..44f634fb8fc 100644
--- a/tgui/packages/tgui/interfaces/ExaminePanelPages.tsx
+++ b/tgui/packages/tgui/interfaces/ExaminePanelPages.tsx
@@ -150,10 +150,10 @@ export const ImageGalleryPage = (props) => {
const {
img_gallery,
nsfw_img_gallery,
- is_naked,
+ //is_naked, // Caustic Edit: Removes naked requirement to view NSFW flavortext
} = data;
const [galleryIndex, setGalleryIndex] = useState('SFW');
- const canViewNsfwGallery = is_naked && nsfw_img_gallery.length > 0;
+ const canViewNsfwGallery = nsfw_img_gallery.length > 0; //is_naked && nsfw_img_gallery.length > 0; // Caustic Edit: Removes naked requirement to view NSFW flavortext
useEffect(() => {
if (galleryIndex === 'NSFW' && !canViewNsfwGallery) {