'Appendage Vore' AKA - Tongue Vore/Long Vore

- Credit to VerySoft for the tongue sprites!

- Adds in 'Long Vore' a selectable neutral trait that allows you to throw out your 'appendage' at a target. (5 tiles). Respects prefs.
- Gives frogs the special attack to do this as well.
- Adds in an admin-spawn gun that allows you to shoot the 'appendage' projectile as if you had the trait. Doesn't respect prefs, obviously.

Will detail this out more in the PR.
This commit is contained in:
C.L
2022-09-08 02:34:23 -04:00
parent 9337f7eea9
commit a91f18e503
10 changed files with 244 additions and 1 deletions
@@ -1152,4 +1152,186 @@
target.visible_message("<span class='warning'>\The [target] suddenly disappears, being dragged into the water!</span>",\
"<span class='danger'>You are dragged below the water and feel yourself slipping directly into \the [src]'s [vore_selected]!</span>")
to_chat(src, "<span class='notice'>You successfully drag \the [target] into the water, slipping them into your [vore_selected].</span>")
target.forceMove(src.vore_selected)
target.forceMove(src.vore_selected)
//This is the 'long vore' ability. Also known as "Grab Prey with appendage" or "Long Predatorial Reach". Or simply "Tongue Vore"
//It involves projectiles (which means it can be VV'd onto a gun for shenanigans)
//It can also be recolored via the proc, which persists between rounds.
/mob/living/proc/long_vore() // Allows the user to tongue grab a creature in range. Made a /living proc so frogs can frog you.
set name = "Grab Prey with appendage"
set category = "Abilities"
set desc = "Grab a target with any of your appendages!"
if(stat || paralysis || weakened || stunned || world.time < last_special) //No tongue flicking while stunned.
to_chat(src, "<span class='warning'>You can't do that in your current state.</span>")
return
last_special = world.time + 10 //Anti-spam.
if (!istype(src, /mob/living))
to_chat(src, "<span class='warning'>It doesn't work that way.</span>")
return
var/choice = tgui_alert(src, "Do you wish to change the color of your appendage or use it?", "Selection List", list("Use it", "Color"))
if(choice == "Color") //Easy way to set color so we don't bloat up the menu with even more buttons.
var/new_color = input(usr, "Choose a color to set your appendage to!", "", appendage_color) as color|null
if(new_color)
appendage_color = new_color
else
var/list/targets = list() //IF IT IS NOT BROKEN. DO NOT FIX IT.
for(var/mob/living/L in range(5, src))
if(!istype(L, /mob/living)) //Don't eat anything that isn't mob/living. Failsafe.
continue
if(L == src) //no eating yourself. 1984.
continue
if(L.devourable && L.throw_vore && (L.can_be_drop_pred || L.can_be_drop_prey))
targets += L
if(!(targets.len))
to_chat(src, "<span class='notice'>No eligible targets found.</span>")
return
var/mob/living/target = tgui_input_list(src, "Please select a target.", "Victim", targets)
if(!target)
return
if(!istype(target, /mob/living)) //Safety.
to_chat(src, "<span class='warning'>You need to select a living tarrget!</span>")
return
if (get_dist(src,target) >= 6)
to_chat(src, "<span class='warning'>You need to be closer to do that.</span>")
return
visible_message("<span class='notice'>\The [src] attempts to snatch up [target]!</span>", \
"<span class='notice'>You attempt to snatch up [target]!</span>" )
playsound(src, 'sound/vore/sunesound/pred/schlorp.ogg', 25)
//Code to shoot the beam here.
var/obj/item/projectile/beam/appendage/appendage_attack = new /obj/item/projectile/beam/appendage(get_turf(loc))
appendage_attack.launch_projectile(target, BP_TORSO, src) //Send it.
last_special = world.time + 100 //Cooldown for successful strike.
/obj/item/projectile/beam/appendage //The tongue projecitle.
name = "appendage"
icon_state = "laser"
nodamage = 1
damage = 0
eyeblur = 0
check_armour = "bullet" //Not really needed, but whatever.
can_miss = FALSE //Let's not miss our tongue!
hitsound = 'sound/vore/sunesound/pred/schlorp.ogg'
hitsound_wall = 'sound/vore/sunesound/pred/schlorp.ogg'
excavation_amount = 0
hitscan_light_intensity = 0
hitscan_light_range = 0
muzzle_flash_intensity = 0
muzzle_flash_range = 0
impact_light_intensity = 0
impact_light_range = 0
light_range = 0 //No your tongue can not glow...For now.
light_power = 0
light_on = 0 //NO LIGHT
combustion = FALSE //No, your tongue can't set the room on fire.
pass_flags = PASSTABLE
muzzle_type = /obj/effect/projectile/muzzle/appendage
tracer_type = /obj/effect/projectile/tracer/appendage
impact_type = /obj/effect/projectile/impact/appendage
/obj/item/projectile/beam/appendage/generate_hitscan_tracers()
if(firer) //This neat little code block allows for C O L O R A B L E tongues! Correction: 'Appendages'
if(istype(firer,/mob/living))
var/mob/living/originator = firer
color = originator.appendage_color
..()
/obj/item/projectile/beam/appendage/on_hit(var/atom/target)
if(target == firer) //NO EATING YOURSELF
return
if(istype(target, /mob/living))
var/mob/living/M = target
var/throw_range = get_dist(firer,M)
if(istype(M))
M.throw_at(firer, throw_range, M.throw_speed, firer) //Fun fact: living things have a throw_speed of 2.
M.updateicon()
else //Anything that isn't a /living
return
if(istype(target, /obj/item/)) //We hit an object? Pull it. This can only happen via admin shenanigans such as a gun being VV'd with this projectile.
var/obj/item/hit_object = target
if(hit_object.density || hit_object.anchored)
if(istype(firer, /mob/living))
var/mob/living/originator = firer
originator.Weaken(2) //If you hit something dense or anchored, fall flat on your face.
originator.visible_message("<span class='warning'>\The [originator] trips over their self and falls flat on their face!</span>", \
"<span class='warning'>You trip over yourself and fall flat on your face!</span>" )
playsound(originator, "punch", 25, 1, -1)
return
else
hit_object.throw_at(firer, throw_range, hit_object.throw_speed, firer)
if(istype(target, /turf/simulated/wall) || istype(target, /obj/machinery/door) || istype(target, /obj/structure/window)) //This can happen normally due to odd terrain. For some reason, it seems to not actually interact with walls.
if(istype(firer, /mob/living))
var/mob/living/originator = firer
originator.Weaken(2) //Hit a wall? Whoops!
originator.visible_message("<span class='warning'>\The [originator] trips over their self and falls flat on their face!</span>", \
"<span class='warning'>You trip over yourself and fall flat on your face!</span>" )
playsound(originator, "punch", 25, 1, -1)
return
else
return
/obj/effect/projectile/muzzle/appendage
icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "muzzle_appendage"
light_range = 0
light_power = 0
light_color = "#FF0D00"
/obj/effect/projectile/tracer/appendage
icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "appendage_beam"
light_range = 0
light_power = 0
light_color = "#FF0D00" //Doesn't matter. Not used.
/obj/effect/projectile/impact/appendage
icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "impact_appendage_combined"
light_range = 0
light_power = 0
light_color = "#FF0D00"
//LONG VORE ABILITY END
/obj/item/weapon/gun/energy/gun/tongue //This is the 'tongue' gun for admin memery.
name = "tongue"
desc = "A tongue that can be used to grab things."
icon = 'icons/mob/dogborg_vr.dmi'
icon_state = "synthtongue"
item_state = "gun"
fire_delay = null
force = 0
fire_delay = 1 //Adminspawn. No delay.
charge_cost = 0 //This is an adminspawn gun...No reason to force it to have a charge state.
projectile_type = /obj/item/projectile/beam/appendage
cell_type = /obj/item/weapon/cell/device/weapon/recharge
battery_lock = 1
modifystate = null
firemodes = list(
list(mode_name="vore", projectile_type=/obj/item/projectile/beam/appendage, modifystate=null, fire_sound='sound/vore/sunesound/pred/schlorp.ogg', charge_cost = 0),)
/obj/item/weapon/gun/energy/gun/tongue/update_icon() //No updating the icon.
icon_state = "synthtongue"
return
@@ -118,6 +118,16 @@
H.verbs |= /mob/living/carbon/human/proc/succubus_drain_finalize
H.verbs |= /mob/living/carbon/human/proc/succubus_drain_lethal
/datum/trait/neutral/long_vore
name = "Long Predatorial Reach"
desc = "Makes you able to use your tongue to grab creatures."
cost = 0
custom_only = FALSE
/datum/trait/neutral/long_vore/apply(var/datum/species/S,var/mob/living/carbon/human/H)
..(S,H)
H.verbs |= /mob/living/proc/long_vore
/datum/trait/neutral/feeder
name = "Feeder"
desc = "Allows you to feed your prey using your own body."
+20
View File
@@ -324,6 +324,26 @@
src.anchored = TRUE
src.pinned += O
//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.
if(istype(AM, /mob/living))
var/mob/living/thrown_mob = AM
if((can_be_drop_pred && throw_vore) && (thrown_mob.devourable && thrown_mob.throw_vore && thrown_mob.can_be_drop_prey)) //Prey thrown into pred.
vore_selected.nom_mob(thrown_mob) //Eat them!!!
visible_message("<span class='warning'>[thrown_mob] is thrown right into [src]'s [lowertext(vore_selected.name)]!</span>")
if(thrown_mob.loc != vore_selected)
thrown_mob.forceMove(vore_selected) //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.
else if((can_be_drop_prey && throw_vore && devourable) && (thrown_mob.can_be_drop_pred && thrown_mob.throw_vore)) //Pred thrown into prey.
visible_message("<span class='warning'>[src] suddenly slips inside of [thrown_mob]'s [lowertext(thrown_mob.vore_selected.name)] as [thrown_mob] flies into them!</span>")
thrown_mob.vore_selected.nom_mob(src) //Eat them!!!
if(src.loc != thrown_mob.vore_selected)
src.forceMove(thrown_mob.vore_selected) //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!
/mob/living/proc/embed(var/obj/O, var/def_zone=null)
O.loc = src
src.embedded += O
@@ -29,6 +29,7 @@
icon = 'icons/mob/vore.dmi'
movement_cooldown = 4 //fast as fucc boie.
can_be_drop_pred = 1 //They can tongue vore.
meat_amount = 4
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
@@ -39,6 +40,10 @@
ai_holder_type = /datum/ai_holder/simple_mob/melee
special_attack_min_range = 1
special_attack_max_range = 5
special_attack_cooldown = 100
// Pepe is love, not hate.
/mob/living/simple_mob/vore/aggressive/frog/New()
if(rand(1,1000000) == 1)
@@ -46,6 +51,21 @@
desc = "You found a rare Pepe. Screenshot for good luck."
..()
/mob/living/simple_mob/vore/aggressive/frog/do_special_attack(atom/A)
set_AI_busy(TRUE)
do_windup_animation(A, 20)
addtimer(CALLBACK(src, .proc/chargeend, A), 20)
/mob/living/simple_mob/vore/aggressive/frog/proc/chargeend(atom/A)
if(stat) //you are dead
set_AI_busy(FALSE)
return
playsound(src, 'sound/vore/sunesound/pred/schlorp.ogg', 25)
var/obj/item/projectile/beam/appendage/appendage_attack = new /obj/item/projectile/beam/appendage(get_turf(loc))
appendage_attack.old_style_target(A, src)
appendage_attack.launch_projectile(A, BP_TORSO, src)
set_AI_busy(FALSE)
// Activate Noms!
/mob/living/simple_mob/vore/aggressive/frog
vore_active = 1
@@ -26,6 +26,7 @@
permit_healbelly = client.prefs_vr.permit_healbelly
noisy = client.prefs_vr.noisy
selective_preference = client.prefs_vr.selective_preference
appendage_color = client.prefs_vr.appendage_color
drop_vore = client.prefs_vr.drop_vore
stumble_vore = client.prefs_vr.stumble_vore
+3
View File
@@ -47,6 +47,7 @@
var/vis_height = 32 // Sprite height used for resize features.
var/show_vore_fx = TRUE // Show belly fullscreens
var/selective_preference = DM_DEFAULT // Preference for selective bellymode
var/appendage_color = "#e03997" //Default pink. Used for the 'long_vore' trait.
var/regen_sounds = list(
'sound/effects/mob_effects/xenochimera/regen_1.ogg',
'sound/effects/mob_effects/xenochimera/regen_2.ogg',
@@ -271,6 +272,7 @@
P.can_be_drop_pred = src.can_be_drop_pred
P.allow_inbelly_spawning = src.allow_inbelly_spawning
P.allow_spontaneous_tf = src.allow_spontaneous_tf
P.appendage_color = src.appendage_color
P.step_mechanics_pref = src.step_mechanics_pref
P.pickup_pref = src.pickup_pref
P.drop_vore = src.drop_vore
@@ -318,6 +320,7 @@
can_be_drop_pred = P.can_be_drop_pred
allow_inbelly_spawning = P.allow_inbelly_spawning
allow_spontaneous_tf = P.allow_spontaneous_tf
appendage_color = P.appendage_color
step_mechanics_pref = P.step_mechanics_pref
pickup_pref = P.pickup_pref
drop_vore = P.drop_vore
+5
View File
@@ -70,6 +70,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
var/vore_smell = "nothing in particular"
var/appendage_color = "#e03997" //Default pink. Used for the 'long_vore' trait.
var/selective_preference = DM_DEFAULT
@@ -171,6 +172,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
vore_smell = json_from_file["vore_smell"]
permit_healbelly = json_from_file["permit_healbelly"]
noisy = json_from_file["noisy"]
appendage_color = json_from_file["appendage_color"]
selective_preference = json_from_file["selective_preference"]
show_vore_fx = json_from_file["show_vore_fx"]
can_be_drop_prey = json_from_file["can_be_drop_prey"]
@@ -210,6 +212,8 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
selective_preference = DM_DEFAULT
if (isnull(noisy))
noisy = FALSE
if (isnull(appendage_color))
appendage_color = "#e03997"
if(isnull(show_vore_fx))
show_vore_fx = TRUE
if(isnull(can_be_drop_prey))
@@ -283,6 +287,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
"vore_smell" = vore_smell,
"permit_healbelly" = permit_healbelly,
"noisy" = noisy,
"appendage_color" = appendage_color,
"selective_preference" = selective_preference,
"show_vore_fx" = show_vore_fx,
"can_be_drop_prey" = can_be_drop_prey,
+1
View File
@@ -272,6 +272,7 @@
"can_be_drop_pred" = host.can_be_drop_pred,
"allow_inbelly_spawning" = host.allow_inbelly_spawning,
"allow_spontaneous_tf" = host.allow_spontaneous_tf,
"appendage_color" = host.appendage_color,
"step_mechanics_active" = host.step_mechanics_pref,
"pickup_mechanics_active" = host.pickup_pref,
"noisy" = host.noisy,
+1
View File
@@ -231,6 +231,7 @@
new_mob.permit_healbelly = permit_healbelly
new_mob.noisy = noisy
new_mob.selective_preference = selective_preference
new_mob.appendage_color = appendage_color
new_mob.drop_vore = drop_vore
new_mob.stumble_vore = stumble_vore
new_mob.slip_vore = slip_vore
Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB