Skip to content

Commit

Permalink
Scaling basic resin construction cost (#7882)
Browse files Browse the repository at this point in the history
# About the pull request

This PR is aimed at discouraging basic resin constructions
(walls/membranes/doors) in areas that are already saturated with resin
constructions. I am not certain yet if 40% saturation is the right
amount to start scaling (as in I generally don't want it to really ever
come in to play for most rounds), and if plasma cost is harsh enough
when its active. The plasma cost will always be under plasma_max if
there even is enough plasma_max needed to do the construction normally.

Current values:

![image](https://github.com/user-attachments/assets/e6994a70-9689-49cc-a3e8-762a1d710ff6)

I also made the admin niche message for enclosed dead bodies more
relevant.

# Explain why it's good for the game

Should mitigate, but not make impossible, saturating areas heavily with
basic resin constructions. I personally think marines have enough tools
to quickly enough deal with this occurring even in caves, but I guess
I'm in the minority.

# Testing Photographs and Procedure
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

</details>


# Changelog
:cl: Drathek
balance: Added scaling to the plasma cost of basic resin constructions
when an area is at least 40% saturated.
admin: Niche messaging for sealing off dead bodies now only applies to
revivable bodies
refactor: Refactored some resin construction code
/:cl:

---------

Co-authored-by: Segrain <[email protected]>
  • Loading branch information
Drulikar and Segrain authored Jan 2, 2025
1 parent 1e75209 commit e787d8e
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 66 deletions.
15 changes: 15 additions & 0 deletions code/game/area/areas.dm
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@
/// How long this area should be un-oviable
var/unoviable_timer = 25 MINUTES

/// How many potentially open turfs can exist in this area
var/openable_turf_count = 0
/// How much destroyable resin currently exists in this area
var/current_resin_count = 0

/area/New()
// This interacts with the map loader, so it needs to be set immediately
Expand Down Expand Up @@ -119,6 +123,17 @@
is_resin_allowed = FALSE
log_mapping("[src] has AREA_UNWEEDABLE flag but has is_resin_allowed as true! Forcing is_resin_allowed false...")

if(!(flags_area & AREA_UNWEEDABLE))
for(var/turf/current in src)
if(!current.density)
openable_turf_count++
continue
if(istype(current, /turf/closed/wall))
var/turf/closed/wall/current_wall = current
if(!current_wall.hull)
openable_turf_count++
continue

/area/proc/initialize_power(override_power)
if(requires_power)
if(override_power) //Reset everything if you want to override.
Expand Down
13 changes: 11 additions & 2 deletions code/game/turfs/walls/wall_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,17 @@

if(!hull)
var/area/area = get_area(src)
if(area && area.linked_lz)
AddComponent(/datum/component/resin_cleanup)
if(area)
if(area.linked_lz)
AddComponent(/datum/component/resin_cleanup)
area.current_resin_count++

/turf/closed/wall/resin/Destroy(force)
. = ..()

if(!hull)
var/area/area = get_area(src)
area?.current_resin_count--

/turf/closed/wall/resin/proc/forsaken_handling()
SIGNAL_HANDLER
Expand Down
25 changes: 15 additions & 10 deletions code/modules/cm_aliens/XenoStructures.dm
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@
W.update_connections()
W.update_icon()

if (hive)
if(hive)
hivenumber = hive

set_hive_data(src, hivenumber)
Expand All @@ -382,8 +382,10 @@
RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling))

var/area/area = get_area(src)
if(area && area.linked_lz)
AddComponent(/datum/component/resin_cleanup)
if(area)
if(area.linked_lz)
AddComponent(/datum/component/resin_cleanup)
area.current_resin_count++

/obj/structure/mineral_door/resin/flamer_fire_act(dam = BURN_LEVEL_TIER_1)
health -= dam
Expand Down Expand Up @@ -482,14 +484,17 @@

/obj/structure/mineral_door/resin/Destroy()
relativewall_neighbours()
var/turf/U = loc
var/area/area = get_area(src)
area?.current_resin_count--
var/turf/base_turf = loc
spawn(0)
var/turf/T
for(var/i in GLOB.cardinals)
T = get_step(U, i)
if(!istype(T)) continue
for(var/obj/structure/mineral_door/resin/R in T)
R.check_resin_support()
var/turf/adjacent_turf
for(var/cardinal in GLOB.cardinals)
adjacent_turf = get_step(base_turf, cardinal)
if(!istype(adjacent_turf))
continue
for(var/obj/structure/mineral_door/resin/door in adjacent_turf)
door.check_resin_support()
. = ..()

/obj/structure/mineral_door/resin/proc/healthcheck()
Expand Down
105 changes: 57 additions & 48 deletions code/modules/mob/living/carbon/xenomorph/Powers.dm
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
/mob/living/carbon/xenomorph/proc/build_resin(atom/A, thick = FALSE, message = TRUE, use_plasma = TRUE, add_build_mod = 1)
/mob/living/carbon/xenomorph/proc/build_resin(atom/target, thick = FALSE, message = TRUE, use_plasma = TRUE, add_build_mod = 1)
if(!selected_resin)
return SECRETE_RESIN_FAIL

var/datum/resin_construction/RC = GLOB.resin_constructions_list[selected_resin]
var/datum/resin_construction/resin_construct = GLOB.resin_constructions_list[selected_resin]

var/total_resin_cost = XENO_RESIN_BASE_COST + RC.cost // Live, diet, shit code, repeat
var/total_resin_cost = XENO_RESIN_BASE_COST + resin_construct.cost // Live, diet, shit code, repeat

if(resin_construct.scaling_cost && use_plasma)
var/area/target_area = get_area(target)
if(target_area && target_area.openable_turf_count)
var/density_ratio = target_area.current_resin_count / target_area.openable_turf_count
if(density_ratio > 0.4)
total_resin_cost = ceil(total_resin_cost * (density_ratio + 0.35) * 2)
if(total_resin_cost > plasma_max && (XENO_RESIN_BASE_COST + resin_construct.cost) < plasma_max)
total_resin_cost = plasma_max

if(action_busy && !can_stack_builds)
return SECRETE_RESIN_FAIL
Expand All @@ -16,91 +25,91 @@
to_chat(src, SPAN_XENOWARNING("It's too tight in here to build."))
return SECRETE_RESIN_FAIL

if(RC.max_per_xeno != RESIN_CONSTRUCTION_NO_MAX)
var/current_amount = length(built_structures[RC.build_path])
if(current_amount >= RC.max_per_xeno)
if(resin_construct.max_per_xeno != RESIN_CONSTRUCTION_NO_MAX)
var/current_amount = length(built_structures[resin_construct.build_path])
if(current_amount >= resin_construct.max_per_xeno)
to_chat(src, SPAN_XENOWARNING("We've already built the maximum possible structures we can!"))
return SECRETE_RESIN_FAIL

var/turf/current_turf = get_turf(A)
var/turf/current_turf = get_turf(target)

if(extra_build_dist != IGNORE_BUILD_DISTANCE && get_dist(src, A) > src.caste.max_build_dist + extra_build_dist) // Hivelords and eggsac carriers have max_build_dist of 1, drones and queens 0
if(extra_build_dist != IGNORE_BUILD_DISTANCE && get_dist(src, target) > src.caste.max_build_dist + extra_build_dist) // Hivelords and eggsac carriers have max_build_dist of 1, drones and queens 0
to_chat(src, SPAN_XENOWARNING("We can't build from that far!"))
return SECRETE_RESIN_FAIL
else if(thick) //hivelords can thicken existing resin structures.
var/thickened = FALSE
if(istype(A, /turf/closed/wall/resin))
var/turf/closed/wall/resin/WR = A
if(istype(target, /turf/closed/wall/resin))
var/turf/closed/wall/resin/wall = target

if(istype(A, /turf/closed/wall/resin/weak))
to_chat(src, SPAN_XENOWARNING("[WR] is too flimsy to be reinforced."))
if(istype(target, /turf/closed/wall/resin/weak))
to_chat(src, SPAN_XENOWARNING("[wall] is too flimsy to be reinforced."))
return SECRETE_RESIN_FAIL

for(var/datum/effects/xeno_structure_reinforcement/sf in WR.effects_list)
to_chat(src, SPAN_XENOWARNING("The extra resin is preventing us from reinforcing [WR]. Wait until it elapse."))
for(var/datum/effects/xeno_structure_reinforcement/sf in wall.effects_list)
to_chat(src, SPAN_XENOWARNING("The extra resin is preventing us from reinforcing [wall]. Wait until it elapse."))
return SECRETE_RESIN_FAIL

if (WR.hivenumber != hivenumber)
to_chat(src, SPAN_XENOWARNING("[WR] doesn't belong to your hive!"))
if (wall.hivenumber != hivenumber)
to_chat(src, SPAN_XENOWARNING("[wall] doesn't belong to your hive!"))
return SECRETE_RESIN_FAIL

if(WR.type == /turf/closed/wall/resin)
WR.ChangeTurf(/turf/closed/wall/resin/thick)
if(wall.type == /turf/closed/wall/resin)
wall.ChangeTurf(/turf/closed/wall/resin/thick)
total_resin_cost = XENO_THICKEN_WALL_COST
else if(WR.type == /turf/closed/wall/resin/membrane)
WR.ChangeTurf(/turf/closed/wall/resin/membrane/thick)
else if(wall.type == /turf/closed/wall/resin/membrane)
wall.ChangeTurf(/turf/closed/wall/resin/membrane/thick)
total_resin_cost = XENO_THICKEN_MEMBRANE_COST
else
to_chat(src, SPAN_XENOWARNING("[WR] can't be made thicker."))
to_chat(src, SPAN_XENOWARNING("[wall] can't be made thicker."))
return SECRETE_RESIN_FAIL
thickened = TRUE

else if(istype(A, /obj/structure/mineral_door/resin))
var/obj/structure/mineral_door/resin/DR = A
if (DR.hivenumber != hivenumber)
to_chat(src, SPAN_XENOWARNING("[DR] doesn't belong to your hive!"))
else if(istype(target, /obj/structure/mineral_door/resin))
var/obj/structure/mineral_door/resin/door = target
if (door.hivenumber != hivenumber)
to_chat(src, SPAN_XENOWARNING("[door] doesn't belong to your hive!"))
return SECRETE_RESIN_FAIL

for(var/datum/effects/xeno_structure_reinforcement/sf in DR.effects_list)
to_chat(src, SPAN_XENOWARNING("The extra resin is preventing us from reinforcing [DR]. Wait until it elapse."))
for(var/datum/effects/xeno_structure_reinforcement/sf in door.effects_list)
to_chat(src, SPAN_XENOWARNING("The extra resin is preventing us from reinforcing [door]. Wait until it elapse."))
return SECRETE_RESIN_FAIL

if(DR.hardness == 1.5) //non thickened
var/oldloc = DR.loc
qdel(DR)
new /obj/structure/mineral_door/resin/thick (oldloc, DR.hivenumber)
if(door.hardness == 1.5) //non thickened
var/oldloc = door.loc
qdel(door)
new /obj/structure/mineral_door/resin/thick (oldloc, door.hivenumber)
total_resin_cost = XENO_THICKEN_DOOR_COST
else
to_chat(src, SPAN_XENOWARNING("[DR] can't be made thicker."))
to_chat(src, SPAN_XENOWARNING("[door] can't be made thicker."))
return SECRETE_RESIN_FAIL
thickened = TRUE

if(thickened)
if(message)
visible_message(SPAN_XENONOTICE("[src] regurgitates a thick substance and thickens [A]."), \
SPAN_XENONOTICE("We regurgitate some resin and thicken [A], using [total_resin_cost] plasma."), null, 5)
visible_message(SPAN_XENONOTICE("[src] regurgitates a thick substance and thickens [target]."), \
SPAN_XENONOTICE("We regurgitate some resin and thicken [target], using [total_resin_cost] plasma."), null, 5)
if(use_plasma)
use_plasma(total_resin_cost)
playsound(loc, "alien_resin_build", 25)
A.add_hiddenprint(src) //so admins know who thickened the walls
target.add_hiddenprint(src) //so admins know who thickened the walls
return TRUE

if (!RC.can_build_here(current_turf, src))
if(!resin_construct.can_build_here(current_turf, src))
return SECRETE_RESIN_FAIL

var/wait_time = RC.build_time * caste.build_time_mult * add_build_mod
var/wait_time = resin_construct.build_time * caste.build_time_mult * add_build_mod

var/obj/effect/alien/weeds/alien_weeds = current_turf.weeds
if(!alien_weeds || alien_weeds.secreting)
return SECRETE_RESIN_FAIL

var/obj/warning
var/succeeded = TRUE
if(RC.build_overlay_icon)
warning = new RC.build_overlay_icon(current_turf)
if(resin_construct.build_overlay_icon)
warning = new resin_construct.build_overlay_icon(current_turf)

if(RC.build_animation_effect)
warning = new RC.build_animation_effect(current_turf)
if(resin_construct.build_animation_effect)
warning = new resin_construct.build_animation_effect(current_turf)

switch(wait_time)
if(1 SECONDS)
Expand All @@ -125,19 +134,19 @@
if(!succeeded)
return SECRETE_RESIN_INTERRUPT

if (!RC.can_build_here(current_turf, src))
if (!resin_construct.can_build_here(current_turf, src))
return SECRETE_RESIN_FAIL

if(use_plasma)
use_plasma(total_resin_cost)
if(message)
visible_message(SPAN_XENONOTICE("[src] regurgitates a thick substance and shapes it into \a [RC.construction_name]!"), \
SPAN_XENONOTICE("We regurgitate some resin and shape it into \a [RC.construction_name][use_plasma ? " at the cost of a total [total_resin_cost] plasma" : ""]."), null, 5)
visible_message(SPAN_XENONOTICE("[src] regurgitates a thick substance and shapes it into \a [resin_construct.construction_name]!"), \
SPAN_XENONOTICE("We regurgitate some resin and shape it into \a [resin_construct.construction_name][use_plasma ? " at the cost of a total [total_resin_cost] plasma" : ""]."), null, 5)
playsound(loc, "alien_resin_build", 25)

var/atom/new_resin = RC.build(current_turf, hivenumber, src)
if(RC.max_per_xeno != RESIN_CONSTRUCTION_NO_MAX)
LAZYADD(built_structures[RC.build_path], new_resin)
var/atom/new_resin = resin_construct.build(current_turf, hivenumber, src)
if(resin_construct.max_per_xeno != RESIN_CONSTRUCTION_NO_MAX)
LAZYADD(built_structures[resin_construct.build_path], new_resin)
RegisterSignal(new_resin, COMSIG_PARENT_QDELETING, PROC_REF(remove_built_structure))

new_resin.add_hiddenprint(src) //so admins know who placed it
Expand All @@ -148,7 +157,7 @@

if(istype(new_resin, /turf/closed))
for(var/mob/living/carbon/human/enclosed_human in new_resin.contents)
if(enclosed_human.stat == DEAD)
if(enclosed_human.stat == DEAD && enclosed_human.is_revivable(TRUE))
msg_admin_niche("[src.ckey]/([src]) has built a closed resin structure, [new_resin.name], on top of a dead human, [enclosed_human.ckey]/([enclosed_human]), at [new_resin.x],[new_resin.y],[new_resin.z] [ADMIN_JMP(new_resin)]")

return SECRETE_RESIN_SUCCESS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,21 @@
button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, resin_construction.construction_name)

// Resin
/datum/action/xeno_action/activable/secrete_resin/use_ability(atom/A)
/datum/action/xeno_action/activable/secrete_resin/use_ability(atom/target)
if(!..())
return FALSE
var/mob/living/carbon/xenomorph/X = owner
if(isstorage(A.loc) || X.contains(A) || istype(A, /atom/movable/screen)) return FALSE
if(A.z != X.z)
var/mob/living/carbon/xenomorph/xeno_owner = owner
if(isstorage(target.loc))
return FALSE
if(xeno_owner.contains(target))
return FALSE
if(istype(target, /atom/movable/screen))
return FALSE
if(target.z != xeno_owner.z)
to_chat(owner, SPAN_XENOWARNING("This area is too far away to affect!"))
return
apply_cooldown()
switch(X.build_resin(A, thick, make_message, plasma_cost != 0, build_speed_mod))
switch(xeno_owner.build_resin(target, thick, make_message, plasma_cost != 0, build_speed_mod))
if(SECRETE_RESIN_INTERRUPT)
if(xeno_cooldown)
apply_cooldown_override(xeno_cooldown * 3)
Expand Down
13 changes: 12 additions & 1 deletion code/modules/mob/living/carbon/xenomorph/resin_constructions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
var/thick_hiveweed = FALSE // if this is set, the thick variants will only work on hiveweeds
var/can_build_on_doors = TRUE // if it can be built on a tile with an open door or not

/// Whether this construction gets more expensive the more saturated the area is
var/scaling_cost = FALSE

/datum/resin_construction/proc/can_build_here(turf/T, mob/living/carbon/xenomorph/X)
var/mob/living/carbon/xenomorph/blocker = locate() in T
if(blocker && blocker != X && blocker.stat != DEAD)
Expand Down Expand Up @@ -115,6 +118,7 @@
desc = "A resin wall, able to block passage."
construction_name = "resin wall"
cost = XENO_RESIN_WALL_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin
build_animation_effect = /obj/effect/resin_construct/weak
Expand All @@ -124,6 +128,7 @@
desc = "A thick resin wall, stronger than regular walls."
construction_name = "thick resin wall"
cost = XENO_RESIN_WALL_THICK_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin/thick
build_animation_effect = /obj/effect/resin_construct/thick
Expand All @@ -132,8 +137,8 @@
name = "Queen Resin Wall"
desc = "A resin wall, able to block passage. Constructed type depends on weeds."
construction_name = "queen resin wall"

cost = XENO_RESIN_WALL_QUEEN_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin
build_path_thick = /turf/closed/wall/resin/thick
Expand All @@ -155,6 +160,7 @@
desc = "Resin membrane that can be seen through."
construction_name = "resin membrane"
cost = XENO_RESIN_MEMBRANE_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin/membrane
build_animation_effect = /obj/effect/resin_construct/transparent/weak
Expand All @@ -164,6 +170,7 @@
desc = "Resin membrane that can be seen through. Constructed type depends on weeds."
construction_name = "queen resin membrane"
cost = XENO_RESIN_MEMBRANE_QUEEN_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin/membrane
build_path_thick = /turf/closed/wall/resin/membrane/thick
Expand All @@ -175,6 +182,7 @@
desc = "Strong resin membrane that can be seen through."
construction_name = "thick resin membrane"
cost = XENO_RESIN_MEMBRANE_THICK_COST
scaling_cost = TRUE

build_path = /turf/closed/wall/resin/membrane/thick
build_animation_effect = /obj/effect/resin_construct/transparent/thick
Expand All @@ -185,6 +193,7 @@
desc = "A resin door that only sisters may pass."
construction_name = "resin door"
cost = XENO_RESIN_DOOR_COST
scaling_cost = TRUE

build_path = /obj/structure/mineral_door/resin
build_animation_effect = /obj/effect/resin_construct/door
Expand Down Expand Up @@ -215,6 +224,7 @@
desc = "A resin door that only sisters may pass. Constructed type depends on weeds."
construction_name = "queen resin door"
cost = XENO_RESIN_DOOR_QUEEN_COST
scaling_cost = TRUE

build_path = /obj/structure/mineral_door/resin
build_path_thick = /obj/structure/mineral_door/resin/thick
Expand All @@ -226,6 +236,7 @@
desc = "A thick resin door, which is more durable, that only sisters may pass."
construction_name = "thick resin door"
cost = XENO_RESIN_DOOR_THICK_COST
scaling_cost = TRUE

build_path = /obj/structure/mineral_door/resin/thick
build_animation_effect = /obj/effect/resin_construct/thickdoor
Expand Down

0 comments on commit e787d8e

Please sign in to comment.