Skip to content

Commit

Permalink
Reorgs xeno_structures.dm, tunnels now use minimap to choose exit. (#…
Browse files Browse the repository at this point in the history
…35)

* tunnel

* reorg

* Update tunnel.dm
  • Loading branch information
Helg2 authored Jul 26, 2024
1 parent 2413f21 commit e466759
Show file tree
Hide file tree
Showing 14 changed files with 1,717 additions and 1,732 deletions.
19 changes: 19 additions & 0 deletions code/__HELPERS/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,22 @@
continue
nearest_target = nearby_vehicle
return nearest_target

/**
* This proc attempts to get an instance of an atom type within distance, with center as the center.
* Arguments
* * center - The center of the search
* * type - The type of atom we're looking for
* * distance - The distance we should search
* * list_to_search - The list to look through for the type
*/
/proc/cheap_get_atom(atom/center, type, distance, list/list_to_search)
var/turf/turf_center = get_turf(center)
if(!turf_center)
return
for(var/atom/near AS in list_to_search)
if(!istype(near, type))
continue
if(get_dist(turf_center, near) > distance)
continue
return near
59 changes: 59 additions & 0 deletions code/modules/xenomorph/_xeno_structure.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/obj/structure/xeno
hit_sound = "alien_resin_break"
layer = RESIN_STRUCTURE_LAYER
resistance_flags = UNACIDABLE
///Bitflags specific to xeno structures
var/xeno_structure_flags
///Which hive(number) do we belong to?
var/hivenumber = XENO_HIVE_NORMAL

/obj/structure/xeno/Initialize(mapload, _hivenumber)
. = ..()
if(!(xeno_structure_flags & IGNORE_WEED_REMOVAL))
RegisterSignal(loc, COMSIG_TURF_WEED_REMOVED, PROC_REF(weed_removed))
if(_hivenumber) ///because admins can spawn them
hivenumber = _hivenumber
LAZYADDASSOC(GLOB.xeno_structures_by_hive, hivenumber, src)
if(xeno_structure_flags & CRITICAL_STRUCTURE)
LAZYADDASSOC(GLOB.xeno_critical_structures_by_hive, hivenumber, src)

/obj/structure/xeno/Destroy()
if(!locate(src) in GLOB.xeno_structures_by_hive[hivenumber]+GLOB.xeno_critical_structures_by_hive[hivenumber]) //The rest of the proc is pointless to look through if its not in the lists
stack_trace("[src] not found in the list of (potentially critical) xeno structures!") //We dont want to CRASH because that'd block deletion completely. Just trace it and continue.
return ..()
GLOB.xeno_structures_by_hive[hivenumber] -= src
if(xeno_structure_flags & CRITICAL_STRUCTURE)
GLOB.xeno_critical_structures_by_hive[hivenumber] -= src
return ..()

/obj/structure/xeno/ex_act(severity)
take_damage(severity * 0.8, BRUTE, BOMB)

/obj/structure/xeno/attack_hand(mob/living/user)
balloon_alert(user, "You only scrape at it")
return TRUE

/obj/structure/xeno/flamer_fire_act(burnlevel)
take_damage(burnlevel / 3, BURN, FIRE)

/obj/structure/xeno/fire_act()
take_damage(10, BURN, FIRE)

/// Destroy the xeno structure when the weed it was on is destroyed
/obj/structure/xeno/proc/weed_removed()
SIGNAL_HANDLER
var/obj/alien/weeds/found_weed = locate(/obj/alien/weeds) in loc
if(found_weed.obj_integrity <= 0)
obj_destruction(damage_flag = MELEE)
else
obj_destruction()

/obj/structure/xeno/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
if(!(HAS_TRAIT(xeno_attacker, TRAIT_VALHALLA_XENO) && xeno_attacker.a_intent == INTENT_HARM && (tgui_alert(xeno_attacker, "Are you sure you want to tear down [src]?", "Tear down [src]?", list("Yes","No"))) == "Yes"))
return ..()
if(!do_after(xeno_attacker, 3 SECONDS, NONE, src))
return
xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
balloon_alert_to_viewers("\The [xeno_attacker] tears down \the [src]!", "We tear down \the [src].")
playsound(src, "alien_resin_break", 25)
take_damage(max_integrity) // Ensure its destroyed
192 changes: 192 additions & 0 deletions code/modules/xenomorph/acidwell.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/obj/structure/xeno/acidwell
name = "acid well"
desc = "An acid well. It stores acid to put out fires."
icon = 'icons/Xeno/acid_pool.dmi'
plane = FLOOR_PLANE
icon_state = "well"
density = FALSE
opacity = FALSE
anchored = TRUE
max_integrity = 5

hit_sound = "alien_resin_move"
destroy_sound = "alien_resin_move"
///How many charges of acid this well contains
var/charges = 1
///If a xeno is charging this well
var/charging = FALSE
///What xeno created this well
var/mob/living/carbon/xenomorph/creator = null

/obj/structure/xeno/acidwell/Initialize(mapload, _creator)
. = ..()
creator = _creator
RegisterSignal(creator, COMSIG_QDELETING, PROC_REF(clear_creator))
update_icon()
var/static/list/connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_cross),
)
AddElement(/datum/element/connect_loc, connections)

/obj/structure/xeno/acidwell/Destroy()
creator = null
return ..()

///Signal handler for creator destruction to clear reference
/obj/structure/xeno/acidwell/proc/clear_creator()
SIGNAL_HANDLER
creator = null

/obj/structure/xeno/acidwell/obj_destruction(damage_amount, damage_type, damage_flag)
if(!QDELETED(creator) && creator.stat == CONSCIOUS && creator.z == z)
var/area/A = get_area(src)
if(A)
to_chat(creator, span_xenoannounce("You sense your acid well at [A.name] has been destroyed!") )

if(damage_amount || damage_flag) //Spawn the gas only if we actually get destroyed by damage
var/datum/effect_system/smoke_spread/xeno/acid/A = new(get_turf(src))
A.set_up(clamp(CEILING(charges*0.5, 1),0,3),src) //smoke scales with charges
A.start()
return ..()

/obj/structure/xeno/acidwell/examine(mob/user)
. = ..()
if(!isxeno(user) && !isobserver(user))
return
. += span_xenonotice("An acid well made by [creator]. It currently has <b>[charges]/[XENO_ACID_WELL_MAX_CHARGES] charges</b>.")

/obj/structure/xeno/acidwell/deconstruct(disassembled = TRUE)
visible_message(span_danger("[src] suddenly collapses!") )
return ..()

/obj/structure/xeno/acidwell/update_icon()
. = ..()
set_light(charges , charges / 2, LIGHT_COLOR_GREEN)

/obj/structure/xeno/acidwell/update_overlays()
. = ..()
if(!charges)
return
. += mutable_appearance(icon, "[charges]", alpha = src.alpha)
. += emissive_appearance(icon, "[charges]", alpha = src.alpha)

/obj/structure/xeno/acidwell/flamer_fire_act(burnlevel) //Removes a charge of acid, but fire is extinguished
acid_well_fire_interaction()

/obj/structure/xeno/acidwell/fire_act() //Removes a charge of acid, but fire is extinguished
acid_well_fire_interaction()

///Handles fire based interactions with the acid well. Depletes 1 charge if there are any to extinguish all fires in the turf while producing acid smoke.
/obj/structure/xeno/acidwell/proc/acid_well_fire_interaction()
if(!charges)
take_damage(50, BURN, FIRE)
return

charges--
update_icon()
var/turf/T = get_turf(src)
var/datum/effect_system/smoke_spread/xeno/acid/extuingishing/acid_smoke = new(T) //spawn acid smoke when charges are actually used
acid_smoke.set_up(0, src) //acid smoke in the immediate vicinity
acid_smoke.start()

for(var/obj/flamer_fire/F in T) //Extinguish all flames in turf
qdel(F)

/obj/structure/xeno/acidwell/attackby(obj/item/I, mob/user, params)
if(!isxeno(user))
return ..()
attack_alien(user)

/obj/structure/xeno/acidwell/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
if(xeno_attacker.a_intent == INTENT_HARM && (CHECK_BITFIELD(xeno_attacker.xeno_caste.caste_flags, CASTE_IS_BUILDER) || xeno_attacker == creator) ) //If we're a builder caste or the creator and we're on harm intent, deconstruct it.
balloon_alert(xeno_attacker, "Removing...")
if(!do_after(xeno_attacker, XENO_ACID_WELL_FILL_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
balloon_alert(xeno_attacker, "Stopped removing")
return
playsound(src, "alien_resin_break", 25)
deconstruct(TRUE, xeno_attacker)
return

if(charges >= 5)
balloon_alert(xeno_attacker, "Already full")
return
if(charging)
balloon_alert(xeno_attacker, "Already being filled")
return

if(xeno_attacker.plasma_stored < XENO_ACID_WELL_FILL_COST) //You need to have enough plasma to attempt to fill the well
balloon_alert(xeno_attacker, "Need [XENO_ACID_WELL_FILL_COST - xeno_attacker.plasma_stored] more plasma")
return

charging = TRUE

balloon_alert(xeno_attacker, "Refilling...")
if(!do_after(xeno_attacker, XENO_ACID_WELL_FILL_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
charging = FALSE
balloon_alert(xeno_attacker, "Aborted refilling")
return

if(xeno_attacker.plasma_stored < XENO_ACID_WELL_FILL_COST)
charging = FALSE
balloon_alert(xeno_attacker, "Need [XENO_ACID_WELL_FILL_COST - xeno_attacker.plasma_stored] more plasma")
return

xeno_attacker.plasma_stored -= XENO_ACID_WELL_FILL_COST
charges++
charging = FALSE
update_icon()
balloon_alert(xeno_attacker, "Now has [charges] / [XENO_ACID_WELL_MAX_CHARGES] charges")
to_chat(xeno_attacker,span_xenonotice("We add acid to [src]. It is currently has <b>[charges] / [XENO_ACID_WELL_MAX_CHARGES] charges</b>.") )

/obj/structure/xeno/acidwell/proc/on_cross(datum/source, atom/movable/A, oldloc, oldlocs)
SIGNAL_HANDLER
if(CHECK_MULTIPLE_BITFIELDS(A.allow_pass_flags, HOVERING))
return
if(iscarbon(A))
HasProximity(A)

/obj/structure/xeno/acidwell/HasProximity(atom/movable/AM)
if(!charges)
return
if(!isliving(AM))
return
var/mob/living/stepper = AM
if(stepper.stat == DEAD)
return

var/charges_used = 0

for(var/obj/item/explosive/grenade/sticky/sticky_bomb in stepper.contents)
if(charges_used >= charges)
break
if(sticky_bomb.stuck_to == stepper)
sticky_bomb.clean_refs()
sticky_bomb.forceMove(loc) // i'm not sure if this is even needed, but just to prevent possible bugs
visible_message(span_danger("[src] sizzles as [sticky_bomb] melts down in the acid."))
qdel(sticky_bomb)
charges_used ++

if(stepper.on_fire && (charges_used < charges))
stepper.ExtinguishMob()
charges_used ++

if(!isxeno(stepper))
stepper.next_move_slowdown += charges * 2 //Acid spray has slow down so this should too; scales with charges, Min 2 slowdown, Max 10
stepper.apply_damage(charges * 10, BURN, BODY_ZONE_PRECISE_L_FOOT, ACID, penetration = 33)
stepper.apply_damage(charges * 10, BURN, BODY_ZONE_PRECISE_R_FOOT, ACID, penetration = 33)
stepper.visible_message(span_danger("[stepper] is immersed in [src]'s acid!") , \
span_danger("We are immersed in [src]'s acid!") , null, 5)
playsound(stepper, "sound/bullets/acid_impact1.ogg", 10 * charges)
new /obj/effect/temp_visual/acid_bath(get_turf(stepper))
charges_used = charges //humans stepping on it empties it out

if(!charges_used)
return

var/datum/effect_system/smoke_spread/xeno/acid/extuingishing/acid_smoke
acid_smoke = new(get_turf(stepper)) //spawn acid smoke when charges are actually used
acid_smoke.set_up(0, src) //acid smoke in the immediate vicinity
acid_smoke.start()

charges -= charges_used
update_icon()
67 changes: 67 additions & 0 deletions code/modules/xenomorph/jellypod.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/obj/structure/xeno/resin_jelly_pod
name = "Resin jelly pod"
desc = "A large resin pod. Inside is a thick, viscous fluid that looks like it doesnt burn easily."
icon = 'icons/Xeno/resinpod.dmi'
icon_state = "resinpod"
density = FALSE
opacity = FALSE
anchored = TRUE
max_integrity = 250
layer = RESIN_STRUCTURE_LAYER
pixel_x = -16
pixel_y = -16
xeno_structure_flags = IGNORE_WEED_REMOVAL

hit_sound = "alien_resin_move"
destroy_sound = "alien_resin_move"
///How many actual jellies the pod has stored
var/chargesleft = 0
///Max amount of jellies the pod can hold
var/maxcharges = 10
///Every 5 times this number seconds we will create a jelly
var/recharge_rate = 10
///Countdown to the next time we generate a jelly
var/nextjelly = 0

/obj/structure/xeno/resin_jelly_pod/Initialize(mapload, _hivenumber)
. = ..()
add_overlay(image(icon, "resinpod_inside", layer + 0.01, dir))
START_PROCESSING(SSslowprocess, src)

/obj/structure/xeno/resin_jelly_pod/Destroy()
STOP_PROCESSING(SSslowprocess, src)
return ..()

/obj/structure/xeno/resin_jelly_pod/examine(mob/user, distance, infix, suffix)
. = ..()
if(isxeno(user))
. += "It has [chargesleft] jelly globules remaining[datum_flags & DF_ISPROCESSING ? ", and will create a new jelly in [(recharge_rate-nextjelly)*5] seconds": " and seems latent"]."

/obj/structure/xeno/resin_jelly_pod/process()
if(nextjelly <= recharge_rate)
nextjelly++
return
nextjelly = 0
chargesleft++
if(chargesleft >= maxcharges)
return PROCESS_KILL

/obj/structure/xeno/resin_jelly_pod/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE

if((xeno_attacker.a_intent == INTENT_HARM && isxenohivelord(xeno_attacker)) || xeno_attacker.hivenumber != hivenumber)
balloon_alert(xeno_attacker, "Destroying...")
if(do_after(xeno_attacker, HIVELORD_TUNNEL_DISMANTLE_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
deconstruct(FALSE)
return

if(!chargesleft)
balloon_alert(xeno_attacker, "No jelly remaining")
to_chat(xeno_attacker, span_xenonotice("We reach into \the [src], but only find dregs of resin. We should wait some more.") )
return
balloon_alert(xeno_attacker, "Retrieved jelly")
new /obj/item/resin_jelly(loc)
chargesleft--
if(!(datum_flags & DF_ISPROCESSING) && (chargesleft < maxcharges))
START_PROCESSING(SSslowprocess, src)
Loading

0 comments on commit e466759

Please sign in to comment.