mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-08-31 00:59:16 +01:00
Demolishing Mobs (#9264)
* Work on the Bluespace Worm, Again. Space worms propagate their sprites/tooltips/meat types/segment types from the head back. Space worms have modified organ lists, only having a brain in their head. Bluespace worms have a unique sprite done by Sypsoti/Schnayy Bluespace worms have more xeno-organs in addition. Bluespace worms convert eaten things to Magmellite, instead of Phoron. * Target through walls. Distance traveled when not hitting a solid structure during charge is based on the length of the worm. Bluespace Worms drop xeno hide. * can_demolish includes trees and barricades simplemobs can now actually attack trees * Truncated version of my Bluespace Worm pr. Simplemob AI can be permitted to demolish walls, mineral turfs, and other common obstructions. Simplemob AI can be given vision through walls, to make greater use of wall demolishing. Spaceworm now has an AI controller with x-ray and demolishing capability to tunnel through rock / into buildings, and a wind-up charge that devours impacted mobs or structures. * Thermic spiders are demolishers, and able to detect prey through walls. * Inert. * Decreased chance for thermic spiders to spawn, matching carriers and webslingers. * Adjust for continued response & thoughts. Thermic dropped to only Demolishing by default. Still a barricade buster, not a wallhacker. Phorogenic bumped to be Demolishing. It's big, purple, and unlikely to care there's a twig in the way of its target. Thermic now has an xray variant for PoI or adminspawn, similar to carriers having the recursion variant. * Spiders: Demolishing Phorogen and Thermic moved to subtypes AI targeting only loops over range once, typecache manually checked for machines instead of making a new list from range again. * AI targeting dist check instead of range == FALSE check is a ! prefix, me. Worm no longer early returns off its overshoot charge call as it does nothing but end the proc regardless of a successful movement * Pain in two letters.
This commit is contained in:
@@ -7,9 +7,10 @@
|
||||
|
||||
var/can_breakthrough = TRUE // If false, the AI will not try to open a path to its goal, like opening doors.
|
||||
var/violent_breakthrough = TRUE // If false, the AI is not allowed to destroy things like windows or other structures in the way. Requires above var to be true.
|
||||
var/can_demolish = FALSE // If false, the AI is not allowed to destroy walls in the way. Requires the above var to be true.
|
||||
|
||||
var/stand_ground = FALSE // If true, the AI won't try to get closer to an enemy if out of range.
|
||||
|
||||
|
||||
// This does the actual attacking.
|
||||
/datum/ai_holder/proc/engage_target()
|
||||
ai_log("engage_target() : Entering.", AI_LOG_DEBUG)
|
||||
@@ -296,6 +297,27 @@
|
||||
ai_log("destroy_surroundings() : Attacking closed door.", AI_LOG_INFO)
|
||||
return melee_attack(D)
|
||||
|
||||
if(can_demolish) // Demolish walls, girders, barricades, and trees.
|
||||
if(istype(problem_turf, /turf/simulated/wall))
|
||||
ai_log("destroy_surroundings() : Attacking wall.", AI_LOG_INFO)
|
||||
return melee_attack(problem_turf)
|
||||
|
||||
if(istype(problem_turf, /turf/simulated/mineral))
|
||||
ai_log("destroy_surroundings() : Digging rock.", AI_LOG_INFO)
|
||||
return melee_attack(problem_turf)
|
||||
|
||||
if(istype(obstacle, /obj/structure/girder))
|
||||
ai_log("destroy_surroundings() : Attacking girder.", AI_LOG_INFO)
|
||||
return melee_attack(obstacle)
|
||||
|
||||
if(istype(obstacle, /obj/structure/barricade))
|
||||
ai_log("destroy_surroundings() : Attacking barricade.", AI_LOG_INFO)
|
||||
return melee_attack(obstacle)
|
||||
|
||||
if(istype(obstacle, /obj/structure/flora/tree))
|
||||
ai_log("destroy_surroundings() : Attacking tree.", AI_LOG_INFO)
|
||||
return melee_attack(obstacle)
|
||||
|
||||
ai_log("destroy_surroundings() : Exiting due to nothing to attack.", AI_LOG_INFO)
|
||||
return ATTACK_FAILED // Nothing to attack.
|
||||
|
||||
|
||||
@@ -30,6 +30,14 @@
|
||||
/datum/ai_holder/simple_mob/guard/give_chase
|
||||
home_low_priority = TRUE
|
||||
|
||||
// Able to destroy common, but usually-ignored barriers. Walls, Trees, Barricades
|
||||
/datum/ai_holder/simple_mob/demolishing
|
||||
can_demolish = TRUE
|
||||
|
||||
// Able to select targets with solid objects between them and it to make greater use of Demolishing
|
||||
/datum/ai_holder/simple_mob/demolishing/xray
|
||||
ignore_opacity = TRUE
|
||||
|
||||
// Doesn't really act until told to by something on the outside.
|
||||
/datum/ai_holder/simple_mob/inert
|
||||
hostile = FALSE
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
var/respect_alpha = TRUE // If true, mobs with a sufficiently low alpha will be treated as invisible.
|
||||
var/alpha_vision_threshold = FAKE_INVIS_ALPHA_THRESHOLD // Targets with an alpha less or equal to this will be considered invisible. Requires above var to be true.
|
||||
|
||||
var/ignore_opacity = FALSE // If true, can target through opaque objects/turfs. Essentially x-ray vision.
|
||||
|
||||
var/lose_target_time = 0 // world.time when a target was lost.
|
||||
var/lose_target_timeout = 5 SECONDS // How long until a mob 'times out' and stops trying to find the mob that disappeared.
|
||||
|
||||
@@ -27,13 +29,19 @@
|
||||
// Step 1, find out what we can see.
|
||||
/datum/ai_holder/proc/list_targets()
|
||||
. = ohearers(vision_range, holder)
|
||||
|
||||
. -= dview_mob // Not the dview mob!
|
||||
|
||||
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/structure/blob))
|
||||
|
||||
for(var/HM in typecache_filter_list(range(vision_range, holder), hostile_machines))
|
||||
if(can_see(holder, HM, vision_range))
|
||||
. += HM
|
||||
for(var/atom/movable/AM in range(vision_range, holder))
|
||||
// Ignoring opacity makes this a slightly hungrier proc as we're now not just checking range for specific machine types, but also living things outside hearing but inside range.
|
||||
if(ignore_opacity && (isliving(AM) || ((ispath(preferred_target) && istype(AM, preferred_target)) || (istype(AM) && AM == preferred_target))))
|
||||
. |= AM
|
||||
|
||||
if(hostile_machines[AM.type]) // Is the atom in the cache of machines we care about
|
||||
if(ignore_opacity || can_see(holder, AM, vision_range))
|
||||
. += AM
|
||||
|
||||
// Step 2, filter down possible targets to things we actually care about.
|
||||
/datum/ai_holder/proc/find_target(var/list/possible_targets, var/has_targets_list = FALSE)
|
||||
@@ -213,7 +221,7 @@
|
||||
ai_log("can_see_target() : Target ([the_target]) was too far from holder. Exiting.", AI_LOG_TRACE)
|
||||
return FALSE
|
||||
|
||||
if(!can_see(holder, the_target, view_range))
|
||||
if(!(ignore_opacity && (get_dist(holder, the_target) <= view_range)) && !can_see(holder, the_target, view_range))
|
||||
ai_log("can_see_target() : Target ([the_target]) failed can_see(). Exiting.", AI_LOG_TRACE)
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -356,6 +356,19 @@ var/global/list/mining_overlay_cache = list()
|
||||
excavation_level += Proj.excavation_amount
|
||||
update_archeo_overlays(Proj.excavation_amount)
|
||||
|
||||
/turf/simulated/mineral/attack_generic(var/mob/living/L, var/damage = 0, var/attack_text = "clawed")
|
||||
. = ..()
|
||||
if(!damage)
|
||||
visible_message(SPAN_NOTICE("\The [L] [attack_text] \the [src] ineffectively."))
|
||||
return FALSE
|
||||
|
||||
else
|
||||
excavation_level = excavation_level + damage
|
||||
visible_message(SPAN_WARNING("\The [L] [attack_text] \the [src], scattering [pick("gravel", "sand", "dust")]!"))
|
||||
if(excavation_level >= 200)
|
||||
GetDrilled(0)
|
||||
return TRUE
|
||||
|
||||
/turf/simulated/mineral/Bumped(AM)
|
||||
|
||||
. = ..()
|
||||
|
||||
@@ -398,6 +398,16 @@
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
// Same as the above, but ignores density of turfs.
|
||||
/turf/proc/CardinalTurfsWithAccessNoDensity(var/obj/item/card/id/ID)
|
||||
var/L[] = new()
|
||||
|
||||
for(var/d in cardinal)
|
||||
var/turf/T = get_step(src, d)
|
||||
if(istype(T))
|
||||
if(!LinkBlockedWithAccess(src, T, ID))
|
||||
L.Add(T)
|
||||
return L
|
||||
|
||||
// Similar to above but not restricted to just cardinal directions.
|
||||
/turf/proc/TurfsWithAccess(var/obj/item/card/id/ID, flags)
|
||||
|
||||
@@ -83,3 +83,10 @@
|
||||
explosion(src.loc, explosion_dev_range, explosion_heavy_range, explosion_light_range, explosion_flash_range)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/phorogenic/demolishing
|
||||
desc = "Crystalline and purple, it makes you shudder to look at it. This one has carapace-covered forelimbs and haunting purple eyes."
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/demolishing/xray
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/phorogenic/demolishing/xray
|
||||
desc = "Crystalline and purple, it makes you shudder to look at it. This one has carapace-covered forelimbs and haunting purple eyes with a malevolent sheen."
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/demolishing/xray
|
||||
|
||||
@@ -36,3 +36,11 @@
|
||||
poison_chance = 30
|
||||
poison_per_bite = 1
|
||||
poison_type = "thermite_v"
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/thermic/demolishing
|
||||
desc = "Mirage-cloaked and orange, it makes you shudder to look at it. This one has carapace-coated forelimbs and simmering orange eyes."
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/demolishing
|
||||
|
||||
/mob/living/simple_mob/animal/giant_spider/thermic/demolishing/xray
|
||||
desc = "Mirage-cloaked and orange, it makes you shudder to look at it. This one has carapace-coated forelegs and simmering orange eyes with a malevolent sheen."
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/demolishing/xray
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
attacktext = list("slammed")
|
||||
|
||||
organ_names = /decl/mob_organ_names
|
||||
organ_names = /decl/mob_organ_names/wormlike
|
||||
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/inert
|
||||
|
||||
@@ -38,6 +38,18 @@
|
||||
meat_amount = 2
|
||||
meat_type = /obj/item/reagent_containers/food/snacks/meat/worm
|
||||
|
||||
internal_organs = list(\
|
||||
/obj/item/organ/internal/heart/grey,\
|
||||
/obj/item/organ/internal/intestine/xeno,\
|
||||
/obj/item/organ/internal/lungs/grey,\
|
||||
/obj/item/organ/internal/xenos/plasmavessel,\
|
||||
/obj/item/organ/internal/xenos/acidgland\
|
||||
)
|
||||
|
||||
butchery_loot = list(\
|
||||
/obj/item/stack/animalhide = 3\
|
||||
)
|
||||
|
||||
var/mob/living/simple_mob/animal/space/space_worm/previous //next/previous segments, correspondingly
|
||||
var/mob/living/simple_mob/animal/space/space_worm/next //head is the nextest segment
|
||||
|
||||
@@ -51,6 +63,7 @@
|
||||
var/flatPlasmaValue = 5 //flat Phoron amount given for non-items
|
||||
|
||||
var/atom/currentlyEating // Worm's current Maw target.
|
||||
var/obj/item/stack/material/digested_sheet = /obj/item/stack/material/phoron // Material sheet type produced from digestion. Default, phoron.
|
||||
|
||||
var/z_transitioning = FALSE // Are we currently moving between Z-levels, or doing something that might mean we can't rely on distance checking for segments?
|
||||
var/sever_chunks = FALSE // Do we fall apart when dying?
|
||||
@@ -58,6 +71,16 @@
|
||||
var/time_maw_opened = 0
|
||||
var/maw_cooldown = 30 SECONDS
|
||||
var/open_maw = FALSE // Are we trying to eat things?
|
||||
var/charging = FALSE // Are we charging?
|
||||
|
||||
/*
|
||||
* The head. Holds multiple abilities.
|
||||
*/
|
||||
/decl/mob_organ_names/wormlike
|
||||
hit_zones = list("annuli") //Worms.
|
||||
|
||||
/decl/mob_organ_names/wormhead
|
||||
hit_zones = list("annuli", "cephalon", "mouth") //Worms, again. This time the head or "cephalon" though.
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head
|
||||
name = "space worm"
|
||||
@@ -71,6 +94,8 @@
|
||||
|
||||
hovering = TRUE
|
||||
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/destructive/worm
|
||||
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 25
|
||||
attack_sharp = TRUE
|
||||
@@ -78,10 +103,36 @@
|
||||
attack_armor_pen = 30
|
||||
attacktext = list("bitten", "gored", "gouged", "chomped", "slammed")
|
||||
|
||||
// Charging is a special attack, based on the tunneler spiders' namesake ability.
|
||||
special_attack_min_range = 2
|
||||
special_attack_max_range = 6
|
||||
special_attack_cooldown = 30 SECONDS
|
||||
|
||||
var/charge_warning = 0.5 SECONDS // How long the dig telegraphing is.
|
||||
var/charge_tile_speed = 2 // How long to wait between each tile. Higher numbers result in an easier to charge attack.
|
||||
|
||||
organ_names = /decl/mob_organ_names/wormhead
|
||||
|
||||
internal_organs = list(\
|
||||
/obj/item/organ/internal/heart/grey,\
|
||||
/obj/item/organ/internal/intestine,\
|
||||
/obj/item/organ/internal/lungs/grey,\
|
||||
/obj/item/organ/internal/xenos/plasmavessel,\
|
||||
/obj/item/organ/internal/immunehub,\
|
||||
/obj/item/organ/internal/brain/grey\
|
||||
)
|
||||
|
||||
animate_movement = SLIDE_STEPS
|
||||
|
||||
var/segment_count = 6
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/apply_bonus_melee_damage(atom/A, damage_amount)
|
||||
if(istype(A, /turf) || istype(A, /obj/machinery/door))
|
||||
damage_amount *= 5
|
||||
else if(istype(A, /obj/mecha))
|
||||
damage_amount *= 1.5
|
||||
return damage_amount
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/severed
|
||||
segment_count = 0
|
||||
severed = TRUE
|
||||
@@ -94,7 +145,7 @@
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/handle_special()
|
||||
..()
|
||||
update_body_faction()
|
||||
update_body_states()
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/update_icon()
|
||||
..()
|
||||
@@ -121,6 +172,8 @@
|
||||
current = newSegment
|
||||
current.faction = faction
|
||||
|
||||
update_body_states()
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/verb/toggle_devour()
|
||||
set name = "Toggle Feeding"
|
||||
set desc = "Extends your teeth for 30 seconds so that you can chew through mobs and structures alike."
|
||||
@@ -136,6 +189,96 @@
|
||||
else
|
||||
set_maw(!open_maw)
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/should_special_attack(atom/A)
|
||||
if(world.time < time_maw_opened + maw_cooldown)
|
||||
return FALSE
|
||||
// Make sure its possible for the worm to reach the target.
|
||||
var/turf/destination = get_turf(A)
|
||||
var/turf/starting_turf = get_turf(src)
|
||||
var/turf/T = starting_turf
|
||||
for(var/i = 1 to get_dist(starting_turf, destination))
|
||||
if(T == destination)
|
||||
break
|
||||
|
||||
T = get_step(T, get_dir(T, destination))
|
||||
return T == destination
|
||||
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/do_special_attack(atom/A)
|
||||
set waitfor = FALSE
|
||||
set_AI_busy(TRUE)
|
||||
|
||||
// Save where we're gonna go soon.
|
||||
var/turf/destination = get_turf(A)
|
||||
var/turf/starting_turf = get_turf(src)
|
||||
|
||||
// Telegraph to give a small window to dodge if really close.
|
||||
set_maw(TRUE)
|
||||
do_windup_animation(A, charge_warning)
|
||||
sleep(charge_warning) // For the telegraphing.
|
||||
|
||||
// Do the charge!
|
||||
visible_message(span("danger","\The [src] charges towards \the [A]!"))
|
||||
|
||||
if(!handle_charge(destination))
|
||||
set_AI_busy(FALSE)
|
||||
return FALSE
|
||||
|
||||
// Did we make it?
|
||||
if(!(src in destination))
|
||||
set_AI_busy(FALSE)
|
||||
return FALSE
|
||||
|
||||
var/overshoot = TRUE
|
||||
|
||||
// Test if something is at destination.
|
||||
for(var/mob/living/L in destination)
|
||||
if(L == src)
|
||||
continue
|
||||
|
||||
visible_message(span("danger","\The [src] slams into \the [L]!"))
|
||||
playsound(src, 'sound/weapons/heavysmash.ogg', 75, 1)
|
||||
AttemptToEat(L)
|
||||
overshoot = FALSE
|
||||
|
||||
if(!overshoot) // We hit the target, or something, at destination, so we're done.
|
||||
set_AI_busy(FALSE)
|
||||
return TRUE
|
||||
|
||||
// Otherwise we need to keep going.
|
||||
var/dir_to_go = get_dir(starting_turf, destination)
|
||||
for(var/i = 1 to rand(2, max(4, tally_segments(0))))
|
||||
destination = get_step(destination, dir_to_go)
|
||||
|
||||
handle_charge(destination) // This is overshooting, we don't really care if we hit this destination so don't check the return, just move.
|
||||
|
||||
set_AI_busy(FALSE)
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
// Does the charge movement, stuns enemies, etc.
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/proc/handle_charge(turf/destination)
|
||||
var/turf/T = get_turf(src) // Hold our current tile.
|
||||
|
||||
// Regular charge loop.
|
||||
for(var/i = 1 to get_dist(src, destination))
|
||||
if(stat)
|
||||
return FALSE // We died or got knocked out on the way.
|
||||
if(loc == destination)
|
||||
break // We somehow got there early.
|
||||
|
||||
// Update T.
|
||||
T = get_step(src, get_dir(src, destination))
|
||||
Move(T)
|
||||
|
||||
sleep(charge_tile_speed)
|
||||
set_maw(FALSE)
|
||||
|
||||
/*
|
||||
* Head end.
|
||||
*/
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/set_maw(var/state = FALSE)
|
||||
open_maw = state
|
||||
if(open_maw)
|
||||
@@ -185,7 +328,7 @@
|
||||
|
||||
if(istype(mover, /mob/living/simple_mob/animal/space/space_worm)) // Worms don't run over worms. That's weird. And also really annoying.
|
||||
return TRUE
|
||||
else if(src.stat == DEAD && !istype(mover, /obj/item/projectile)) // Projectiles need to do their normal checks.
|
||||
if(src.stat == DEAD && !istype(mover, /obj/item/projectile)) // Projectiles need to do their normal checks.
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -206,6 +349,12 @@
|
||||
else
|
||||
previous.z_transitioning = FALSE
|
||||
previous.forceMove(old_loc) // None of this 'ripped in half by an airlock' business.
|
||||
|
||||
if(open_maw)
|
||||
for(var/atom/movable/AM in get_turf(src))
|
||||
if(!AM.anchored && prob(30))
|
||||
AttemptToEat(AM)
|
||||
|
||||
update_icon()
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/head/Bump(atom/obstacle)
|
||||
@@ -214,10 +363,12 @@
|
||||
if(currentlyEating != obstacle)
|
||||
currentlyEating = obstacle
|
||||
|
||||
set_AI_busy(TRUE)
|
||||
if(!charging)
|
||||
set_AI_busy(TRUE)
|
||||
if(AttemptToEat(obstacle))
|
||||
currentlyEating = null
|
||||
set_AI_busy(FALSE)
|
||||
if(!charging)
|
||||
set_AI_busy(FALSE)
|
||||
else
|
||||
currentlyEating = null
|
||||
. = ..(obstacle)
|
||||
@@ -245,7 +396,7 @@
|
||||
if((!W.reinf_material && do_after(src, 5 SECONDS)) || do_after(src, 10 SECONDS)) // 10 seconds for an R-wall, 5 seconds for a normal one.
|
||||
if(target)
|
||||
W.dismantle_wall()
|
||||
return 1
|
||||
return TRUE
|
||||
else if(istype(target,/atom/movable))
|
||||
if(istype(target,/mob) || do_after(src, 5)) // 5 ticks to eat stuff like tables.
|
||||
var/atom/movable/objectOrMob = target
|
||||
@@ -268,7 +419,8 @@
|
||||
|
||||
if(D && (D.stat & BROKEN|NOPOWER))
|
||||
D.open(TRUE)
|
||||
break
|
||||
D.update_nearby_tiles(need_rebuild=1)
|
||||
return TRUE
|
||||
|
||||
if(istype(objectOrMob, /obj/effect/energy_field))
|
||||
var/obj/effect/energy_field/EF = objectOrMob
|
||||
@@ -283,12 +435,15 @@
|
||||
else
|
||||
EF.visible_message("<span class='danger'>\The [EF] reverberates as it returns to normal.</span>")
|
||||
|
||||
if(istype(objectOrMob, /obj/machinery/shieldwall)) // This shield type is explicitly a containment field, and if you somehow get a worm inside this, congrats.
|
||||
return FALSE
|
||||
|
||||
if(objectOrMob)
|
||||
objectOrMob.update_nearby_tiles(need_rebuild=1)
|
||||
objectOrMob.forceMove(src)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/Attach(var/mob/living/simple_mob/animal/space/space_worm/attachement)
|
||||
if(!attachement)
|
||||
@@ -320,18 +475,20 @@
|
||||
if(stomach_special_digest(stomachContent))
|
||||
continue
|
||||
if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value
|
||||
if(!istype(stomachContent,/obj/item/stack/material/phoron))
|
||||
if(!istype(stomachContent,digested_sheet))
|
||||
var/obj/item/stack/oldStack = stomachContent
|
||||
new /obj/item/stack/material/phoron(src, oldStack.get_amount())
|
||||
new digested_sheet(src, oldStack.get_amount())
|
||||
qdel(oldStack)
|
||||
continue
|
||||
else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class
|
||||
var/obj/item/oldItem = stomachContent
|
||||
new /obj/item/stack/material/phoron(src, oldItem.w_class)
|
||||
if(oldItem.unacidable)
|
||||
continue
|
||||
new digested_sheet(src, oldItem.w_class)
|
||||
qdel(oldItem)
|
||||
continue
|
||||
else
|
||||
new /obj/item/stack/material/phoron(src, flatPlasmaValue) //just flat amount
|
||||
new digested_sheet(src, flatPlasmaValue) //just flat amount
|
||||
if(!isliving(stomachContent))
|
||||
qdel(stomachContent)
|
||||
else
|
||||
@@ -359,19 +516,67 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/stomach_special(var/atom/A) // Futureproof. Anything that interacts with contents without relying on digestion probability. Return TRUE if it should skip digest.
|
||||
if(istype(A, /mob/living/simple_mob))
|
||||
var/mob/living/simple_mob/SM = A
|
||||
if(!SM.ckey) // Players can always fight back.
|
||||
SM.Stun(3)
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/stomach_special_digest(var/atom/A) // Futureproof. Any special checks that interact with digested atoms. I.E., ore processing. Return TRUE if it should skip future digest checks.
|
||||
if(istype(A, /obj/mecha))
|
||||
var/obj/mecha/ME = A
|
||||
ME.take_damage(rand(10,60), "bio")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/update_body_faction()
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/update_body_states()
|
||||
if(next) // Keep us on the same page, here.
|
||||
faction = next.faction
|
||||
if(mob_class != next.mob_class)
|
||||
mob_class = next.mob_class
|
||||
if(plane != next.plane)
|
||||
plane = next.plane
|
||||
if(invisibility != next.invisibility)
|
||||
invisibility = next.invisibility
|
||||
if(meat_type != next.meat_type)
|
||||
meat_type = next.meat_type
|
||||
if(severed_head_type != next.severed_head_type)
|
||||
severed_head_type = next.severed_head_type
|
||||
if(segment_type != next.segment_type)
|
||||
segment_type = next.segment_type
|
||||
if(digested_sheet != next.digested_sheet)
|
||||
digested_sheet = next.digested_sheet
|
||||
if(tt_desc != next.tt_desc)
|
||||
tt_desc = next.tt_desc
|
||||
if(faction != next.faction)
|
||||
faction = next.faction
|
||||
if(icon != next.icon)
|
||||
icon = next.icon
|
||||
|
||||
// Handle damage distribution, if we're alive. Dead segments are dead weight.
|
||||
// If the next headward segment has more damage, take some of the damage to ourself.
|
||||
if(stat != DEAD)
|
||||
if(next.bruteloss > bruteloss)
|
||||
var/change = round((next.bruteloss - bruteloss) / 2)
|
||||
next.adjustBruteLoss(-change)
|
||||
adjustBruteLoss(change)
|
||||
|
||||
if(next.fireloss > fireloss)
|
||||
var/change = round((next.fireloss - fireloss) / 2)
|
||||
next.adjustFireLoss(-change)
|
||||
adjustFireLoss(change)
|
||||
|
||||
if(previous)
|
||||
previous.update_body_faction()
|
||||
previous.update_body_states()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// Returns the number of segments.
|
||||
/mob/living/simple_mob/animal/space/space_worm/proc/tally_segments(var/count = 0)
|
||||
count++
|
||||
if(previous)
|
||||
return previous.tally_segments(count)
|
||||
return count
|
||||
|
||||
// Worm meat.
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/worm
|
||||
@@ -390,7 +595,7 @@
|
||||
src.bitesize = 3
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/meat/worm/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/material/knife))
|
||||
if(is_sharp(W))
|
||||
var/to_spawn = pickweight(/obj/random/junk = 30,
|
||||
/obj/random/trash = 30,
|
||||
/obj/random/maintenance/clean = 15,
|
||||
@@ -414,3 +619,15 @@
|
||||
to_chat(user, "<span class='alien'>You cut the tissue holding the chunks together.</span>")
|
||||
|
||||
..()
|
||||
|
||||
/*
|
||||
* AI
|
||||
*/
|
||||
|
||||
/datum/ai_holder/simple_mob/destructive/worm
|
||||
can_demolish = TRUE
|
||||
ignore_opacity = TRUE
|
||||
|
||||
/datum/ai_holder/simple_mob/destructive/worm/intelligent
|
||||
astar_adjacent_proc = /turf/proc/CardinalTurfsWithAccessNoDensity
|
||||
use_astar = TRUE
|
||||
|
||||
Reference in New Issue
Block a user