diff --git a/code/__defines/vore_prefs.dm b/code/__defines/vore_prefs.dm index 28eed19fcd..a1ded3bf27 100644 --- a/code/__defines/vore_prefs.dm +++ b/code/__defines/vore_prefs.dm @@ -29,6 +29,11 @@ target.stumble_vore = source.stumble_vore; \ target.phase_vore = source.phase_vore; \ \ + target.spont_belly_rear = source.spont_belly_rear; \ + target.spont_belly_left = source.spont_belly_left; \ + target.spont_belly_front = source.spont_belly_front; \ + target.spont_belly_right = source.spont_belly_right; \ + \ target.resizable = source.resizable; \ target.step_mechanics_pref = source.step_mechanics_pref; \ target.pickup_pref = source.pickup_pref; \ diff --git a/code/_helpers/type2type.dm b/code/_helpers/type2type.dm index 59cd38a927..4a40a5530c 100644 --- a/code/_helpers/type2type.dm +++ b/code/_helpers/type2type.dm @@ -97,29 +97,43 @@ dirs += "DOWN" return dirs.Join(" ") -// Converts an angle (degrees) into an ss13 direction -/proc/angle2dir(var/degree) - degree = (degree + 22.5) % 365 // 22.5 = 45 / 2 - if (degree < 45) return NORTH - if (degree < 90) return NORTHEAST - if (degree < 135) return EAST - if (degree < 180) return SOUTHEAST - if (degree < 225) return SOUTH - if (degree < 270) return SOUTHWEST - if (degree < 315) return WEST - return NORTH|WEST +//Converts an angle (degrees) into a ss13 direction +GLOBAL_LIST_INIT(modulo_angle_to_dir, list(NORTH,NORTHEAST,EAST,SOUTHEAST,SOUTH,SOUTHWEST,WEST,NORTHWEST)) +#define angle2dir(X) (GLOB.modulo_angle_to_dir[round((((X%360)+382.5)%360)/45)+1]) -// Returns the north-zero clockwise angle in degrees, given a direction -/proc/dir2angle(var/D) - switch (D) - if (NORTH) return 0 - if (SOUTH) return 180 - if (EAST) return 90 - if (WEST) return 270 - if (NORTHEAST) return 45 - if (SOUTHEAST) return 135 - if (NORTHWEST) return 315 - if (SOUTHWEST) return 225 +/proc/angle2dir_cardinal(degree) + degree = SIMPLIFY_DEGREES(degree) + switch(round(degree, 0.1)) + if(315.5 to 360, 0 to 45.5) + return NORTH + if(45.6 to 135.5) + return EAST + if(135.6 to 225.5) + return SOUTH + if(225.6 to 315.5) + return WEST + +//returns the north-zero clockwise angle in degrees, given a direction +/proc/dir2angle(D) + switch(D) + if(NORTH) + return 0 + if(SOUTH) + return 180 + if(EAST) + return 90 + if(WEST) + return 270 + if(NORTHEAST) + return 45 + if(SOUTHEAST) + return 135 + if(NORTHWEST) + return 315 + if(SOUTHWEST) + return 225 + else + return null /// Returns a list(x, y), being the change in position required to step in the passed in direction /proc/dir2offset(dir) diff --git a/code/datums/elements/vore/spontaneous_vore.dm b/code/datums/elements/vore/spontaneous_vore.dm index 13f22bb62e..f83ddbe9c4 100644 --- a/code/datums/elements/vore/spontaneous_vore.dm +++ b/code/datums/elements/vore/spontaneous_vore.dm @@ -28,7 +28,8 @@ //We are able to eat the person stumbling into us. if(can_stumble_vore(prey = target, pred = source)) //This is if the person stumbling into us is able to eat us! source.visible_message(span_vwarning("[target] flops carelessly into [source]!")) - source.begin_instant_nom(source, prey = target, pred = source, belly = source.vore_selected) + var/obj/belly/destination_belly = source.get_current_spont_belly(target) + source.begin_instant_nom(source, prey = target, pred = source, belly = destination_belly) target.stop_flying() return CANCEL_STUMBLED_INTO @@ -36,7 +37,8 @@ if(can_stumble_vore(prey = source, pred = target)) //This is if the person stumbling into us is able to be eaten by us! BROKEN! source.visible_message(span_vwarning("[target] flops carelessly into [source]!")) target.forceMove(get_turf(source)) - source.begin_instant_nom(target, prey = source, pred = target, belly = target.vore_selected) + var/obj/belly/destination_belly = target.get_current_spont_belly(source) + source.begin_instant_nom(target, prey = source, pred = target, belly = destination_belly) source.stop_flying() return CANCEL_STUMBLED_INTO @@ -72,11 +74,14 @@ //Handle object throw vore if(isitem(hitby)) var/obj/item/O = hitby - if(source.stat != DEAD && source.trash_catching && source.vore_selected) + var/obj/belly/destination_belly = source.get_current_spont_belly(O) + 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)) - source.visible_message(span_vwarning("[O] is thrown directly into [source]'s [lowertext(source.vore_selected.name)]!")) + source.visible_message(span_vwarning("[O] is thrown directly into [source]'s [lowertext(destination_belly.name)]!")) O.throwing = 0 - source.vore_selected.nom_atom(O) + 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. @@ -94,23 +99,25 @@ // PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE. // PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY. if(can_throw_vore(prey = thrown_mob, pred = source)) - if(!source.vore_selected) + var/obj/belly/destination_belly = source.get_current_spont_belly(thrown_mob) + if(!destination_belly) return - source.vore_selected.nom_atom(thrown_mob) //Eat them!!! - source.visible_message(span_vwarning("[thrown_mob] is thrown right into [source]'s [lowertext(source.vore_selected.name)]!")) + destination_belly.nom_atom(thrown_mob) //Eat them!!! + source.visible_message(span_vwarning("[thrown_mob] is thrown right into [source]'s [lowertext(destination_belly.name)]!")) source.on_throw_vore_special(TRUE, thrown_mob) add_attack_logs(thrown_mob.thrower,source,"Devoured [thrown_mob.name] via throw vore.") - return //We can stop here. We don't need to calculate damage or anything else. They're eaten. + return COMSIG_CANCEL_HITBY //We can stop here. We don't need to calculate damage or anything else. They're eaten. // PERSON BEING HIT: CAN BE DROP PREY, ALLOWS THROW VORE, AND IS DEVOURABLE. // PERSON BEING THROWN: CAN BE DROP PRED, ALLOWS THROW VORE. else if(can_throw_vore(prey = source, pred = thrown_mob))//Pred thrown into prey. - if(!thrown_mob.vore_selected) + var/obj/belly/destination_belly = thrown_mob.get_current_spont_belly(source) + if(!destination_belly) return - source.visible_message(span_vwarning("[source] suddenly slips inside of [thrown_mob]'s [lowertext(thrown_mob.vore_selected.name)] as [thrown_mob] flies into them!")) - thrown_mob.vore_selected.nom_atom(source) //Eat them!!! + source.visible_message(span_vwarning("[source] suddenly slips inside of [thrown_mob]'s [lowertext(destination_belly.name)] as [thrown_mob] flies into them!")) + destination_belly.nom_atom(source) //Eat them!!! add_attack_logs(thrown_mob.LAssailant,source,"Was Devoured by [thrown_mob.name] via throw vore.") - return + return COMSIG_CANCEL_HITBY //source = person standing up //crossed = person sliding @@ -120,12 +127,19 @@ if(source == crossed || !istype(crossed)) return + //Person being slipped into eats the person slipping if(can_slip_vore(pred = source, prey = crossed)) //If we can vore them go for it - source.begin_instant_nom(source, prey = crossed, pred = source, belly = source.vore_selected) + var/obj/belly/destination_belly = source.get_current_spont_belly(crossed) + if(!destination_belly) + return + source.begin_instant_nom(source, prey = crossed, pred = source, belly = destination_belly) return COMPONENT_BLOCK_CROSS //The person slipping eats the person being slipped into else if(can_slip_vore(pred = crossed, prey = source)) - source.begin_instant_nom(crossed, prey = source, pred = crossed, belly = crossed.vore_selected) //Must be + var/obj/belly/destination_belly = crossed.get_current_spont_belly(source) + if(!destination_belly) + return + source.begin_instant_nom(crossed, prey = source, pred = crossed, belly = destination_belly) //Must be return //We DON'T block it here. Pred can slip onto the prey's tile, no problem. diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 9506e220b1..bc8938441c 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -350,33 +350,9 @@ emp_act // if(buckled && buckled == AM) // return // Don't get hit by the thing we're buckled to. - //VORESTATION EDIT START - Allows for thrown vore! - //Throwing a prey into a pred takes priority. After that it checks to see if the person being thrown is a pred. - // I put more comments here for ease of reading. if(isliving(source)) - var/mob/living/thrown_mob = source - if(isanimal(thrown_mob) && !allowmobvore && !thrown_mob.ckey) //Is the thrown_mob an animal and we don't allow mobvore? + if(SEND_SIGNAL(src, COMSIG_LIVING_HIT_BY_THROWN_ENTITY, source, speed) & COMSIG_CANCEL_HITBY) return - // PERSON BEING HIT: CAN BE DROP PRED, ALLOWS THROW VORE. - // PERSON BEING THROWN: DEVOURABLE, ALLOWS THROW VORE, CAN BE DROP PREY. - if(can_throw_vore(src, thrown_mob)) - vore_selected.nom_atom(thrown_mob) //Eat them!!! - visible_message(span_vwarning("[thrown_mob] is thrown right into [src]'s [lowertext(vore_selected.name)]!")) - if(thrown_mob.loc != vore_selected) - vore_selected.nom_atom(thrown_mob) //Double check. Should never happen but...Weirder things have happened! - add_attack_logs(thrown_mob.thrower,src,"Devoured [thrown_mob.name] via throw vore.") - return //We can stop here. We don't need to calculate damage or anything else. They're eaten. - - // PERSON BEING HIT: CAN BE DROP PREY, ALLOWS THROW VORE, AND IS DEVOURABLE. - // PERSON BEING THROWN: CAN BE DROP PRED, ALLOWS THROW VORE. - else if(can_throw_vore(thrown_mob, src)) //Pred thrown into prey. - visible_message(span_vwarning("[src] suddenly slips inside of [thrown_mob]'s [lowertext(thrown_mob.vore_selected.name)] as [thrown_mob] flies into them!")) - thrown_mob.vore_selected.nom_atom(src) //Eat them!!! - if(src.loc != thrown_mob.vore_selected) - thrown_mob.vore_selected.nom_atom(src) //Double check. Should never happen but...Weirder things have happened! - add_attack_logs(thrown_mob.LAssailant,src,"Was Devoured by [thrown_mob.name] via throw vore.") - return - //VORESTATION EDIT END - Allows for thrown vore! if(isitem(source)) var/obj/item/O = source diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/vore.dm b/code/modules/mob/living/simple_mob/subtypes/vore/vore.dm index 6e1352176d..d8cb7be7dd 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/vore.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/vore.dm @@ -36,6 +36,10 @@ can_be_afk_pred = client.prefs_vr.can_be_afk_pred throw_vore = client.prefs_vr.throw_vore food_vore = client.prefs_vr.food_vore + spont_belly_rear = client.prefs_vr.spont_belly_rear + spont_belly_left = client.prefs_vr.spont_belly_left + spont_belly_front = client.prefs_vr.spont_belly_front + spont_belly_right = client.prefs_vr.spont_belly_right consume_liquid_belly = client.prefs_vr.consume_liquid_belly allow_spontaneous_tf = client.prefs_vr.allow_spontaneous_tf digest_leave_remains = client.prefs_vr.digest_leave_remains diff --git a/code/modules/vore/eating/living_vr.dm b/code/modules/vore/eating/living_vr.dm index 24e08d0ac8..652c6c31c0 100644 --- a/code/modules/vore/eating/living_vr.dm +++ b/code/modules/vore/eating/living_vr.dm @@ -775,6 +775,27 @@ var/belly = user.vore_selected return begin_instant_nom(user, prey, user, belly) +/mob/living/proc/get_current_spont_belly(atom/movable/preything) + var/direction_diff = angle2dir_cardinal(dir2angle(get_dir(src, preything)) - dir2angle(dir)) + var/spont_belly_name + switch(direction_diff) + if(NORTH) + if(spont_belly_front) + spont_belly_name = spont_belly_front + if(SOUTH) + if(spont_belly_rear) + spont_belly_name = spont_belly_rear + if(EAST) + if(spont_belly_right) + spont_belly_name = spont_belly_right + if(WEST) + if(spont_belly_left) + spont_belly_name = spont_belly_left + for(var/obj/belly/lookup_belly in vore_organs) + if(lookup_belly.name == spont_belly_name) + return lookup_belly + return vore_selected + /mob/living/proc/glow_toggle() set name = "Glow (Toggle)" set category = "Abilities.General" diff --git a/code/modules/vore/eating/mob_vr.dm b/code/modules/vore/eating/mob_vr.dm index af2c079f17..46acf99a3b 100644 --- a/code/modules/vore/eating/mob_vr.dm +++ b/code/modules/vore/eating/mob_vr.dm @@ -19,6 +19,10 @@ var/drop_vore = TRUE var/throw_vore = TRUE var/food_vore = TRUE + var/obj/belly/spont_belly_front = null + var/obj/belly/spont_belly_rear = null + var/obj/belly/spont_belly_left = null + var/obj/belly/spont_belly_right = null var/consume_liquid_belly = FALSE //starting off because if someone is into that, they'll toggle it first time they get the error. Otherway around would be more pref breaky. var/digest_pain = TRUE var/can_be_drop_prey = FALSE diff --git a/code/modules/vore/eating/panel_databackend/vorepanel_pref_data.dm b/code/modules/vore/eating/panel_databackend/vorepanel_pref_data.dm index 8fde893c2b..5e289505a9 100644 --- a/code/modules/vore/eating/panel_databackend/vorepanel_pref_data.dm +++ b/code/modules/vore/eating/panel_databackend/vorepanel_pref_data.dm @@ -43,6 +43,10 @@ "throw_vore" = owner.throw_vore, "phase_vore" = owner.phase_vore, "food_vore" = owner.food_vore, + "spont_belly_rear" = owner.spont_belly_rear, + "spont_belly_left" = owner.spont_belly_left, + "spont_belly_front" = owner.spont_belly_front, + "spont_belly_right" = owner.spont_belly_right, "consume_liquid_belly" = owner.consume_liquid_belly, "digest_pain" = owner.digest_pain, "eating_privacy_global" = owner.eating_privacy_global, @@ -69,7 +73,12 @@ "aestethic_messages" = compile_aesthetic_messages(owner), "vore_sprite_color" = owner.vore_sprite_color, "vore_sprite_multiply" = owner.vore_sprite_multiply, - "vore_icon_options" = owner.vore_icon_bellies + "vore_icon_options" = owner.vore_icon_bellies, + // spont options + "spont_rear" = owner.spont_belly_rear, + "spont_front" = owner.spont_belly_front, + "spont_left" = owner.spont_belly_left, + "spont_right" = owner.spont_belly_right ) /datum/vore_look/proc/compile_aesthetic_messages(mob/owner) diff --git a/code/modules/vore/eating/panel_databackend/vorepanel_set_attribute.dm b/code/modules/vore/eating/panel_databackend/vorepanel_set_attribute.dm index e0392c62c0..59a921dbf0 100644 --- a/code/modules/vore/eating/panel_databackend/vorepanel_set_attribute.dm +++ b/code/modules/vore/eating/panel_databackend/vorepanel_set_attribute.dm @@ -822,25 +822,25 @@ host.vore_selected.clear_preview(host) //Clears the stomach overlay. This is a failsafe but shouldn't occur. . = TRUE if("b_fullscreen_color") - var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.belly_fullscreen_color = newcolor host.vore_selected.update_internal_overlay() . = TRUE if("b_fullscreen_color2") - var/newcolor2 = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color2) + var/newcolor2 = sanitize_hexcolor(lowertext(params["val"])) if(newcolor2) host.vore_selected.belly_fullscreen_color2 = newcolor2 host.vore_selected.update_internal_overlay() . = TRUE if("b_fullscreen_color3") - var/newcolor3 = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color3) + var/newcolor3 = sanitize_hexcolor(lowertext(params["val"])) if(newcolor3) host.vore_selected.belly_fullscreen_color3 = newcolor3 host.vore_selected.update_internal_overlay() . = TRUE if("b_fullscreen_color4") - var/newcolor4 = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.belly_fullscreen_color4) + var/newcolor4 = sanitize_hexcolor(lowertext(params["val"])) if(newcolor4) host.vore_selected.belly_fullscreen_color4 = newcolor4 host.vore_selected.update_internal_overlay() @@ -1003,7 +1003,7 @@ host.handle_belly_update() host.updateVRPanel() if("b_undergarment_color") - var/newcolor = tgui_color_picker(user, "Choose a color.", "", host.vore_selected.undergarment_color) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.undergarment_color = newcolor host.handle_belly_update() @@ -1015,17 +1015,17 @@ host.vore_selected.tail_to_change_to = tail_choice . = TRUE if("b_tail_color") - var/newcolor = tgui_color_picker(user, "Choose tail color.", "", host.vore_selected.tail_colouration) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.tail_colouration = newcolor . = TRUE if("b_tail_color2") - var/newcolor = tgui_color_picker(user, "Choose tail secondary color.", "", host.vore_selected.tail_extra_overlay) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.tail_extra_overlay = newcolor . = TRUE if("b_tail_color3") - var/newcolor = tgui_color_picker(user, "Choose tail tertiary color.", "", host.vore_selected.tail_extra_overlay2) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.tail_extra_overlay2 = newcolor . = TRUE diff --git a/code/modules/vore/eating/panel_databackend/vorepanel_set_liqattribute.dm b/code/modules/vore/eating/panel_databackend/vorepanel_set_liqattribute.dm index e531a702c3..d963ee024f 100644 --- a/code/modules/vore/eating/panel_databackend/vorepanel_set_liqattribute.dm +++ b/code/modules/vore/eating/panel_databackend/vorepanel_set_liqattribute.dm @@ -102,7 +102,7 @@ host.vore_selected.update_internal_overlay() . = TRUE if("b_custom_reagentcolor") - var/newcolor = tgui_color_picker(user, "Choose custom color for liquid overlay. Cancel for normal reagent color.", "", host.vore_selected.custom_reagentcolor) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.custom_reagentcolor = newcolor else @@ -137,7 +137,7 @@ host.vore_selected.update_internal_overlay() . = TRUE if("b_mush_color") - var/newcolor = tgui_color_picker(user, "Choose custom color for mush overlay.", "", host.vore_selected.mush_color) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.mush_color = newcolor host.vore_selected.update_internal_overlay() @@ -194,7 +194,7 @@ host.vore_selected.update_internal_overlay() . = TRUE if("b_custom_ingested_color") - var/newcolor = tgui_color_picker(user, "Choose custom color for ingested metabolism overlay. Cancel for reagent-based dynamic blend.", "", host.vore_selected.custom_ingested_color) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(newcolor) host.vore_selected.custom_ingested_color = newcolor else diff --git a/code/modules/vore/eating/panel_databackend/vorepanel_vore_subdata.dm b/code/modules/vore/eating/panel_databackend/vorepanel_vore_subdata.dm index d6e2c650b0..f7de689f59 100644 --- a/code/modules/vore/eating/panel_databackend/vorepanel_vore_subdata.dm +++ b/code/modules/vore/eating/panel_databackend/vorepanel_vore_subdata.dm @@ -149,7 +149,7 @@ if(selected.message_mode || selected.escapechance) tab_data["subtypes"] += SUCCESS_MESSAGE if(!message_subtab) - message_subtab = ATTEMPT_MESSAGE + message_subtab = ITEM_MESSAGE if(message_subtab == ATTEMPT_MESSAGE) tab_data["possible_messages"] = list(TO_PREY, TO_YOU) if(!selected_message) diff --git a/code/modules/vore/eating/vore_vr.dm b/code/modules/vore/eating/vore_vr.dm index c6e694519d..154ca54b58 100644 --- a/code/modules/vore/eating/vore_vr.dm +++ b/code/modules/vore/eating/vore_vr.dm @@ -59,6 +59,10 @@ var/slip_vore = TRUE var/throw_vore = TRUE var/food_vore = TRUE + var/spont_belly_rear = null + var/spont_belly_left = null + var/spont_belly_right = null + var/spont_belly_front = null var/consume_liquid_belly = FALSE //starting off because if someone is into that, they'll toggle it first time they get the error. Otherway around would be more pref breaky. var/digest_pain = TRUE @@ -216,6 +220,10 @@ slip_vore = json_from_file["slip_vore"] food_vore = json_from_file["food_vore"] throw_vore = json_from_file["throw_vore"] + spont_belly_rear = json_from_file["spont_belly_rear"] + spont_belly_left = json_from_file["spont_belly_left"] + spont_belly_front = json_from_file["spont_belly_front"] + spont_belly_right = json_from_file["spont_belly_right"] consume_liquid_belly = json_from_file["consume_liquid_belly"] stumble_vore = json_from_file["stumble_vore"] digest_pain = json_from_file["digest_pain"] @@ -438,6 +446,10 @@ "slip_vore" = slip_vore, "stumble_vore" = stumble_vore, "throw_vore" = throw_vore, + "spont_belly_rear" = spont_belly_rear, + "spont_belly_left" = spont_belly_left, + "spont_belly_front" = spont_belly_front, + "spont_belly_right" = spont_belly_right, "allow_mind_transfer" = allow_mind_transfer, "phase_vore" = phase_vore, "consume_liquid_belly" = consume_liquid_belly, diff --git a/code/modules/vore/eating/vorepanel_vr.dm b/code/modules/vore/eating/vorepanel_vr.dm index 92e84fb7fc..0b69d1ff6d 100644 --- a/code/modules/vore/eating/vorepanel_vr.dm +++ b/code/modules/vore/eating/vorepanel_vr.dm @@ -49,6 +49,7 @@ var/sc_message_subtab // our soulcatcher message subtab var/aset_message_subtab var/selected_message + var/list/preset_colors /datum/vore_look/New(mob/new_host) if(istype(new_host)) @@ -59,6 +60,11 @@ host = null . = ..() +/datum/vore_look/tgui_close(mob/user) + if(user) + user.write_preference_directly(/datum/preference/text/preset_colors, preset_colors) + . = ..() + /datum/vore_look/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -113,6 +119,7 @@ ) data["min_belly_name"] = BELLIES_NAME_MIN data["max_belly_name"] = BELLIES_NAME_MAX + preset_colors = user.read_preference(/datum/preference/text/preset_colors) return data @@ -126,6 +133,7 @@ data["unsaved_changes"] = unsaved_changes data["active_tab"] = active_tab data["persist_edit_mode"] = host.persistend_edit_mode + data["presets"] = preset_colors // Inisde Data data["inside"] = get_inside_data(host) @@ -621,6 +629,8 @@ host.client.prefs_vr.food_vore = host.food_vore unsaved_changes = TRUE return TRUE + if("set_spont_belly") + return set_spont_belly(params) if("toggle_consume_liquid_belly") host.consume_liquid_belly = !host.consume_liquid_belly if(host.client.prefs_vr) @@ -651,7 +661,7 @@ var/belly_choice = params["attribute"] if(!(belly_choice in host.vore_icon_bellies)) return FALSE - var/newcolor = tgui_color_picker(ui.user, "Choose a color.", "", host.vore_sprite_color[belly_choice]) + var/newcolor = sanitize_hexcolor(lowertext(params["val"])) if(!newcolor) return FALSE host.vore_sprite_color[belly_choice] = newcolor @@ -884,6 +894,20 @@ unsaved_changes = TRUE host.soulgem.set_custom_message(message, SC_DELETE_MESSAGE) return TRUE + if("preset") + var/raw_data = lowertext(params["color"]) + var/index = lowertext(params["index"]) + var/list/entries = splittext(preset_colors, ";") + while(LAZYLEN(entries) < 20) + entries += "#FFFFFF" + if(LAZYLEN(entries) > 20) + entries.Cut(21) + var/hex = sanitize_hexcolor(raw_data) + if (!hex || !isnum(index) || entries[index] == hex) + return + entries[index] = hex + preset_colors = entries.Join(";") + return FALSE /datum/vore_look/proc/pick_from_inside(mob/user, params) var/atom/movable/target = locate(params["pick"]) @@ -1386,6 +1410,50 @@ return TRUE +/datum/vore_look/proc/set_spont_belly(params) + switch(params["attribute"]) + if("rear") + var/spont_target = html_encode(params["val"]) + if(spont_target == "Current Selected") + host.spont_belly_rear = null + else + host.spont_belly_rear = spont_target + if(host.client.prefs_vr) + host.client.prefs_vr.spont_belly_rear = host.spont_belly_rear + unsaved_changes = TRUE + return TRUE + if("front") + var/spont_target = html_encode(params["val"]) + if(spont_target == "Current Selected") + host.spont_belly_front = null + else + host.spont_belly_front = spont_target + if(host.client.prefs_vr) + host.client.prefs_vr.spont_belly_front = host.spont_belly_front + unsaved_changes = TRUE + return TRUE + if("left") + var/spont_target = html_encode(params["val"]) + if(spont_target == "Current Selected") + host.spont_belly_left = null + else + host.spont_belly_left = spont_target + if(host.client.prefs_vr) + host.client.prefs_vr.spont_belly_left = host.spont_belly_left + unsaved_changes = TRUE + return TRUE + if("right") + var/spont_target = html_encode(params["val"]) + if(spont_target == "Current Selected") + host.spont_belly_right = null + else + host.spont_belly_right = spont_target + if(host.client.prefs_vr) + host.client.prefs_vr.spont_belly_right = host.spont_belly_right + unsaved_changes = TRUE + return TRUE + return FALSE + /datum/vore_look/proc/sanitize_fixed_list(var/list/messages, type, delim = "\n\n", limit) if(!limit) CRASH("[type] set message called without limit!") diff --git a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx index 98df3dbf1e..b411c38414 100644 --- a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx +++ b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx @@ -96,7 +96,11 @@ export const ColorPickerModal: React.FC = () => { }); useEffect(() => { - syncColorPreset(); + const timeoutId = setTimeout(() => { + syncColorPreset(); + }, 100); + + return () => clearTimeout(timeoutId); }, [selectedColor]); if (!title) { @@ -301,7 +305,6 @@ export const ColorSelector: React.FC = React.memo( ); const [showPresets, setShowPresets] = useState(false); - const rgb = hsvaToRgba(color); const hexColor = hsvaToHex(color); return ( @@ -334,14 +337,14 @@ export const ColorSelector: React.FC = React.memo( backgroundColor={hexColor} /> - - - + - - {possible_fullscreens.map((fullscreen) => ( - - - - ))} - - - ) : ( -
- - + + + +
+ + {editMode && ( - +
+ + + + + {possible_fullscreens.map((fullscreen) => ( + + + + ))} + +
- - - + )} + ); }; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VisualTab/VoreSpriteAffect.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VisualTab/VoreSpriteAffect.tsx index ca6d4fca4b..14776160a3 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VisualTab/VoreSpriteAffect.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VisualTab/VoreSpriteAffect.tsx @@ -1,5 +1,5 @@ import { Box, LabeledList, Stack } from 'tgui-core/components'; - +import { capitalize } from 'tgui-core/string'; import { spriteToTooltip } from '../../constants'; import type { BellyVisualData, HostMob } from '../../types'; import { VorePanelEditCheckboxes } from '../../VorePanelElements/VorePanelEditCheckboxes'; @@ -13,8 +13,9 @@ export const VoreSpriteAffects = (props: { editMode: boolean; bellyVisualData: BellyVisualData; hostMobtype: HostMob; + presets: string; }) => { - const { editMode, bellyVisualData, hostMobtype } = props; + const { editMode, bellyVisualData, hostMobtype, presets } = props; const { vore_sprite_flags, absorbed_voresprite, @@ -105,7 +106,7 @@ export const VoreSpriteAffects = (props: { subAction="b_belly_sprite_to_affect" editMode={editMode} options={belly_sprite_options} - entry={belly_sprite_to_affect} + entry={capitalize(belly_sprite_to_affect)} tooltip="Set the belly sprite to effect." /> @@ -143,11 +144,11 @@ export const VoreSpriteAffects = (props: { diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions.tsx index a48bffbecf..3c36f5491f 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyLiquidOptions.tsx @@ -11,10 +11,11 @@ import { LiquidOptionsRight } from './LiquidTab/LiquidOptionsRight'; export const VoreSelectedBellyLiquidOptions = (props: { editMode: boolean; bellyLiquidData: BellyLiquidData; + presets: string; }) => { const { act } = useBackend(); - const { editMode, bellyLiquidData } = props; + const { editMode, bellyLiquidData, presets } = props; const { show_liq, liq_interacts } = bellyLiquidData; return ( @@ -73,6 +74,7 @@ export const VoreSelectedBellyLiquidOptions = (props: { diff --git a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx index bae57ed560..6f484e2f55 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VoreSelectedBellyTabs/VoreSelectedBellyVisuals.tsx @@ -1,6 +1,6 @@ +import { useRef, useState } from 'react'; import { useBackend } from 'tgui/backend'; import { Button, LabeledList, Section, Stack } from 'tgui-core/components'; - import type { BellyVisualData, HostMob } from '../types'; import { VorePanelEditColor } from '../VorePanelElements/VorePanelEditColor'; import { VorePanelEditSwitch } from '../VorePanelElements/VorePanelEditSwitch'; @@ -9,12 +9,14 @@ import { VoreSpriteAffects } from './VisualTab/VoreSpriteAffect'; export const VoreSelectedBellyVisuals = (props: { editMode: boolean; + belly_name: string; bellyVisualData: BellyVisualData; hostMobtype: HostMob; + presets: string; }) => { const { act } = useBackend(); - const { editMode, bellyVisualData, hostMobtype } = props; + const { editMode, belly_name, bellyVisualData, hostMobtype, presets } = props; const { belly_fullscreen, colorization_enabled, @@ -28,6 +30,29 @@ export const VoreSelectedBellyVisuals = (props: { affects_voresprite, } = bellyVisualData; + const lastBellyRef = useRef(null); + const [editedColors, setEditedColors] = useState< + Partial> + >({}); + + if (belly_name !== lastBellyRef.current) { + lastBellyRef.current = belly_name; + setEditedColors({}); + } + + const updateColor = (index: number, val: string) => { + setEditedColors((prev) => ({ ...prev, [index]: val })); + }; + + const liveColorsToUse = editMode + ? [ + editedColors[0] ?? belly_fullscreen_color, + editedColors[1] ?? belly_fullscreen_color2, + editedColors[2] ?? belly_fullscreen_color3, + editedColors[3] ?? belly_fullscreen_color4, + ] + : null; + return ( @@ -38,7 +63,7 @@ export const VoreSelectedBellyVisuals = (props: { action="set_attribute" subAction="b_affects_vore_sprites" editMode={editMode} - tooltip="Allows you to toggle if this belly should effect voresprites" + tooltip="Allows you to toggle if this belly should affect voresprites" active={!!affects_voresprite} /> } @@ -48,6 +73,7 @@ export const VoreSelectedBellyVisuals = (props: { editMode={editMode} bellyVisualData={bellyVisualData} hostMobtype={hostMobtype} + presets={presets} /> )} @@ -65,7 +91,7 @@ export const VoreSelectedBellyVisuals = (props: { subAction="b_colorization_enabled" editMode={editMode} active={!!colorization_enabled} - tooltip="Switches between the legacy pre-colored icon set and the modern colorable one." + tooltip="Switches between legacy pre-colored icons and modern colorable overlay" /> @@ -112,44 +138,47 @@ export const VoreSelectedBellyVisuals = (props: { editMode={editMode} action="set_attribute" subAction="b_fullscreen_color" - value_of={null} back_color={belly_fullscreen_color} name_of="Color 1:" tooltip="Set the Vore FX overlay's first color." + presets={presets} + onRealtimeValue={(val) => updateColor(0, val)} /> updateColor(1, val)} /> updateColor(2, val)} /> updateColor(3, val)} /> >; active_belly: string | null; our_bellies: BellyData[]; belly_rub_target: string | null; @@ -22,11 +19,10 @@ export const VoreUserPreferencesAesthetic = (props: { vore_sprite_multiply: Record; vore_icon_options: string[]; aestethicMessages: AestMessageData; + presets: string; }) => { const { editMode, - persist_edit_mode, - toggleEditMode, active_belly, belly_rub_target, our_bellies, @@ -34,6 +30,7 @@ export const VoreUserPreferencesAesthetic = (props: { vore_sprite_multiply, vore_icon_options, aestethicMessages, + presets, } = props; const sanitizeCorruption = fixCorruptedData(aestethicMessages.active_message); @@ -51,18 +48,7 @@ export const VoreUserPreferencesAesthetic = (props: { ); return ( -
- } - > +
@@ -83,7 +69,7 @@ export const VoreUserPreferencesAesthetic = (props: { entry + "' sprite." } - value_of={undefined} + presets={presets} /> >; + active_belly: string | null; + our_bellies: BellyData[]; + spont_rear: string | null; + spont_front: string | null; + spont_left: string | null; + spont_right: string | null; +}) => { + const { + editMode, + persist_edit_mode, + toggleEditMode, + active_belly, + our_bellies, + spont_rear, + spont_front, + spont_left, + spont_right, + } = props; + + const getBellies = our_bellies.map((belly) => { + return belly.display_name ? belly.display_name : belly.name; + }); + + const locationNames = [...getBellies, 'Current Selected']; + + const capitalizedName = active_belly && capitalize(active_belly); + + return ( +
+ } + > + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/VorePanel/constants.ts b/tgui/packages/tgui/interfaces/VorePanel/constants.ts index dc190be121..310d5d9e91 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/constants.ts +++ b/tgui/packages/tgui/interfaces/VorePanel/constants.ts @@ -1,12 +1,8 @@ -export const stats: (string | undefined)[] = [undefined, 'average', 'bad']; +export const stats = [undefined, 'average', 'bad'] as const; -export const vorespawnAbsorbedText: string[] = ['No', 'Yes', 'Prey Choice']; +export const vorespawnAbsorbedText = ['No', 'Yes', 'Prey Choice']; -export const vorespawnAbsorbedColor: (string | undefined)[] = [ - undefined, - 'green', - 'orange', -]; +export const vorespawnAbsorbedColor = [undefined, 'green', 'orange'] as const; export const selectiveBellyOptions = ['Digest', 'Absorb']; @@ -25,7 +21,7 @@ export const digestModeToColor = { 'Encase In Egg': 'blue', 'Digest (Food Only)': 'red', 'Digest (Dispersed Damage)': 'red', -}; +} as const; export const reagentToColor = { Water: undefined, @@ -41,7 +37,7 @@ export const reagentToColor = { 'Concentrated Radium': 'orange', Tricordrazine: 'green', Ethanol: undefined, -}; +} as const; export const digestModeToPreyMode = { Hold: 'being held.', @@ -55,7 +51,7 @@ export const digestModeToPreyMode = { 'Size Steal': 'having your size stolen.', Heal: 'being healed.', 'Encase In Egg': 'being encased in an egg.', -}; +} as const; export const SYNTAX_REGEX = /%belly|%pred|%prey|%countpreytotal|%countpreyabsorbed|%countprey|%countghosts|%count|%digestedprey|%ghost|%item|%dest|%goo|%happybelly|%fat|%grip|%cozy|%angry|%acid|%snack|%hot|%snake/g; @@ -63,7 +59,7 @@ export const SYNTAX_COLOR = { '%belly': 'average', '%pred': 'bad', '%prey': 'good', -}; +} as const; export const tabToNames = [ 'Controls', @@ -74,7 +70,7 @@ export const tabToNames = [ 'Interactions', 'Contents', 'Liquid Options', -]; +] as const; export const modeToTooltip = { Numbing: 'Prey will recieve no pain from vorgan damage.', @@ -90,14 +86,14 @@ export const modeToTooltip = { 'Muffle Items': ' Muffles noise from items inside the vorgan.', 'TURBO MODE': 'Heavily increases tick speed of the vorgan (6x).', 'Absorbed Devour': 'Allows absorbed prey to devour other prey.', -}; +} as const; export const spriteToTooltip = { 'Normal Belly Sprite': "This belly will effect the mob's belly sprite if available.", 'Undergarment addition': "This belly will effect the mob's undergarment sprite if available.", -}; +} as const; export const liquidToTooltip = { 'Produce Liquids': @@ -108,7 +104,7 @@ export const liquidToTooltip = { 'Enables belly liquid production while prey is being absorbed.', 'Draining Liquids': 'Enables belly liquid production while prey is being drained.', -}; +} as const; export const messageTabLabel = [ 'Description', @@ -122,13 +118,13 @@ export const messageTabLabel = [ 'Bellymode', 'Idle', 'Liquid Fullness', -]; +] as const; export const eatingMessagePrivacy = { default: undefined, subtle: 'green', loud: 'red', -}; +} as const; export const robotBellyOptions = ['Sleeper', 'Vorebelly', 'Both']; @@ -142,14 +138,14 @@ export const nutriTimeToText = { 35: '6 hours', 71: '12 hours', 143: '24 hours', -}; +} as const; export const aestehticTabsToIcons = { 'Set Taste': 'grin-tongue', 'Set Smell': 'wind', 'Set Nutrition Examine': 'flask', 'Set Weight Examine': 'weight-hanging', -}; +} as const; export const preyAbilityToData = { devour_as_absorbed: { @@ -157,4 +153,4 @@ export const preyAbilityToData = { desc: 'Allows you to devour nearby prey after having been absorbed.', color: 'red', }, -}; +} as const; diff --git a/tgui/packages/tgui/interfaces/VorePanel/index.tsx b/tgui/packages/tgui/interfaces/VorePanel/index.tsx index ecc7be0342..027c67ba4c 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/index.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/index.tsx @@ -41,6 +41,7 @@ export const VorePanel = () => { general_pref_data, min_belly_name, max_belly_name, + presets, } = data; const [editMode, setEditMode] = useState(!!persist_edit_mode); @@ -67,6 +68,7 @@ export const VorePanel = () => { persist_edit_mode={persist_edit_mode} minBellyName={min_belly_name} maxBellyName={max_belly_name} + presets={presets} /> ); tabs[1] = ( @@ -94,6 +96,7 @@ export const VorePanel = () => { editMode={editMode} toggleEditMode={setEditMode} persist_edit_mode={persist_edit_mode} + presets={presets} /> ); tabs[4] = prefs && ; diff --git a/tgui/packages/tgui/interfaces/VorePanel/types.ts b/tgui/packages/tgui/interfaces/VorePanel/types.ts index f53ed3c42c..880a042ea6 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/types.ts +++ b/tgui/packages/tgui/interfaces/VorePanel/types.ts @@ -9,6 +9,7 @@ export type Data = { prey_abilities: PreyAbilityData[] | null; active_tab: number; persist_edit_mode: BooleanLike; + presets: string; host_mobtype: HostMob | null; our_bellies?: BellyData[] | null; min_belly_name: number; @@ -399,6 +400,10 @@ export type GeneralPrefData = { vore_sprite_color: Record; vore_sprite_multiply: Record; vore_icon_options: string[]; + spont_rear: string | null; + spont_front: string | null; + spont_left: string | null; + spont_right: string | null; }; export type AestMessageData = { diff --git a/tgui/packages/tgui/styles/interfaces/VorePanel.scss b/tgui/packages/tgui/styles/interfaces/VorePanel.scss index 8d76c4c012..5c10554c19 100644 --- a/tgui/packages/tgui/styles/interfaces/VorePanel.scss +++ b/tgui/packages/tgui/styles/interfaces/VorePanel.scss @@ -39,3 +39,18 @@ overflow: hidden; padding: var(--space-m); } + +.VorePanel__Floating { + height: 325px; + width: 580px; + background-color: var(--color-section); + backdrop-filter: var(--blur-medium); + border: var(--border-thickness-tiny) solid var(--color-border); + border-radius: var(--border-radius-medium); + box-shadow: var(--shadow-glow-medium) hsla(0, 0%, 0%, 0.5); + margin: var(--space-m); + color: var(--color-text); + overflow-y: scroll; + overflow-x: hidden; + padding: var(--space-m); +}