mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-21 12:08:55 +01:00
274 lines
10 KiB
Plaintext
274 lines
10 KiB
Plaintext
#define FINAL_BUD_GROWTH_ICON 3
|
|
/**
|
|
* Kudzu Flower Bud
|
|
*
|
|
* A flower created by flowering kudzu which spawns a venus human trap after a certain amount of time has passed.
|
|
*
|
|
* A flower created by kudzu with the flowering mutation. Spawns a venus human trap after 2 minutes under normal circumstances.
|
|
* Also spawns 4 vines going out in diagonal directions from the bud. Any living creature not aligned with plants is damaged by these vines.
|
|
* Once it grows a venus human trap, the bud itself will destroy itself.
|
|
*
|
|
*/
|
|
/// Flower bud structure that ghost role spawns, actual spawn logic handled by /obj/effect/mob_spawn/ghost_role/venus_human_trap
|
|
/obj/structure/alien/resin/flower_bud //inheriting basic attack/damage stuff from alien structures
|
|
name = "flower bud"
|
|
desc = "A large pulsating plant..."
|
|
icon = 'icons/mob/spacevines.dmi'
|
|
icon_state = "bud0"
|
|
layer = SPACEVINE_MOB_LAYER
|
|
opacity = FALSE
|
|
canSmoothWith = null
|
|
smoothing_flags = NONE
|
|
density = FALSE
|
|
/// The amount of time it takes to create a venus human trap.
|
|
var/growth_time = 120 SECONDS
|
|
var/growth_icon = 0
|
|
|
|
/// Used by countdown to check time, this is when the timer will complete and the venus trap will spawn.
|
|
var/finish_time
|
|
/// The countdown ghosts see to when the plant will hatch
|
|
var/obj/effect/countdown/flower_bud/countdown
|
|
|
|
var/trait_flags = 0
|
|
|
|
var/list/vines = list()
|
|
|
|
/// The spawner that actually handles spawning the ghost role in
|
|
var/obj/effect/mob_spawn/ghost_role/venus_human_trap/spawner
|
|
|
|
/obj/structure/alien/resin/flower_bud/Initialize(mapload)
|
|
. = ..()
|
|
spawner = new(get_turf(loc))
|
|
spawner.flower_bud = src
|
|
countdown = new(src)
|
|
var/list/anchors = list()
|
|
anchors += locate(x-2,y+2,z)
|
|
anchors += locate(x+2,y+2,z)
|
|
anchors += locate(x-2,y-2,z)
|
|
anchors += locate(x+2,y-2,z)
|
|
|
|
for(var/turf/T in anchors)
|
|
vines += Beam(T, "vine", maxdistance=5, beam_type=/obj/effect/ebeam/vine)
|
|
finish_time = world.time + growth_time
|
|
addtimer(CALLBACK(src, PROC_REF(bear_fruit)), growth_time)
|
|
addtimer(CALLBACK(src, PROC_REF(progress_growth)), growth_time/4)
|
|
countdown.start()
|
|
|
|
/obj/structure/alien/resin/flower_bud/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
|
|
if((trait_flags & SPACEVINE_HEAT_RESISTANT) && damage_type == BURN)
|
|
damage_amount = 0
|
|
. = ..()
|
|
|
|
/obj/structure/alien/resin/flower_bud/attacked_by(obj/item/item, mob/living/user, list/modifiers, list/attack_modifiers)
|
|
LAZYSET(attack_modifiers, SILENCE_DEFAULT_MESSAGES, TRUE)
|
|
LAZYSET(attack_modifiers, FORCE_MULTIPLIER, 1)
|
|
if(item.damtype == BURN)
|
|
MODIFY_ATTACK_FORCE_MULTIPLIER(attack_modifiers, 4)
|
|
if(item.get_sharpness())
|
|
MODIFY_ATTACK_FORCE_MULTIPLIER(attack_modifiers, 16) // alien resin applies 75% reduction to brute damage so this actually x4 damage
|
|
return ..()
|
|
|
|
/obj/structure/alien/resin/flower_bud/Destroy()
|
|
QDEL_LIST(vines)
|
|
QDEL_NULL(countdown)
|
|
if(spawner) // anti harddel checks
|
|
if(!QDELETED(spawner))
|
|
qdel(spawner)
|
|
spawner = null
|
|
return ..()
|
|
|
|
/// Tells the spawner that the venus human trap is ready
|
|
/obj/structure/alien/resin/flower_bud/proc/bear_fruit()
|
|
visible_message(span_danger("The plant has borne fruit!"))
|
|
if(spawner)
|
|
spawner.bear_fruit()
|
|
|
|
/obj/structure/alien/resin/flower_bud/proc/progress_growth()
|
|
growth_icon++
|
|
icon_state = "bud[growth_icon]"
|
|
if(growth_icon == FINAL_BUD_GROWTH_ICON)
|
|
return
|
|
addtimer(CALLBACK(src, PROC_REF(progress_growth)), growth_time/4)
|
|
|
|
/obj/structure/alien/resin/flower_bud/attack_ghost(mob/user)
|
|
spawner.attack_ghost(user)
|
|
|
|
/obj/effect/ebeam/vine
|
|
name = "thick vine"
|
|
mouse_opacity = MOUSE_OPACITY_ICON
|
|
desc = "A thick vine, painful to the touch."
|
|
|
|
/obj/effect/ebeam/vine/Initialize(mapload)
|
|
. = ..()
|
|
var/static/list/loc_connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
|
|
)
|
|
AddElement(/datum/element/connect_loc, loc_connections)
|
|
|
|
/obj/effect/ebeam/vine/proc/on_entered(datum/source, atom/movable/AM)
|
|
SIGNAL_HANDLER
|
|
if(isliving(AM))
|
|
var/mob/living/L = AM
|
|
if(!isvineimmune(L))
|
|
L.adjustBruteLoss(5)
|
|
to_chat(L, span_alert("You cut yourself on the thorny vines."))
|
|
|
|
/**
|
|
* Venus Human Trap
|
|
*
|
|
* The result of a kudzu flower bud, these enemies use vines to drag prey close to them for attack.
|
|
*
|
|
* A carnivorious plant which uses vines to catch and ensnare prey. Spawns from kudzu flower buds.
|
|
* Each one can attach up to two temporary vines to objects or mobs and drag them around with it.
|
|
* Attempting to attach a vine to something with a vine already attached to it will pull all movable targets closer on command.
|
|
* Once the prey is in melee range, melee attacks from the venus human trap heals itself for 10% of its max health, assuming the target is alive.
|
|
* Akin to certain spiders, venus human traps can also be possessed and controlled by ghosts.
|
|
*
|
|
*/
|
|
|
|
/mob/living/basic/venus_human_trap
|
|
name = "venus human trap"
|
|
desc = "Now you know how the fly feels."
|
|
icon = 'icons/mob/spacevines.dmi'
|
|
icon_state = "venus_human_trap"
|
|
health_doll_icon = "venus_human_trap"
|
|
mob_biotypes = MOB_ORGANIC | MOB_PLANT
|
|
layer = SPACEVINE_MOB_LAYER
|
|
health = 100
|
|
maxHealth = 100
|
|
obj_damage = 60
|
|
melee_damage_lower = 10
|
|
melee_damage_upper = 20
|
|
minimum_survivable_temperature = 100
|
|
combat_mode = TRUE
|
|
basic_mob_flags = DEL_ON_DEATH
|
|
death_message = "collapses into bits of plant matter."
|
|
attacked_sound = 'sound/mobs/non-humanoids/venus_trap/venus_trap_hurt.ogg'
|
|
death_sound = 'sound/mobs/non-humanoids/venus_trap/venus_trap_death.ogg'
|
|
attack_sound = 'sound/mobs/non-humanoids/venus_trap/venus_trap_hit.ogg'
|
|
unsuitable_heat_damage = 5 // heat damage is different from cold damage since coldmos is significantly more common than plasmafires
|
|
unsuitable_cold_damage = 2 // they now do take cold damage, but this should be sufficiently small that it does not cause major issues
|
|
habitable_atmos = null
|
|
unsuitable_atmos_damage = 0
|
|
/// copied over from the code from eyeballs (the mob) to make it easier for venus human traps to see in kudzu that doesn't have the transparency mutation
|
|
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
|
|
// Real green, cause of course
|
|
lighting_cutoff_red = 10
|
|
lighting_cutoff_green = 35
|
|
lighting_cutoff_blue = 20
|
|
faction = list(FACTION_HOSTILE,FACTION_VINES,FACTION_PLANTS)
|
|
initial_language_holder = /datum/language_holder/venus
|
|
unique_name = TRUE
|
|
speed = 1.2
|
|
melee_attack_cooldown = 1.2 SECONDS
|
|
ai_controller = /datum/ai_controller/basic_controller/human_trap
|
|
///how much damage we take out of weeds
|
|
var/no_weed_damage = 12.5
|
|
///how much do we heal in weeds
|
|
var/weed_heal = 10
|
|
///if the balloon alert was shown atleast once, reset after healing in weeds
|
|
var/alert_shown = FALSE
|
|
|
|
/mob/living/basic/venus_human_trap/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/lifesteal, 5)
|
|
var/static/list/innate_actions = list(
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle = BB_TARGETED_ACTION,
|
|
)
|
|
grant_actions_by_list(innate_actions)
|
|
|
|
/mob/living/basic/venus_human_trap/RangedAttack(atom/victim)
|
|
if(!combat_mode)
|
|
return
|
|
var/datum/action/cooldown/mob_cooldown/tangle_ability = ai_controller.blackboard[BB_TARGETED_ACTION]
|
|
if(!istype(tangle_ability))
|
|
return
|
|
tangle_ability.Trigger(target = victim)
|
|
|
|
/mob/living/basic/venus_human_trap/Life(seconds_per_tick = SSMOBS_DT, times_fired)
|
|
. = ..()
|
|
if(!.)
|
|
return FALSE
|
|
|
|
var/vines_in_range = locate(/obj/structure/spacevine) in range(2, src)
|
|
if(!vines_in_range && !alert_shown)
|
|
alert_shown = TRUE
|
|
balloon_alert(src, "do not leave vines!")
|
|
else if(vines_in_range)
|
|
alert_shown = FALSE
|
|
|
|
adjustBruteLoss(vines_in_range ? -weed_heal : no_weed_damage) //every life tick take 20 damage if not near vines or heal 10 if near vines, 5 times out of weeds = u ded
|
|
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle
|
|
name = "Tangle"
|
|
button_icon = 'icons/mob/spacevines.dmi'
|
|
button_icon_state = "Light1"
|
|
desc = "Grabs a target with a sticky vine, allowing you to pull it alongside you."
|
|
cooldown_time = 8 SECONDS
|
|
/// An assoc list of all the plant's vines (beam = leash)
|
|
var/list/datum/beam/vines = list()
|
|
/// How far away a plant can attach a vine to something
|
|
var/vine_grab_distance = 4
|
|
/// how long does a vine attached to something last (and its leash) (lasts twice as long on nonliving things)
|
|
var/vine_duration = 2 SECONDS
|
|
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle/Remove(mob/remove_from)
|
|
QDEL_LIST(vines)
|
|
return ..()
|
|
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle/Activate(atom/movable/target_atom)
|
|
if(!ismovable(target_atom) || istype(target_atom, /obj/structure/spacevine))
|
|
return
|
|
if(target_atom.anchored)
|
|
owner.balloon_alert(owner, "can't pull!")
|
|
return
|
|
if(get_dist(owner, target_atom) > vine_grab_distance)
|
|
owner.balloon_alert(owner, "too far!")
|
|
return
|
|
var/list/target_turfs = get_line(owner, target_atom) - list(get_turf(owner), get_turf(target_atom))
|
|
for(var/turf/blockage in target_turfs)
|
|
if(blockage.is_blocked_turf(exclude_mobs = TRUE))
|
|
owner.balloon_alert(owner, "path blocked!")
|
|
return
|
|
|
|
var/datum/beam/new_vine = owner.Beam(target_atom, icon_state = "vine", time = vine_duration * (ismob(target_atom) ? 1 : 2), beam_type = /obj/effect/ebeam/vine, emissive = FALSE)
|
|
var/component = target_atom.AddComponent(/datum/component/leash, owner, vine_grab_distance)
|
|
RegisterSignal(new_vine, COMSIG_QDELETING, PROC_REF(remove_vine), new_vine)
|
|
vines[new_vine] = component
|
|
if(isliving(target_atom))
|
|
var/mob/living/victim = target_atom
|
|
victim.Knockdown(2 SECONDS)
|
|
StartCooldown()
|
|
return TRUE
|
|
|
|
/**
|
|
* Removes a vine from the list.
|
|
*
|
|
* Removes the vine from our list.
|
|
* Called specifically when the vine is about to be destroyed, so we don't have any null references.
|
|
* Arguments:
|
|
* * datum/beam/vine - The vine to be removed from the list.
|
|
*/
|
|
/datum/action/cooldown/mob_cooldown/projectile_attack/vine_tangle/proc/remove_vine(datum/beam/vine)
|
|
SIGNAL_HANDLER
|
|
|
|
qdel(vines[vine])
|
|
vines -= vine
|
|
|
|
/datum/ai_controller/basic_controller/human_trap
|
|
blackboard = list(
|
|
BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
|
|
)
|
|
|
|
ai_movement = /datum/ai_movement/basic_avoidance
|
|
idle_behavior = /datum/idle_behavior/idle_random_walk
|
|
planning_subtrees = list(
|
|
/datum/ai_planning_subtree/escape_captivity,
|
|
/datum/ai_planning_subtree/simple_find_target,
|
|
/datum/ai_planning_subtree/targeted_mob_ability/continue_planning,
|
|
/datum/ai_planning_subtree/attack_obstacle_in_path,
|
|
/datum/ai_planning_subtree/basic_melee_attack_subtree,
|
|
)
|
|
|
|
#undef FINAL_BUD_GROWTH_ICON
|