diff --git a/code/modules/cm_aliens/weeds.dm b/code/modules/cm_aliens/weeds.dm index fa79e70115dd..924bc33d90aa 100644 --- a/code/modules/cm_aliens/weeds.dm +++ b/code/modules/cm_aliens/weeds.dm @@ -676,4 +676,32 @@ /obj/effect/resin_construct/transparent/weak icon_state = "WeakTransparentConstruct" +/obj/effect/resin_construct/fastweak + icon_state = "WeakReflectiveFast" + +/obj/effect/resin_construct/speed_node + icon_state = "speednode" + +/obj/effect/resin_construct/cost_node + icon_state = "costnode" + +/obj/effect/resin_construct/construct_node + icon_state = "constructnode" + +/obj/effect/resin_construct/construct_doorslow + icon_state = "BoundDoorSlow" + +/obj/effect/resin_construct/construct_wallslow + icon_state = "BoundWallSlow" + +/obj/effect/resin_construct/thickfast + icon_state = "ThickConstructFast" + +/obj/effect/resin_construct/thickdoorfast + icon_state = "ThickDoorConstructFast" + layer = FIREDOOR_CLOSED_LAYER + +/obj/effect/resin_construct/transparent/thickfast + icon_state = "WeakTransparentConstructFast" + #undef WEED_BASE_GROW_SPEED diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/hivelord/hivelord_macros.dm b/code/modules/mob/living/carbon/xenomorph/abilities/hivelord/hivelord_macros.dm new file mode 100644 index 000000000000..2bfeb63d02c7 --- /dev/null +++ b/code/modules/mob/living/carbon/xenomorph/abilities/hivelord/hivelord_macros.dm @@ -0,0 +1,28 @@ +/datum/action/xeno_action/verb/verb_change_design() + set category = "Alien" + set name = "Change Design Mark" + set hidden = TRUE + var/action_name = "Change Design Mark" + handle_xeno_macro(src, action_name) + +/datum/action/xeno_action/verb/place_design() + set category = "Alien" + set name = "Place Design" + set hidden = TRUE + var/action_name = "Place Design" + handle_xeno_macro(src, action_name) + +/datum/action/xeno_action/verb/verb_toggle_design_icons() + set category = "Alien" + set name = "Change Design Mark" + set hidden = TRUE + var/action_name = "Change Design Mark" + handle_xeno_macro(src, action_name) + +/datum/action/xeno_action/verb/verb_greater_surge() + set category = "Alien" + set name = "Greater Resin Surge" + set hidden = TRUE + var/action_name = "Greater Resin Surge" + handle_xeno_macro(src, action_name) + diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/designer.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/designer.dm index 6230452f25ed..611d01747583 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/designer.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/hivelord/designer.dm @@ -63,52 +63,6 @@ . = list() . += "Nodes sustained: [length(bound_xeno.current_design)] / [bound_xeno.max_design_nodes]" -// ""animations"" (effects) -/obj/effect/resin_construct/fastweak - icon_state = "WeakReflectiveFast" - -/obj/effect/resin_construct/speed_node - icon_state = "speednode" - -/obj/effect/resin_construct/cost_node - icon_state = "costnode" - -/obj/effect/resin_construct/construct_node - icon_state = "constructnode" - -/obj/effect/resin_construct/construct_doorslow - icon_state = "DoorConstrucSlow" - -/obj/effect/resin_construct/construct_wallslow - icon_state = "WeakConstructSlow" - -/obj/effect/resin_construct/thickfast - icon_state = "ThickConstructFast" - -/obj/effect/resin_construct/thickdoorfast - icon_state = "ThickDoorConstructFast" - layer = FIREDOOR_CLOSED_LAYER - -/obj/effect/resin_construct/transparent/thickfast - icon_state = "WeakTransparentConstructFast" - -//Marks - -/datum/design_mark - var/name = "xeno_declare" - var/icon_state = "empty" - var/desc = "Xenos make psychic markers with this meaning as positional lasting communication to each other." - -/datum/design_mark/resin_wall - name = "Resin Wall" - desc = "Place resin wall here!" - icon_state = "mark_wall" - -/datum/design_mark/resin_door - name = "Resin Door" - desc = "Place resin door here!" - icon_state = "mark_door" - // Far-sight /datum/action/xeno_action/onclick/toggle_long_range/designer handles_movement = FALSE @@ -117,579 +71,489 @@ delay = 0 ////////////////////////// -/// Designer... Paths. /// +/// Change Design /// ////////////////////////// -/obj/effect/alien/resin/design - name = "Design Node" - desc = "A weird node, it looks mutated." - icon = 'icons/mob/xenos/effects.dmi' - icon_state = "static_speednode" - density = FALSE - opacity = FALSE - layer = RESIN_UNDER_STRUCTURE_LAYER - plane = FLOOR_PLANE - health = HEALTH_RESIN_XENO_STICKY - - var/datum/design_mark/mark_meaning = /datum/design_mark/resin_wall - var/mob/living/carbon/xenomorph/bound_xeno - var/obj/effect/alien/weeds/bound_weed - var/hivenumber = XENO_HIVE_NORMAL - var/plasma_cost = 0 +/datum/action/xeno_action/onclick/change_design + name = "Choose Action" + action_icon_state = "static_speednode" + plasma_cost = 0 + xeno_cooldown = 0 + macro_path = /datum/action/xeno_action/verb/verb_change_design + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_2 - var/image/chosenMark +/datum/action/xeno_action/onclick/change_design/use_ability(atom/Atom) + var/mob/living/carbon/xenomorph/xeno = owner + if(!xeno.check_state()) + return -/obj/effect/alien/resin/design/Initialize(mapload, obj/effect/alien/weeds/weeds, mob/living/carbon/xenomorph/xeno) - if(!istype(xeno)) - return INITIALIZE_HINT_QDEL + var/static/list/options = list( + "Optimized Node (50)" = icon(/datum/action/xeno_action::icon_file, "static_speednode"), + "Construct Node (70)" = icon(/datum/action/xeno_action::icon_file, "static_constructnode"), + "Thicken Resin (60)" = icon(/datum/action/xeno_action::icon_file, "upgrade_resin"), + "Open Old UI" = icon(/datum/action/xeno_action::icon_file, "open_ui"), + "Remove Node (25)" = icon(/datum/action/xeno_action::icon_file, "remove_node"), + "Flexible Node (60)" = icon(/datum/action/xeno_action::icon_file, "static_costnode") + ) - bound_xeno = xeno - bound_weed = weeds - hivenumber = xeno.hivenumber + var/choice + if(owner.client.prefs.no_radials_preference) + choice = tgui_input_list(owner, "Choose Design Option", "Pick", options, theme="hive_status") + else + choice = show_radial_menu(owner, owner?.client.get_eye(), options, radius = 50) - RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - RegisterSignal(bound_xeno, COMSIG_PARENT_QDELETING, PROC_REF(on_xeno_expire)) + var/des = FALSE + var/rem = FALSE + plasma_cost = 0 + switch(choice) + if("Optimized Node (50)") + xeno.selected_design = /obj/effect/alien/resin/design/speed_node + des = TRUE + if("Flexible Node (60)") + xeno.selected_design = /obj/effect/alien/resin/design/cost_node + des = TRUE + if("Construct Node (70)") + xeno.selected_design = /obj/effect/alien/resin/design/construct_node + des = TRUE + if("Thicken Resin (60)") + xeno.selected_design = /obj/effect/alien/resin/design/upgrade + rem = TRUE + if("Remove Node (25)") + xeno.selected_design = /obj/effect/alien/resin/design/remove + rem = TRUE + if("Open Old UI") + tgui_interact(xeno) - set_hive_data(src, hivenumber) - . = ..() + if(des) + to_chat(xeno, SPAN_NOTICE("We will now build [xeno.selected_design.name].")) + if(rem) + to_chat(xeno, SPAN_NOTICE("We will now remotely [xeno.selected_design.name].")) - if(bound_weed.hivenumber != bound_xeno.hivenumber) - qdel(src) + xeno.update_icons() + button.overlays.Cut() + button.overlays += image(icon_file, button, xeno.selected_design.icon_state) - if(xeno.selected_design_mark) - mark_meaning = new xeno.selected_design_mark + return ..() - var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] - if(hive) - hive.designer_marks += src - if(mark_meaning) - var/icon_state_to_use = get_marker_icon_state() - if(icon_state_to_use) - chosenMark = image(icon, src, icon_state_to_use, ABOVE_HUD_LAYER, "pixel_y" = 5) - chosenMark.plane = ABOVE_HUD_PLANE - chosenMark.appearance_flags = RESET_COLOR +// Below is UI for old players. - for(xeno in hive.totalXenos) - if(xeno.client) - xeno.hud_set_design_marks() - refresh_marker() +/datum/action/xeno_action/onclick/change_design/give_to(mob/living/carbon/xenomorph/xeno) + . = ..() -/obj/effect/alien/resin/design/Destroy() - var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] - if(hive) - hive.designer_marks -= src - for(var/mob/living/carbon/xenomorph/xeno in hive.totalXenos) - if(xeno.client && chosenMark) - xeno.client.images -= chosenMark - xeno.hud_set_design_marks() + button.overlays.Cut() + button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, initial(xeno.selected_design.icon_state)) + button.overlays += image(icon_file, button, action_icon_state) - if(!QDELETED(bound_xeno)) - bound_xeno.current_design.Remove(src) - unregister_weed_expiration_signal_design() - bound_xeno = null - bound_weed = null - chosenMark = null - return ..() +/datum/action/xeno_action/onclick/change_design/ui_assets(mob/user) + return list(get_asset_datum(/datum/asset/spritesheet/choose_design)) -/obj/effect/alien/resin/design/proc/refresh_marker() - if(!chosenMark || !mark_meaning) +/datum/action/xeno_action/onclick/change_design/ui_static_data(mob/user) + var/mob/living/carbon/xenomorph/xeno = user + if(!istype(xeno)) return - if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) - chosenMark.icon_state = mark_meaning.icon_state + . = list() -/obj/effect/alien/resin/design/proc/get_marker_icon_state() - if(!mark_meaning) - return null - return mark_meaning.icon_state + var/list/design_list = list() + for(var/obj/effect/alien/resin/design/design as anything in xeno.available_design) + var/list/entry = list() -/obj/effect/alien/resin/design/proc/on_weed_expire() - SIGNAL_HANDLER - qdel(src) + entry["name"] = initial(design.name) + entry["desc"] = initial(design.desc) + entry["image"] = replacetext(initial(design.icon_state), " ", "-") + entry["id"] = "[design]" + design_list += list(entry) -/obj/effect/alien/resin/design/proc/on_xeno_expire() - SIGNAL_HANDLER - qdel(src) + .["design"] = design_list -/obj/effect/alien/resin/design/proc/check_hivenumber_match() - if(!bound_weed || !bound_xeno) - visible_message(SPAN_XENOWARNING("The node shudders and decays back into the weeds.")) - qdel(src) - else if(bound_weed.hivenumber != bound_xeno.hivenumber) - visible_message(SPAN_XENOWARNING("The node withers away.")) - qdel(src) +/datum/action/xeno_action/onclick/change_design/ui_data(mob/user) + var/mob/living/carbon/xenomorph/xeno = user + if(!istype(xeno)) + return -/obj/effect/alien/resin/design/proc/unregister_weed_expiration_signal_design() - if(bound_weed) - UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) + . = list() + .["selected_design"] = xeno.selected_design -/obj/effect/alien/resin/design/proc/register_weed_expiration_signal_design(obj/effect/alien/weeds/new_weed) - RegisterSignal(new_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - bound_weed = new_weed - check_hivenumber_match() +/datum/action/xeno_action/onclick/change_design/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ChooseDesign", "Choose Design") + ui.set_autoupdate(FALSE) + ui.open() -/obj/effect/alien/resin/design/proc/hud_set_queen_overwatch() - return +/datum/action/xeno_action/onclick/change_design/Destroy() + SStgui.close_uis(src) + return ..() -/obj/effect/alien/resin/design/speed_node - name = "Design Optimized Node (50)" - icon_state = "static_speednode" - plasma_cost = 50 +/datum/action/xeno_action/onclick/change_design/ui_state(mob/user) + return GLOB.always_state -/obj/effect/alien/resin/design/speed_node/refresh_marker() - if(!chosenMark || !mark_meaning) +/datum/action/xeno_action/onclick/change_design/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) return - if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) - chosenMark.icon_state = mark_meaning.icon_state + "_speed" - else - ..() + var/mob/living/carbon/xenomorph/xeno = ui.user + if(!istype(xeno)) + return -/obj/effect/alien/resin/design/speed_node/get_marker_icon_state() - if(!mark_meaning) - return null - return mark_meaning.icon_state + "_speed" + switch(action) + if("choose_design") + var/selected_type = text2path(params["type"]) + if(!(selected_type in xeno.available_design)) + return -/obj/effect/alien/resin/design/speed_node/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this node looks like it has a big green oozing bulb at its center, making the weeds under it twitch...") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that building on top of this node will speed up your construction speed by [SPAN_BOLDNOTICE("50%")].") + var/obj/effect/alien/resin/design/design = selected_type + to_chat(xeno, SPAN_NOTICE("We will now build [initial(design.name)] when designing.")) + //update the button's overlay with new choice + xeno.update_icons() + button.overlays.Cut() + button.overlays += image(icon_file, button, action_icon_state) + button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, initial(design.icon_state)) + xeno.selected_design = selected_type + . = TRUE -/obj/effect/alien/resin/design/cost_node - name = "Design Flexible Node (60)" - icon_state = "static_costnode" - plasma_cost = 60 + if("refresh_ui") + . = TRUE -/obj/effect/alien/resin/design/cost_node/refresh_marker() - if(!chosenMark || !mark_meaning) - return - - if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) - chosenMark.icon_state = mark_meaning.icon_state + "_cost" - else - ..() - -/obj/effect/alien/resin/design/cost_node/get_marker_icon_state() - if(!mark_meaning) - return null - return mark_meaning.icon_state + "_cost" - -/obj/effect/alien/resin/design/cost_node/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this node looks like its made of smaller blue bulbs grown together, making the weeds under them look soft and squishy.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that building on top of this node will decrease plasma cost of basic resin structures by [SPAN_BOLDNOTICE("50%")].") - -/obj/effect/alien/resin/design/construct_node - name = "Design Construct Node (70)" - icon_state = "static_constructnode" - plasma_cost = 70 - var/plasma_donation = 70 - var/building = FALSE - var/thick_build = FALSE - var/obj/effect/resin_construct/build_overlay +///////////////////////////// +/// Place Design /// +///////////////////////////// -/obj/effect/alien/resin/design/construct_node/Initialize(mapload) - . = ..() - var/area/area = get_area(src) - if(area) - if(area.linked_lz) - AddComponent(/datum/component/resin_cleanup) - area.current_resin_count++ +/datum/action/xeno_action/activable/place_design + name = "Influence" + action_icon_state = "secrete_resin" + plasma_cost = 0 + macro_path = /datum/action/xeno_action/verb/place_design + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_3 + xeno_cooldown = 0 + var/max_reach = 10 + var/design_toggle = TRUE -/obj/effect/alien/resin/design/construct_node/proc/complete_construction(turf/Turf, design_mark, mob/living/carbon/xenomorph/xeno) - if(QDELETED(src) || QDELETED(Turf)) +/datum/action/xeno_action/activable/place_design/use_ability(atom/target_atom, mods, use_plasma = TRUE, message = TRUE) + var/mob/living/carbon/xenomorph/xeno = owner + if(!can_remote_build()) + to_chat(owner, SPAN_XENONOTICE("We must be standing on weeds to channel our nutrients and influence.")) return - if(build_overlay && !QDELETED(build_overlay)) - qdel(build_overlay) - build_overlay = null - - building = FALSE - - if(istype(design_mark, /datum/design_mark/resin_wall)) - if(!istype(Turf, /turf/closed/wall)) - var/turf/placed - if(thick_build) - placed = Turf.place_on_top(/turf/closed/wall/resin/weedbound/thick) - else - placed = Turf.place_on_top(/turf/closed/wall/resin/weedbound/normal) - - var/turf/closed/wall/resin/Res = get_turf(Turf) - if(istype(Res)) - Res.hivenumber = src.hivenumber - set_hive_data(Res, Res.hivenumber) - - to_chat(xeno, SPAN_NOTICE("We create a weedbound wall.")) - playsound(placed, "alien_resin_build", 25) - else - to_chat(xeno, SPAN_WARNING("A wall already exists here.")) - - else if(istype(design_mark, /datum/design_mark/resin_door)) - if(!istype(Turf, /obj/structure/mineral_door)) - var/obj/new_structure - if(thick_build) - new_structure = new /obj/structure/mineral_door/resin/weedbound/thick(Turf) - else - new_structure = new /obj/structure/mineral_door/resin/weedbound/normal(Turf) - - var/obj/structure/mineral_door/resin/Res = locate(/obj/structure/mineral_door/resin) in get_turf(Turf) - if(istype(Res)) - Res.hivenumber = src.hivenumber - set_hive_data(Res, Res.hivenumber) - - to_chat(xeno, SPAN_NOTICE("We create a weedbound door.")) - playsound(new_structure, "alien_resin_build", 25) - else - to_chat(xeno, SPAN_WARNING("A door already exists here.")) - - qdel(src) - -/obj/effect/alien/resin/design/construct_node/Destroy() - if(build_overlay && !QDELETED(build_overlay)) - qdel(build_overlay) - if(bound_weed) - unregister_weed_expiration_signal_design() - var/area/area = get_area(src) - area?.current_resin_count-- - return ..() - -/obj/effect/alien/resin/design/construct_node/attack_hand(mob/user) - if(!isxeno(user)) - to_chat(user, SPAN_WARNING("You don't understand how to interact with this strange node.")) + if(!action_cooldown_check()) return - var/mob/living/carbon/xenomorph/xeno = user - - if(!can_begin_construction(xeno)) + if(!xeno.check_state()) return - var/total_plasma_cost = get_total_plasma_cost(xeno) - if(xeno.plasma_stored < total_plasma_cost) - to_chat(xeno, SPAN_WARNING("You lack the plasma to feed this node. [xeno.plasma_stored]/[total_plasma_cost]")) + if(mods["click_catcher"]) return - xeno.plasma_stored -= total_plasma_cost - to_chat(xeno, SPAN_NOTICE("You activate the node, it latches onto us and it forcefully consumes [total_plasma_cost] of our plasma.")) - - begin_construction(xeno) - -/obj/effect/alien/resin/design/construct_node/attackby(obj/item/item, mob/user) - if(isxeno(user) && user.a_intent != INTENT_HARM) - if(istype(item, /obj/item/reagent_container/food/snacks/resin_fruit/plasma)) - to_chat(user, SPAN_NOTICE("We squeeze plasma fruit juices on node, activating its growth.")) - qdel(item) - thick_build = TRUE - - var/mob/living/carbon/xenomorph/xeno = user - begin_construction(xeno) + if(ismob(target_atom)) + if(!can_see(xeno, target_atom, max_reach)) + to_chat(xeno, SPAN_XENODANGER("We cannot see that location!")) return - - //Do NOT call attack_hand here — that bypasses destruction - to_chat(user, SPAN_NOTICE("You examine the node curiously, but nothing happens.")) - return - - . = ..() - -/obj/effect/alien/resin/design/construct_node/attack_alien(mob/living/carbon/xenomorph/xeno) - if(xeno.a_intent != INTENT_HARM) - return attack_hand(xeno) else - return ..() - -/obj/effect/alien/resin/design/construct_node/proc/get_total_plasma_cost(mob/living/carbon/xenomorph/xeno) - var/area/target_area = get_area(get_turf(src)) - var/total_plasma_cost = plasma_donation - - 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_plasma_cost = ceil(total_plasma_cost * (density_ratio + 0.35) * 2) - if(total_plasma_cost > xeno.plasma_max && (XENO_RESIN_BASE_COST + plasma_donation) < xeno.plasma_max) - total_plasma_cost = xeno.plasma_max - - return total_plasma_cost - -/obj/effect/alien/resin/design/construct_node/proc/can_begin_construction(mob/living/carbon/xenomorph/xeno) - if(building) - to_chat(xeno, SPAN_WARNING("This node is already being infused with plasma.")) - return FALSE - - if(xeno.hivenumber != src.hivenumber) - to_chat(xeno, SPAN_WARNING("This construct node does not belong to your hive.")) - return FALSE - - if(!mark_meaning) - to_chat(xeno, SPAN_WARNING("This node has no valid design selected.")) - return FALSE - - var/turf/Turf = get_turf(src) - if(!istype(Turf)) - to_chat(xeno, SPAN_WARNING("This is not a valid location.")) - return FALSE + if(get_dist(xeno, target_atom) > max_reach) + to_chat(xeno, SPAN_WARNING("That's too far away!")) + return - return TRUE + var/turf/target_turf = get_turf(target_atom) + if(!istype(target_turf)) + to_chat(xeno, SPAN_WARNING("We cannot design without weeds.")) + return -/obj/effect/alien/resin/design/construct_node/proc/begin_construction(mob/living/carbon/xenomorph/xeno) - if(!can_begin_construction(xeno)) + var/obj/effect/alien/weeds/target_weeds = locate(/obj/effect/alien/weeds) in target_turf + if(!target_weeds) + to_chat(xeno, SPAN_WARNING("There are no weeds to create a connection!")) return - var/turf/Turf = get_turf(src) - building = TRUE + if(target_weeds.hivenumber != xeno.hivenumber) + to_chat(xeno, SPAN_WARNING("These weeds do not belong to our hive; they reject our influence.")) + return - var/obj/effect/resin_construct/overlay + var/plasma_cost + if(xeno.selected_design && xeno.selected_design.plasma_cost) + plasma_cost = xeno.selected_design.plasma_cost - if(istype(mark_meaning, /datum/design_mark/resin_wall)) - overlay = new /obj/effect/resin_construct/construct_wallslow(Turf) - else if(istype(mark_meaning, /datum/design_mark/resin_door)) - overlay = new /obj/effect/resin_construct/construct_doorslow(Turf) + if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/upgrade)) + if(!(istype(target_atom, /turf/closed/wall/resin) || istype(target_atom, /turf/closed/wall/resin/membrane) || istype(target_atom, /obj/structure/mineral_door/resin))) + to_chat(xeno, SPAN_XENOWARNING("We can only upgrade resin walls, membrane and doors!")) + return - build_overlay = overlay + if(istype(target_atom, /turf/closed/wall/resin) || istype(target_atom, /turf/closed/wall/resin/membrane)) + var/turf/closed/wall/resin/wall = target_atom - if(bound_weed.weed_strength >= WEED_LEVEL_HIVE) - thick_build = TRUE + if(wall.hivenumber != xeno.hivenumber) + to_chat(xeno, SPAN_XENOWARNING("[wall] does not belong to our hive!")) + return - if((xeno.caste_type in XENO_CONSTRUCT_NODE_BOOST) && !istype(xeno.strain, /datum/xeno_strain/designer)) - thick_build = TRUE + if(wall.upgrading_now) //<--- Prevent spam and waste of plasma + to_chat(xeno, SPAN_WARNING("This wall is already being reinforced!")) + return - addtimer(CALLBACK(src, PROC_REF(complete_construction), Turf, mark_meaning, xeno), 4 SECONDS) + wall.upgrading_now = TRUE -/obj/effect/alien/resin/design/construct_node/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this node looks like big blub composed of smaller purple glowing cups, pumping some strange liquid trough weeds.") - if(isxeno(user) || isobserver(user)) - var/mob/living/carbon/xenomorph/xeno = user - var/total_plasma_cost = get_total_plasma_cost(xeno) - . += SPAN_NOTICE("You sense that feeding [SPAN_BOLDNOTICE("[total_plasma_cost]")] plasma with our hand to this node will secrete a [SPAN_BOLDNOTICE("[mark_meaning]")], you also heard that using plasma fruit works too.") + if(wall.type == /turf/closed/wall/resin) + var/obj/thick_wall = new /obj/effect/resin_construct/thickfast(target_turf, src, xeno) + if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) + qdel(thick_wall) + wall.upgrading_now = FALSE + return + qdel(thick_wall) + wall.ChangeTurf(/turf/closed/wall/resin/thick) -//Should not be upgradable because it's not "stable" but special actions should create thick variant -/turf/closed/wall/resin/weedbound //NEVER use this variant, use subtypes - name = "weedbound resin wall" - desc = "An oddly solidified resin wall with a layered pattern that reminds you of flower buds." - icon_state = "weedboundresin" - walltype = WALL_WEEDBOUND_RESIN + else if(wall.type == /turf/closed/wall/resin/membrane) + var/obj/thick_membrane = new /obj/effect/resin_construct/transparent/thickfast(target_turf, src, xeno) + if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) + qdel(thick_membrane) + wall.upgrading_now = FALSE + return + qdel(thick_membrane) + wall.ChangeTurf(/turf/closed/wall/resin/membrane/thick) + else + to_chat(xeno, SPAN_XENOWARNING("[wall] can't be made thicker.")) + return - var/obj/effect/alien/weeds/bound_weed - var/old_hivenumber + wall.upgrading_now = FALSE -/turf/closed/wall/resin/weedbound/Initialize() - . = ..() - bound_weed = locate(/obj/effect/alien/weeds) in get_turf(src) - if(!bound_weed) - addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 3 SECONDS) - return - if(bound_weed) - old_hivenumber = bound_weed.hivenumber - RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + else if(istype(target_atom, /obj/structure/mineral_door/resin)) + var/obj/structure/mineral_door/resin/door = target_atom -/turf/closed/wall/resin/weedbound/Destroy() - if(bound_weed) - UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) - bound_weed = null + if(door.hivenumber != xeno.hivenumber) + to_chat(xeno, SPAN_XENOWARNING("[door] does not belong to your hive!")) + return - var/turf/Turf = get_turf(src) - if(Turf) - visible_message(SPAN_ALERT("The weedbound wall collapses into a puddle of sticky slime.")) - spawn_nutriplasm(Turf) + if(door.upgrading_now) + to_chat(xeno, SPAN_WARNING("This door is already being reinforced!")) + return - return ..() + if(door.hardness == 1.5) + door.upgrading_now = TRUE + var/obj/thick_door = new /obj/effect/resin_construct/thickdoorfast(target_turf, src, xeno) + if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) + qdel(thick_door) + door.upgrading_now = FALSE + return + qdel(thick_door) + var/oldloc = door.loc + qdel(door) + new /obj/structure/mineral_door/resin/thick(oldloc, door.hivenumber) + else + if(xeno.try_toggle_resin_door(door)) + if(!check_and_use_plasma_owner()) + return TRUE + return + return -/turf/closed/wall/resin/weedbound/proc/spawn_nutriplasm(turf/Turf) - return + else + to_chat(xeno, SPAN_XENOWARNING("We can only upgrade resin structures!")) + return -/turf/closed/wall/resin/weedbound/proc/on_weed_expire() - SIGNAL_HANDLER + if(!check_and_use_plasma_owner(plasma_cost)) + return - if(!old_hivenumber) - ScrapeAway() - return + xeno.visible_message(SPAN_XENONOTICE("Weeds around [target_atom] start to twitch and pump substance towards it, thickening it in process!"), + SPAN_XENONOTICE("We start to channel nutrients towards [target_atom], using [plasma_cost] plasma."), null, 5) + playsound(target_atom, "alien_resin_build", 25) - addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 1 DECISECONDS) + target_atom.add_hiddenprint(xeno) //Tracks who reinforced it for admins + return TRUE -/turf/closed/wall/resin/weedbound/proc/check_weed_replacement() - var/turf/Turf = get_turf(src) - if(!Turf) - ScrapeAway() + if(xeno.try_toggle_resin_door(target_atom)) + if(!check_and_use_plasma_owner()) + return TRUE return - var/obj/effect/alien/weeds/new_weed = locate(/obj/effect/alien/weeds) in Turf - - if(new_weed && new_weed.hivenumber == old_hivenumber) - bound_weed = new_weed - RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - else - playsound(src, "alien_resin_break", 25) - ScrapeAway() - -/turf/closed/wall/resin/weedbound/normal/spawn_nutriplasm(turf/Turf) - new /obj/effect/alien/resin/sticky/weak_nutriplasm(Turf) - -/turf/closed/wall/resin/weedbound/normal/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this strange wall appears to have merged with the resin below to hold itself together.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that this resin wall will collapse if the weeds it is merged with disappear.") - -/turf/closed/wall/resin/weedbound/thick - name = "thick weedbound resin wall" - desc = "An oddly solidified thick resin wall with a layered pattern that reminds you of flower buds." - icon_state = "thickweedboundresin" - damage_cap = HEALTH_WALL_XENO_THICK - walltype = WALL_THICK_WEEDBOUND_RESIN + if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/remove)) + var/obj/effect/alien/resin/design/target_node = locate(/obj/effect/alien/resin/design) in target_turf + if(!target_node) + to_chat(xeno, SPAN_XENOWARNING("There is no resin node here to remove!")) + return -/turf/closed/wall/resin/weedbound/thick/spawn_nutriplasm(turf/Turf) - new /obj/effect/alien/resin/sticky/strong_nutriplasm(Turf) + if(target_node.hivenumber != xeno.hivenumber) + to_chat(xeno, SPAN_XENOWARNING("This node does not belong to your hive!")) + return -/turf/closed/wall/resin/weedbound/thick/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this strange darker wall appears to have merged with the resin below to hold itself together.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that this thick resin wall will collapse if the weeds it is merged with disappear.") + if(target_node.bound_xeno != xeno) + to_chat(xeno, SPAN_XENOWARNING("You cannot remove a node placed by another sister!")) + return -/obj/structure/mineral_door/resin/weedbound //NEVER use this variant, use subtypes - name = "weedbound resin door" - desc = "A weird resin door that solidified strangely, forming a petal-like pattern." - icon_state = "weedbound resin" - mineralType = "weedbound resin" - hardness = 1.4 + qdel(target_node) + to_chat(xeno, SPAN_XENONOTICE("We sever the bond to the node, causing it to dissolve into the ground.")) + playsound(xeno.loc, "alien_resin_move2", 25) + return - var/obj/effect/alien/weeds/bound_weed - var/old_hivenumber + if(length(xeno.current_design) >= xeno.max_design_nodes) //Check if there are more nodes than length that was defined + to_chat(xeno, SPAN_XENOWARNING("We cannot sustain another node, one will wither away to allow this one to live!")) + var/obj/effect/alien/resin/design/old_design = xeno.current_design[1] //Check with node is first for deletion on list + xeno.current_design.Remove(old_design) //Removes first node stored inside list + qdel(old_design) //Delete node. -/obj/structure/mineral_door/resin/weedbound/Initialize() - . = ..() - bound_weed = locate(/obj/effect/alien/weeds) in get_turf(src) - if(!bound_weed) - addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 3 SECONDS) - return - if(bound_weed) - old_hivenumber = bound_weed.hivenumber - RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + var/selected_design = xeno.selected_design -/obj/structure/mineral_door/resin/weedbound/Destroy() - if(bound_weed) - UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) - bound_weed = null + if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/speed_node)) //Check path you selected from list + if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) + to_chat(src, SPAN_WARNING("There's something built here already.")) + return + var/obj/speed_warn = new /obj/effect/resin_construct/speed_node(target_turf, src, xeno) //Create "Animation" overlay + if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) + qdel(speed_warn) //Delete "Animation" overlay after defined time + return + qdel(speed_warn) //Delete again just in case overlay don't get deleted + if(!is_turf_clean(target_turf)) //Recheck the turf again just in case + to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) + return + if(!check_and_use_plasma_owner(plasma_cost)) + return + xeno.visible_message(SPAN_XENONOTICE("\The [xeno] channels nutrients and shapes it into a node!")) + var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) //Create node you selected from list + if(!design) + to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) + return + playsound(xeno.loc, "alien_resin_build", 25) + xeno.current_design.Add(design) //Add Node to list. - var/turf/Turf = get_turf(src) - if(Turf) - visible_message(SPAN_ALERT("The weedbound wall collapses into a puddle of sticky slime.")) - spawn_nutriplasm(Turf) + if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/cost_node)) + if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) + to_chat(src, SPAN_WARNING("There's something built here already.")) + return + var/obj/cost_warn = new /obj/effect/resin_construct/cost_node(target_turf, src, xeno) + if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) + qdel(cost_warn) + return + qdel(cost_warn) + if(!is_turf_clean(target_turf)) + to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) + return + if(!check_and_use_plasma_owner(plasma_cost)) + return + xeno.visible_message(SPAN_XENONOTICE("The [xeno] channels nutrients and shapes it into a node!")) + var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) + if(!design) + to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) + return + playsound(xeno.loc, "alien_resin_build", 25) + xeno.current_design.Add(design) + if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/construct_node)) + if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) + to_chat(src, SPAN_WARNING("There's something built here already.")) + return + if(!xeno.check_alien_construction(target_turf, check_doors = FALSE)) + return FALSE + var/obj/const_warn = new /obj/effect/resin_construct/construct_node(target_turf, src, xeno) + if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) + qdel(const_warn) + return + qdel(const_warn) + if(!is_turf_clean(target_turf)) + to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) + return + if(!check_and_use_plasma_owner(plasma_cost)) + return + xeno.visible_message(SPAN_XENONOTICE("The [xeno] channels nutrients and shapes it into a node!")) + var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) + if(!design) + to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) + return + playsound(xeno.loc, "alien_resin_build", 25) + xeno.current_design.Add(design) + apply_cooldown() return ..() -/obj/structure/mineral_door/resin/weedbound/proc/spawn_nutriplasm(turf/Turf) - return - -/obj/structure/mineral_door/resin/weedbound/proc/on_weed_expire() - SIGNAL_HANDLER +/datum/action/xeno_action/activable/place_design/proc/can_remote_build() + if(!locate(/obj/effect/alien/weeds) in get_turf(owner)) + return FALSE + return TRUE - if(!old_hivenumber) - Dismantle() - return +/mob/living/carbon/xenomorph/proc/try_toggle_resin_door(atom/target_atom) + if(!istype(target_atom, /obj/structure/mineral_door/resin)) + return FALSE - addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 1 DECISECONDS) + var/obj/structure/mineral_door/resin/resin_door = target_atom -/obj/structure/mineral_door/resin/weedbound/proc/check_weed_replacement() - var/turf/Turf = get_turf(src) - if(!Turf) - Dismantle() - return + if(resin_door.hivenumber != hivenumber) + to_chat(src, SPAN_XENOWARNING("This door does not belong to our hive!")) + return TRUE - var/obj/effect/alien/weeds/new_weed = locate(/obj/effect/alien/weeds) in Turf + if(resin_door.TryToSwitchState(src)) + if(resin_door.open) + to_chat(src, SPAN_XENONOTICE("We focus our connection to the resin and remotely close the resin door.")) + else + to_chat(src, SPAN_XENONOTICE("We focus our connection to the resin and remotely open the resin door.")) - if(new_weed && new_weed.hivenumber == old_hivenumber) - bound_weed = new_weed - RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - else - playsound(src, "alien_resin_break", 25) - Dismantle() + return TRUE -/obj/structure/mineral_door/resin/weedbound/normal/spawn_nutriplasm(turf/Turf) - new /obj/effect/alien/resin/sticky/weak_nutriplasm(Turf) +/datum/action/xeno_action/activable/place_design/proc/is_turf_clean(turf/current_turf, check_resin_additions = FALSE, check_doors = FALSE, check_resin_doors = FALSE) + var/has_obstacle = FALSE + for(var/obj/target in current_turf) + if(check_doors) + if(istype(target, /obj/structure/machinery/door)) + to_chat(src, SPAN_WARNING("[target] is blocking the resin! There's not enough space to build that here.")) + return FALSE + if(check_resin_additions) + if(istype(target, /obj/effect/alien/resin/sticky) || istype(target, /obj/effect/alien/resin/spike) || istype(target, /obj/effect/alien/resin/sticky/fast)) + has_obstacle = TRUE + to_chat(src, SPAN_WARNING("[target] is blocking the resin!")) + return FALSE + if(check_resin_doors) + if(istype(target, /obj/structure/mineral_door/resin)) + to_chat(src, SPAN_WARNING("[target] is blocking the resin node! There's not enough space to build that here.")) + return FALSE + if(current_turf.density || has_obstacle || locate(/obj/effect/alien/resin/design) in current_turf) + return FALSE + return TRUE -/obj/structure/mineral_door/resin/weedbound/normal/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this strange door appears to have merged with the resin below to hold itself together.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that this resin door will collapse if the weeds it is merged with disappear.") +/////////////////////////////// +/// Change Node Marker /// +/////////////////////////////// -/obj/structure/mineral_door/resin/weedbound/thick - name = "thick weedbound resin door" - desc = "A weird thick resin door that solidified strangely, forming a petal-like pattern." - icon_state = "thick weedbound resin" - mineralType = "thick weedbound resin" - health = HEALTH_DOOR_XENO_THICK - hardness = 1.9 +/datum/action/xeno_action/onclick/toggle_design_icons + name = "Change Design Mark" + action_icon_state = "design_mark_1" + plasma_cost = 0 + macro_path = /datum/action/xeno_action/verb/verb_toggle_design_icons + action_type = XENO_ACTION_CLICK + ability_primacy = XENO_PRIMARY_ACTION_4 -/obj/structure/mineral_door/resin/weedbound/thick/spawn_nutriplasm(turf/Turf) - new /obj/effect/alien/resin/sticky/strong_nutriplasm(Turf) +/datum/action/xeno_action/onclick/toggle_design_icons/can_use_action() + var/mob/living/carbon/xenomorph/xeno = owner + if(xeno && !xeno.buckled && !xeno.is_mob_incapacitated()) + return TRUE -/obj/structure/mineral_door/resin/weedbound/thick/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this strange darker door appears to have merged with the resin below to hold itself together.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("You sense that this thick resin door will collapse if the weeds it is merged with disappear.") +/datum/action/xeno_action/onclick/toggle_design_icons/use_ability() + var/mob/living/carbon/xenomorph/xeno = owner -/obj/effect/alien/resin/sticky/weak_nutriplasm - name = "thin sticky nutriplasm" - desc = "A thin layer of disgusting sticky slime." - icon_state = "weak_nutriplasm" - slow_amt = 5 + if (!istype(xeno)) + return -/obj/effect/alien/resin/sticky/weak_nutriplasm/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this thin, sticky substance reminds you of sticky resin.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("We stare at the remains of weedbound walls - nutriplasm. As edible as it sounds, it's just another kind of sticky resin.") + if(!xeno.check_state(TRUE)) + return -/obj/effect/alien/resin/sticky/strong_nutriplasm - name = "sticky nutriplasm" - desc = "A thick layer of disgusting sticky slime." - icon_state = "strong_nutriplasm" - slow_amt = 10 + var/datum/action/xeno_action/activable/place_design/cAction = get_action(xeno, /datum/action/xeno_action/activable/place_design) -/obj/effect/alien/resin/sticky/strong_nutriplasm/get_examine_text(mob/user) - . = ..() - if(ishuman(user)) - . += SPAN_NOTICE("On closer examination, this thick, sticky substance reminds you of sticky resin.") - if(isxeno(user) || isobserver(user)) - . += SPAN_NOTICE("We stare at thick nutriplasm, the remains from weedbound resin, it sound delicious but you remember, its just different sticky resin.") + if(!istype(cAction)) + return -/obj/effect/alien/resin/design/upgrade - name = "Thicken Resin (60)" - desc = "Channel our plasma and nutrients to thicken structures." - icon = 'icons/mob/hud/actions_xeno.dmi' - icon_state = "upgrade_resin" - plasma_cost = 60 + cAction.design_toggle = !cAction.design_toggle -/obj/effect/alien/resin/design/remove - name = "Remove Design Node (25)" - desc = "Channel our plasma to revert design node back to weeds." - icon = 'icons/mob/hud/actions_xeno.dmi' - icon_state = "remove_node" - plasma_cost = 25 + var/action_icon_result + if(cAction.design_toggle) + action_icon_result = "design_mark_1" + to_chat(xeno, SPAN_INFO("We will now place wall markers.")) + xeno.selected_design_mark = /datum/design_mark/resin_wall + else + action_icon_result = "design_mark_2" + to_chat(xeno, SPAN_INFO("We will now place door markers.")) + xeno.selected_design_mark = /datum/design_mark/resin_door + + button.overlays.Cut() + button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, action_icon_result) + return ..() ////////////////////////// // Greater Resin Surge. // ////////////////////////// -/datum/action/xeno_action/verb/verb_greater_surge() - set category = "Alien" - set name = "Greater Resin Surge" - set hidden = TRUE - var/action_name = "Greater Resin Surge" - handle_xeno_macro(src, action_name) - /datum/action/xeno_action/activable/greater_resin_surge name = "Greater Resin Surge (250)" action_icon_state = "greater_resin_surge" @@ -748,517 +612,596 @@ qdel(node) xeno.current_design -= node -/datum/action/xeno_action/activable/greater_resin_surge/proc/create_animation_overlay(turf/target_turf, animation_type) - if(!istype(target_turf, /turf)) - return +/datum/action/xeno_action/activable/greater_resin_surge/proc/create_animation_overlay(turf/target_turf, animation_type) + if(!istype(target_turf, /turf)) + return + + if(!ispath(animation_type, /obj/effect/resin_construct/fastweak)) + return + var/obj/effect/resin_construct/fastweak/animation = new animation_type(target_turf) + + addtimer(CALLBACK(animation, TYPE_PROC_REF(/obj/effect/resin_construct/fastweak, delete_animation)), 2 SECONDS) + +/obj/effect/resin_construct/fastweak/proc/delete_animation() + if(!QDELETED(src)) + qdel(src) + +//Marks + +/datum/design_mark + var/name = "xeno_declare" + var/icon_state = "empty" + var/desc = "Xenos make psychic markers with this meaning as positional lasting communication to each other." + +/datum/design_mark/resin_wall + name = "Resin Wall" + desc = "Place resin wall here!" + icon_state = "mark_wall" + +/datum/design_mark/resin_door + name = "Resin Door" + desc = "Place resin door here!" + icon_state = "mark_door" + +////////////////////////// +/// Designer... Paths. /// +////////////////////////// + +/obj/effect/alien/resin/design + name = "Design Node" + desc = "A weird node, it looks mutated." + icon = 'icons/mob/xenos/effects.dmi' + icon_state = "static_speednode" + density = FALSE + opacity = FALSE + layer = RESIN_UNDER_STRUCTURE_LAYER + plane = FLOOR_PLANE + health = HEALTH_RESIN_XENO_STICKY + + var/datum/design_mark/mark_meaning = /datum/design_mark/resin_wall + var/mob/living/carbon/xenomorph/bound_xeno + var/obj/effect/alien/weeds/bound_weed + var/hivenumber = XENO_HIVE_NORMAL + var/plasma_cost = 0 + + var/image/chosenMark + +/obj/effect/alien/resin/design/Initialize(mapload, obj/effect/alien/weeds/weeds, mob/living/carbon/xenomorph/xeno) + if(!istype(xeno)) + return INITIALIZE_HINT_QDEL + + bound_xeno = xeno + bound_weed = weeds + hivenumber = xeno.hivenumber + + RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + RegisterSignal(bound_xeno, COMSIG_PARENT_QDELETING, PROC_REF(on_xeno_expire)) + + set_hive_data(src, hivenumber) + . = ..() + + if(bound_weed.hivenumber != bound_xeno.hivenumber) + qdel(src) + + if(xeno.selected_design_mark) + mark_meaning = new xeno.selected_design_mark + + var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] + if(hive) + hive.designer_marks += src + if(mark_meaning) + var/icon_state_to_use = get_marker_icon_state() + if(icon_state_to_use) + chosenMark = image(icon, src, icon_state_to_use, ABOVE_HUD_LAYER, "pixel_y" = 5) + chosenMark.plane = ABOVE_HUD_PLANE + chosenMark.appearance_flags = RESET_COLOR + + for(xeno in hive.totalXenos) + if(xeno.client) + xeno.hud_set_design_marks() + refresh_marker() + +/obj/effect/alien/resin/design/Destroy() + var/datum/hive_status/hive = GLOB.hive_datum[hivenumber] + if(hive) + hive.designer_marks -= src + for(var/mob/living/carbon/xenomorph/xeno in hive.totalXenos) + if(xeno.client && chosenMark) + xeno.client.images -= chosenMark + xeno.hud_set_design_marks() + + if(!QDELETED(bound_xeno)) + bound_xeno.current_design.Remove(src) + unregister_weed_expiration_signal_design() + bound_xeno = null + bound_weed = null + chosenMark = null + return ..() + +/obj/effect/alien/resin/design/proc/refresh_marker() + if(!chosenMark || !mark_meaning) + return + + if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) + chosenMark.icon_state = mark_meaning.icon_state + +/obj/effect/alien/resin/design/proc/get_marker_icon_state() + if(!mark_meaning) + return null + return mark_meaning.icon_state - if(!ispath(animation_type, /obj/effect/resin_construct/fastweak)) - return - var/obj/effect/resin_construct/fastweak/animation = new animation_type(target_turf) +/obj/effect/alien/resin/design/proc/on_weed_expire() + SIGNAL_HANDLER + qdel(src) - addtimer(CALLBACK(animation, TYPE_PROC_REF(/obj/effect/resin_construct/fastweak, delete_animation)), 2 SECONDS) +/obj/effect/alien/resin/design/proc/on_xeno_expire() + SIGNAL_HANDLER + qdel(src) -/obj/effect/resin_construct/fastweak/proc/delete_animation() - if(!QDELETED(src)) +/obj/effect/alien/resin/design/proc/check_hivenumber_match() + if(!bound_weed || !bound_xeno) + visible_message(SPAN_XENOWARNING("The node shudders and decays back into the weeds.")) + qdel(src) + else if(bound_weed.hivenumber != bound_xeno.hivenumber) + visible_message(SPAN_XENOWARNING("The node withers away.")) qdel(src) -///////////////////////////// -/// Place Design /// -///////////////////////////// +/obj/effect/alien/resin/design/proc/unregister_weed_expiration_signal_design() + if(bound_weed) + UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) -/datum/action/xeno_action/activable/place_design - name = "Influence" - action_icon_state = "secrete_resin" - plasma_cost = 0 - macro_path = /datum/action/xeno_action/verb/place_design - action_type = XENO_ACTION_CLICK - ability_primacy = XENO_PRIMARY_ACTION_3 - xeno_cooldown = 0 - var/max_reach = 10 - var/design_toggle = TRUE +/obj/effect/alien/resin/design/proc/register_weed_expiration_signal_design(obj/effect/alien/weeds/new_weed) + RegisterSignal(new_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + bound_weed = new_weed + check_hivenumber_match() -/datum/action/xeno_action/verb/place_design() - set category = "Alien" - set name = "Place Design" - set hidden = TRUE - var/action_name = "Place Design" - handle_xeno_macro(src, action_name) +/obj/effect/alien/resin/design/proc/hud_set_queen_overwatch() + return -/datum/action/xeno_action/activable/place_design/use_ability(atom/target_atom, mods, use_plasma = TRUE, message = TRUE) - var/mob/living/carbon/xenomorph/xeno = owner - if(!can_remote_build()) - to_chat(owner, SPAN_XENONOTICE("We must be standing on weeds to channel our nutrients and influence.")) - return +/obj/effect/alien/resin/design/speed_node + name = "Design Optimized Node (50)" + icon_state = "static_speednode" + plasma_cost = 50 - if(!action_cooldown_check()) +/obj/effect/alien/resin/design/speed_node/refresh_marker() + if(!chosenMark || !mark_meaning) return - if(!xeno.check_state()) - return + if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) + chosenMark.icon_state = mark_meaning.icon_state + "_speed" + else + ..() - if(mods["click_catcher"]) - return +/obj/effect/alien/resin/design/speed_node/get_marker_icon_state() + if(!mark_meaning) + return null + return mark_meaning.icon_state + "_speed" - if(ismob(target_atom)) - if(!can_see(xeno, target_atom, max_reach)) - to_chat(xeno, SPAN_XENODANGER("We cannot see that location!")) - return - else - if(get_dist(xeno, target_atom) > max_reach) - to_chat(xeno, SPAN_WARNING("That's too far away!")) - return +/obj/effect/alien/resin/design/speed_node/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this node looks like it has a big green oozing bulb at its center, making the weeds under it twitch...") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that building on top of this node will speed up your construction speed by [SPAN_BOLDNOTICE("50%")].") - var/turf/target_turf = get_turf(target_atom) - if(!istype(target_turf)) - to_chat(xeno, SPAN_WARNING("We cannot design without weeds.")) - return +/obj/effect/alien/resin/design/cost_node + name = "Design Flexible Node (60)" + icon_state = "static_costnode" + plasma_cost = 60 - var/obj/effect/alien/weeds/target_weeds = locate(/obj/effect/alien/weeds) in target_turf - if(!target_weeds) - to_chat(xeno, SPAN_WARNING("There are no weeds to create a connection!")) +/obj/effect/alien/resin/design/cost_node/refresh_marker() + if(!chosenMark || !mark_meaning) return - if(target_weeds.hivenumber != xeno.hivenumber) - to_chat(xeno, SPAN_WARNING("These weeds do not belong to our hive; they reject our influence.")) - return + if(bound_xeno.selected_design_mark == /datum/design_mark/resin_wall || bound_xeno.selected_design_mark == /datum/design_mark/resin_door) + chosenMark.icon_state = mark_meaning.icon_state + "_cost" + else + ..() - var/plasma_cost - if(xeno.selected_design && xeno.selected_design.plasma_cost) - plasma_cost = xeno.selected_design.plasma_cost +/obj/effect/alien/resin/design/cost_node/get_marker_icon_state() + if(!mark_meaning) + return null + return mark_meaning.icon_state + "_cost" - if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/upgrade)) - if(!(istype(target_atom, /turf/closed/wall/resin) || istype(target_atom, /turf/closed/wall/resin/membrane) || istype(target_atom, /obj/structure/mineral_door/resin))) - to_chat(xeno, SPAN_XENOWARNING("We can only upgrade resin walls, membrane and doors!")) - return +/obj/effect/alien/resin/design/cost_node/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this node looks like its made of smaller blue bulbs grown together, making the weeds under them look soft and squishy.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that building on top of this node will decrease plasma cost of basic resin structures by [SPAN_BOLDNOTICE("50%")].") - if(istype(target_atom, /turf/closed/wall/resin) || istype(target_atom, /turf/closed/wall/resin/membrane)) - var/turf/closed/wall/resin/wall = target_atom +/obj/effect/alien/resin/design/construct_node + name = "Design Construct Node (70)" + icon_state = "static_constructnode" + plasma_cost = 70 + var/plasma_donation = 70 + var/building = FALSE + var/thick_build = FALSE + var/obj/effect/resin_construct/build_overlay - if(wall.hivenumber != xeno.hivenumber) - to_chat(xeno, SPAN_XENOWARNING("[wall] does not belong to our hive!")) - return +/obj/effect/alien/resin/design/construct_node/Initialize(mapload) + . = ..() + var/area/area = get_area(src) + if(area) + if(area.linked_lz) + AddComponent(/datum/component/resin_cleanup) + area.current_resin_count++ - if(wall.upgrading_now) //<--- Prevent spam and waste of plasma - to_chat(xeno, SPAN_WARNING("This wall is already being reinforced!")) - return +/obj/effect/alien/resin/design/construct_node/proc/complete_construction(turf/Turf, design_mark, mob/living/carbon/xenomorph/xeno) + if(QDELETED(src) || QDELETED(Turf)) + return - wall.upgrading_now = TRUE + if(build_overlay && !QDELETED(build_overlay)) + qdel(build_overlay) + build_overlay = null - if(wall.type == /turf/closed/wall/resin) - var/obj/thick_wall = new /obj/effect/resin_construct/thickfast(target_turf, src, xeno) - if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) - qdel(thick_wall) - wall.upgrading_now = FALSE - return - qdel(thick_wall) - wall.ChangeTurf(/turf/closed/wall/resin/thick) + building = FALSE - else if(wall.type == /turf/closed/wall/resin/membrane) - var/obj/thick_membrane = new /obj/effect/resin_construct/transparent/thickfast(target_turf, src, xeno) - if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) - qdel(thick_membrane) - wall.upgrading_now = FALSE - return - qdel(thick_membrane) - wall.ChangeTurf(/turf/closed/wall/resin/membrane/thick) + if(istype(design_mark, /datum/design_mark/resin_wall)) + if(!istype(Turf, /turf/closed/wall)) + var/turf/placed + if(thick_build) + placed = Turf.place_on_top(/turf/closed/wall/resin/weedbound/thick) else - to_chat(xeno, SPAN_XENOWARNING("[wall] can't be made thicker.")) - return - - wall.upgrading_now = FALSE - - else if(istype(target_atom, /obj/structure/mineral_door/resin)) - var/obj/structure/mineral_door/resin/door = target_atom + placed = Turf.place_on_top(/turf/closed/wall/resin/weedbound/normal) - if(door.hivenumber != xeno.hivenumber) - to_chat(xeno, SPAN_XENOWARNING("[door] does not belong to your hive!")) - return + var/turf/closed/wall/resin/Res = get_turf(Turf) + if(istype(Res)) + Res.hivenumber = src.hivenumber + set_hive_data(Res, Res.hivenumber) - if(door.upgrading_now) - to_chat(xeno, SPAN_WARNING("This door is already being reinforced!")) - return + to_chat(xeno, SPAN_NOTICE("We create a weedbound wall.")) + playsound(placed, "alien_resin_build", 25) + else + to_chat(xeno, SPAN_WARNING("A wall already exists here.")) - if(door.hardness == 1.5) - door.upgrading_now = TRUE - var/obj/thick_door = new /obj/effect/resin_construct/thickdoorfast(target_turf, src, xeno) - if(!do_after(xeno, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD)) - qdel(thick_door) - door.upgrading_now = FALSE - return - qdel(thick_door) - var/oldloc = door.loc - qdel(door) - new /obj/structure/mineral_door/resin/thick(oldloc, door.hivenumber) + else if(istype(design_mark, /datum/design_mark/resin_door)) + if(!istype(Turf, /obj/structure/mineral_door)) + var/obj/new_structure + if(thick_build) + new_structure = new /obj/structure/mineral_door/resin/weedbound/thick(Turf) else - if(xeno.try_toggle_resin_door(door)) - if(!check_and_use_plasma_owner()) - return TRUE - return - return + new_structure = new /obj/structure/mineral_door/resin/weedbound/normal(Turf) + + var/obj/structure/mineral_door/resin/Res = locate(/obj/structure/mineral_door/resin) in get_turf(Turf) + if(istype(Res)) + Res.hivenumber = src.hivenumber + set_hive_data(Res, Res.hivenumber) + to_chat(xeno, SPAN_NOTICE("We create a weedbound door.")) + playsound(new_structure, "alien_resin_build", 25) else - to_chat(xeno, SPAN_XENOWARNING("We can only upgrade resin structures!")) - return + to_chat(xeno, SPAN_WARNING("A door already exists here.")) - if(!check_and_use_plasma_owner(plasma_cost)) - return + qdel(src) - xeno.visible_message(SPAN_XENONOTICE("Weeds around [target_atom] start to twitch and pump substance towards it, thickening it in process!"), - SPAN_XENONOTICE("We start to channel nutrients towards [target_atom], using [plasma_cost] plasma."), null, 5) - playsound(target_atom, "alien_resin_build", 25) +/obj/effect/alien/resin/design/construct_node/Destroy() + if(build_overlay && !QDELETED(build_overlay)) + qdel(build_overlay) + if(bound_weed) + unregister_weed_expiration_signal_design() + var/area/area = get_area(src) + area?.current_resin_count-- + return ..() - target_atom.add_hiddenprint(xeno) //Tracks who reinforced it for admins - return TRUE +/obj/effect/alien/resin/design/construct_node/attack_hand(mob/user) + if(!isxeno(user)) + to_chat(user, SPAN_WARNING("You don't understand how to interact with this strange node.")) + return - if(xeno.try_toggle_resin_door(target_atom)) - if(!check_and_use_plasma_owner()) - return TRUE + var/mob/living/carbon/xenomorph/xeno = user + + if(!can_begin_construction(xeno)) + return + + var/total_plasma_cost = get_total_plasma_cost(xeno) + if(xeno.plasma_stored < total_plasma_cost) + to_chat(xeno, SPAN_WARNING("You lack the plasma to feed this node. [xeno.plasma_stored]/[total_plasma_cost]")) return - if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/remove)) - var/obj/effect/alien/resin/design/target_node = locate(/obj/effect/alien/resin/design) in target_turf - if(!target_node) - to_chat(xeno, SPAN_XENOWARNING("There is no resin node here to remove!")) - return + xeno.plasma_stored -= total_plasma_cost + to_chat(xeno, SPAN_NOTICE("You activate the node, it latches onto us and it forcefully consumes [total_plasma_cost] of our plasma.")) - if(target_node.hivenumber != xeno.hivenumber) - to_chat(xeno, SPAN_XENOWARNING("This node does not belong to your hive!")) - return + begin_construction(xeno) - if(target_node.bound_xeno != xeno) - to_chat(xeno, SPAN_XENOWARNING("You cannot remove a node placed by another sister!")) +/obj/effect/alien/resin/design/construct_node/attackby(obj/item/item, mob/user) + if(isxeno(user) && user.a_intent != INTENT_HARM) + if(istype(item, /obj/item/reagent_container/food/snacks/resin_fruit/plasma)) + to_chat(user, SPAN_NOTICE("We squeeze plasma fruit juices on node, activating its growth.")) + qdel(item) + thick_build = TRUE + + var/mob/living/carbon/xenomorph/xeno = user + begin_construction(xeno) return - qdel(target_node) - to_chat(xeno, SPAN_XENONOTICE("We sever the bond to the node, causing it to dissolve into the ground.")) - playsound(xeno.loc, "alien_resin_move2", 25) + //Do NOT call attack_hand here — that bypasses destruction + to_chat(user, SPAN_NOTICE("You examine the node curiously, but nothing happens.")) return - if(length(xeno.current_design) >= xeno.max_design_nodes) //Check if there are more nodes than length that was defined - to_chat(xeno, SPAN_XENOWARNING("We cannot sustain another node, one will wither away to allow this one to live!")) - var/obj/effect/alien/resin/design/old_design = xeno.current_design[1] //Check with node is first for deletion on list - xeno.current_design.Remove(old_design) //Removes first node stored inside list - qdel(old_design) //Delete node. + . = ..() - var/selected_design = xeno.selected_design +/obj/effect/alien/resin/design/construct_node/attack_alien(mob/living/carbon/xenomorph/xeno) + if(xeno.a_intent != INTENT_HARM) + return attack_hand(xeno) + else + return ..() - if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/speed_node)) //Check path you selected from list - if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) - to_chat(src, SPAN_WARNING("There's something built here already.")) - return - var/obj/speed_warn = new /obj/effect/resin_construct/speed_node(target_turf, src, xeno) //Create "Animation" overlay - if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) - qdel(speed_warn) //Delete "Animation" overlay after defined time - return - qdel(speed_warn) //Delete again just in case overlay don't get deleted - if(!is_turf_clean(target_turf)) //Recheck the turf again just in case - to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) - return - if(!check_and_use_plasma_owner(plasma_cost)) - return - xeno.visible_message(SPAN_XENONOTICE("\The [xeno] channels nutrients and shapes it into a node!")) - var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) //Create node you selected from list - if(!design) - to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) - return - playsound(xeno.loc, "alien_resin_build", 25) - xeno.current_design.Add(design) //Add Node to list. +/obj/effect/alien/resin/design/construct_node/proc/get_total_plasma_cost(mob/living/carbon/xenomorph/xeno) + var/area/target_area = get_area(get_turf(src)) + var/total_plasma_cost = plasma_donation - if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/cost_node)) - if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) - to_chat(src, SPAN_WARNING("There's something built here already.")) - return - var/obj/cost_warn = new /obj/effect/resin_construct/cost_node(target_turf, src, xeno) - if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) - qdel(cost_warn) - return - qdel(cost_warn) - if(!is_turf_clean(target_turf)) - to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) - return - if(!check_and_use_plasma_owner(plasma_cost)) - return - xeno.visible_message(SPAN_XENONOTICE("The [xeno] channels nutrients and shapes it into a node!")) - var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) - if(!design) - to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) - return - playsound(xeno.loc, "alien_resin_build", 25) - xeno.current_design.Add(design) + 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_plasma_cost = ceil(total_plasma_cost * (density_ratio + 0.35) * 2) + if(total_plasma_cost > xeno.plasma_max && (XENO_RESIN_BASE_COST + plasma_donation) < xeno.plasma_max) + total_plasma_cost = xeno.plasma_max - if(ispath(xeno.selected_design, /obj/effect/alien/resin/design/construct_node)) - if(!is_turf_clean(target_turf, check_resin_doors = TRUE)) - to_chat(src, SPAN_WARNING("There's something built here already.")) - return - if(!xeno.check_alien_construction(target_turf, check_doors = FALSE)) - return FALSE - var/obj/const_warn = new /obj/effect/resin_construct/construct_node(target_turf, src, xeno) - if(!do_after(xeno, 0.5 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD) || selected_design != xeno.selected_design) - qdel(const_warn) - return - qdel(const_warn) - if(!is_turf_clean(target_turf)) - to_chat(xeno, SPAN_XENOWARNING("Something else has taken root here before us.")) - return - if(!check_and_use_plasma_owner(plasma_cost)) - return - xeno.visible_message(SPAN_XENONOTICE("The [xeno] channels nutrients and shapes it into a node!")) - var/obj/effect/alien/resin/design/design = new xeno.selected_design(target_weeds.loc, target_weeds, xeno) - if(!design) - to_chat(xeno, SPAN_XENOHIGHDANGER("Couldn't find node to place! Contact a coder!")) - return - playsound(xeno.loc, "alien_resin_build", 25) - xeno.current_design.Add(design) - apply_cooldown() - return ..() + return total_plasma_cost -/datum/action/xeno_action/activable/place_design/proc/can_remote_build() - if(!locate(/obj/effect/alien/weeds) in get_turf(owner)) +/obj/effect/alien/resin/design/construct_node/proc/can_begin_construction(mob/living/carbon/xenomorph/xeno) + if(building) + to_chat(xeno, SPAN_WARNING("This node is already being infused with plasma.")) return FALSE - return TRUE -/mob/living/carbon/xenomorph/proc/try_toggle_resin_door(atom/target_atom) - if(!istype(target_atom, /obj/structure/mineral_door/resin)) + if(xeno.hivenumber != src.hivenumber) + to_chat(xeno, SPAN_WARNING("This construct node does not belong to your hive.")) return FALSE - var/obj/structure/mineral_door/resin/resin_door = target_atom - - if(resin_door.hivenumber != hivenumber) - to_chat(src, SPAN_XENOWARNING("This door does not belong to our hive!")) - return TRUE + if(!mark_meaning) + to_chat(xeno, SPAN_WARNING("This node has no valid design selected.")) + return FALSE - if(resin_door.TryToSwitchState(src)) - if(resin_door.open) - to_chat(src, SPAN_XENONOTICE("We focus our connection to the resin and remotely close the resin door.")) - else - to_chat(src, SPAN_XENONOTICE("We focus our connection to the resin and remotely open the resin door.")) + var/turf/Turf = get_turf(src) + if(!istype(Turf)) + to_chat(xeno, SPAN_WARNING("This is not a valid location.")) + return FALSE return TRUE -/datum/action/xeno_action/activable/place_design/proc/is_turf_clean(turf/current_turf, check_resin_additions = FALSE, check_doors = FALSE, check_resin_doors = FALSE) - var/has_obstacle = FALSE - for(var/obj/target in current_turf) - if(check_doors) - if(istype(target, /obj/structure/machinery/door)) - to_chat(src, SPAN_WARNING("[target] is blocking the resin! There's not enough space to build that here.")) - return FALSE - if(check_resin_additions) - if(istype(target, /obj/effect/alien/resin/sticky) || istype(target, /obj/effect/alien/resin/spike) || istype(target, /obj/effect/alien/resin/sticky/fast)) - has_obstacle = TRUE - to_chat(src, SPAN_WARNING("[target] is blocking the resin!")) - return FALSE - if(check_resin_doors) - if(istype(target, /obj/structure/mineral_door/resin)) - to_chat(src, SPAN_WARNING("[target] is blocking the resin node! There's not enough space to build that here.")) - return FALSE - if(current_turf.density || has_obstacle || locate(/obj/effect/alien/resin/design) in current_turf) - return FALSE - return TRUE +/obj/effect/alien/resin/design/construct_node/proc/begin_construction(mob/living/carbon/xenomorph/xeno) + if(!can_begin_construction(xeno)) + return -/////////////////////////////// -/// Change Node Marker /// -/////////////////////////////// + var/turf/Turf = get_turf(src) + building = TRUE -/datum/action/xeno_action/verb/verb_toggle_design_icons() - set category = "Alien" - set name = "Change Design Mark" - set hidden = TRUE - var/action_name = "Change Design Mark" - handle_xeno_macro(src, action_name) + var/obj/effect/resin_construct/overlay -/datum/action/xeno_action/onclick/toggle_design_icons - name = "Change Design Mark" - action_icon_state = "design_mark_1" - plasma_cost = 0 - macro_path = /datum/action/xeno_action/verb/verb_toggle_design_icons - action_type = XENO_ACTION_CLICK - ability_primacy = XENO_PRIMARY_ACTION_4 + if(istype(mark_meaning, /datum/design_mark/resin_wall)) + overlay = new /obj/effect/resin_construct/construct_wallslow(Turf) + else if(istype(mark_meaning, /datum/design_mark/resin_door)) + overlay = new /obj/effect/resin_construct/construct_doorslow(Turf) -/datum/action/xeno_action/onclick/toggle_design_icons/can_use_action() - var/mob/living/carbon/xenomorph/xeno = owner - if(xeno && !xeno.buckled && !xeno.is_mob_incapacitated()) - return TRUE + build_overlay = overlay -/datum/action/xeno_action/onclick/toggle_design_icons/use_ability() - var/mob/living/carbon/xenomorph/xeno = owner + if(bound_weed.weed_strength >= WEED_LEVEL_HIVE) + thick_build = TRUE - if (!istype(xeno)) + if((xeno.caste_type in XENO_CONSTRUCT_NODE_BOOST) && !istype(xeno.strain, /datum/xeno_strain/designer)) + thick_build = TRUE + + addtimer(CALLBACK(src, PROC_REF(complete_construction), Turf, mark_meaning, xeno), 4 SECONDS) + +/obj/effect/alien/resin/design/construct_node/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this node looks like big blub composed of smaller purple glowing cups, pumping some strange liquid trough weeds.") + if(isxeno(user) || isobserver(user)) + var/mob/living/carbon/xenomorph/xeno = user + var/total_plasma_cost = get_total_plasma_cost(xeno) + . += SPAN_NOTICE("You sense that feeding [SPAN_BOLDNOTICE("[total_plasma_cost]")] plasma with our hand to this node will secrete a [SPAN_BOLDNOTICE("[mark_meaning]")], you also heard that using plasma fruit works too.") + +//Should not be upgradable because it's not "stable" but special actions should create thick variant +/turf/closed/wall/resin/weedbound //NEVER use this variant, use subtypes + name = "weedbound resin wall" + desc = "An oddly solidified resin wall with a layered pattern that reminds you of flower buds." + icon_state = "weedboundresin" + walltype = WALL_WEEDBOUND_RESIN + + var/obj/effect/alien/weeds/bound_weed + var/old_hivenumber + +/turf/closed/wall/resin/weedbound/Initialize() + . = ..() + bound_weed = locate(/obj/effect/alien/weeds) in get_turf(src) + if(!bound_weed) + addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 3 SECONDS) return + if(bound_weed) + old_hivenumber = bound_weed.hivenumber + RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - if(!xeno.check_state(TRUE)) +/turf/closed/wall/resin/weedbound/Destroy() + if(bound_weed) + UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) + bound_weed = null + + var/turf/Turf = get_turf(src) + if(Turf) + visible_message(SPAN_ALERT("The weedbound wall collapses into a puddle of sticky slime.")) + spawn_nutriplasm(Turf) + + return ..() + +/turf/closed/wall/resin/weedbound/proc/spawn_nutriplasm(turf/Turf) + return + +/turf/closed/wall/resin/weedbound/proc/on_weed_expire() + SIGNAL_HANDLER + + if(!old_hivenumber) + ScrapeAway() return - var/datum/action/xeno_action/activable/place_design/cAction = get_action(xeno, /datum/action/xeno_action/activable/place_design) + addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 1 DECISECONDS) - if(!istype(cAction)) +/turf/closed/wall/resin/weedbound/proc/check_weed_replacement() + var/turf/Turf = get_turf(src) + if(!Turf) + ScrapeAway() return - cAction.design_toggle = !cAction.design_toggle + var/obj/effect/alien/weeds/new_weed = locate(/obj/effect/alien/weeds) in Turf - var/action_icon_result - if(cAction.design_toggle) - action_icon_result = "design_mark_1" - to_chat(xeno, SPAN_INFO("We will now place wall markers.")) - xeno.selected_design_mark = /datum/design_mark/resin_wall + if(new_weed && new_weed.hivenumber == old_hivenumber) + bound_weed = new_weed + RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) else - action_icon_result = "design_mark_2" - to_chat(xeno, SPAN_INFO("We will now place door markers.")) - xeno.selected_design_mark = /datum/design_mark/resin_door + playsound(src, "alien_resin_break", 25) + ScrapeAway() - button.overlays.Cut() - button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, action_icon_result) - return ..() +/turf/closed/wall/resin/weedbound/normal/spawn_nutriplasm(turf/Turf) + new /obj/effect/alien/resin/sticky/weak_nutriplasm(Turf) -////////////////////////// -/// Change Design /// -////////////////////////// +/turf/closed/wall/resin/weedbound/normal/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this strange wall appears to have merged with the resin below to hold itself together.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that this resin wall will collapse if the weeds it is merged with disappear.") -/datum/action/xeno_action/verb/verb_change_design() - set category = "Alien" - set name = "Change Design Mark" - set hidden = TRUE - var/action_name = "Change Design Mark" - handle_xeno_macro(src, action_name) +/turf/closed/wall/resin/weedbound/thick + name = "thick weedbound resin wall" + desc = "An oddly solidified thick resin wall with a layered pattern that reminds you of flower buds." + icon_state = "thickweedboundresin" + damage_cap = HEALTH_WALL_XENO_THICK + walltype = WALL_THICK_WEEDBOUND_RESIN -/datum/action/xeno_action/onclick/change_design - name = "Choose Action" - action_icon_state = "static_speednode" - plasma_cost = 0 - xeno_cooldown = 0 - macro_path = /datum/action/xeno_action/verb/verb_change_design - action_type = XENO_ACTION_CLICK - ability_primacy = XENO_PRIMARY_ACTION_2 +/turf/closed/wall/resin/weedbound/thick/spawn_nutriplasm(turf/Turf) + new /obj/effect/alien/resin/sticky/strong_nutriplasm(Turf) -/datum/action/xeno_action/onclick/change_design/use_ability(atom/Atom) - var/mob/living/carbon/xenomorph/xeno = owner - if(!xeno.check_state()) - return +/turf/closed/wall/resin/weedbound/thick/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this strange darker wall appears to have merged with the resin below to hold itself together.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that this thick resin wall will collapse if the weeds it is merged with disappear.") - var/static/list/options = list( - "Optimized Node (50)" = icon(/datum/action/xeno_action::icon_file, "static_speednode"), - "Construct Node (70)" = icon(/datum/action/xeno_action::icon_file, "static_constructnode"), - "Thicken Resin (60)" = icon(/datum/action/xeno_action::icon_file, "upgrade_resin"), - "Open Old UI" = icon(/datum/action/xeno_action::icon_file, "open_ui"), - "Remove Node (25)" = icon(/datum/action/xeno_action::icon_file, "remove_node"), - "Flexible Node (60)" = icon(/datum/action/xeno_action::icon_file, "static_costnode") - ) +/obj/structure/mineral_door/resin/weedbound //NEVER use this variant, use subtypes + name = "weedbound resin door" + desc = "A weird resin door that solidified strangely, forming a petal-like pattern." + icon_state = "weedbound resin" + mineralType = "weedbound resin" + hardness = 1.4 - var/choice - if(owner.client.prefs.no_radials_preference) - choice = tgui_input_list(owner, "Choose Design Option", "Pick", options, theme="hive_status") - else - choice = show_radial_menu(owner, owner?.client.get_eye(), options, radius = 50) + var/obj/effect/alien/weeds/bound_weed + var/old_hivenumber - var/des = FALSE - var/rem = FALSE - plasma_cost = 0 - switch(choice) - if("Optimized Node (50)") - xeno.selected_design = /obj/effect/alien/resin/design/speed_node - des = TRUE - if("Flexible Node (60)") - xeno.selected_design = /obj/effect/alien/resin/design/cost_node - des = TRUE - if("Construct Node (70)") - xeno.selected_design = /obj/effect/alien/resin/design/construct_node - des = TRUE - if("Thicken Resin (60)") - xeno.selected_design = /obj/effect/alien/resin/design/upgrade - rem = TRUE - if("Remove Node (25)") - xeno.selected_design = /obj/effect/alien/resin/design/remove - rem = TRUE - if("Open Old UI") - tgui_interact(xeno) +/obj/structure/mineral_door/resin/weedbound/Initialize() + . = ..() + bound_weed = locate(/obj/effect/alien/weeds) in get_turf(src) + if(!bound_weed) + addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 3 SECONDS) + return + if(bound_weed) + old_hivenumber = bound_weed.hivenumber + RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) - if(des) - to_chat(xeno, SPAN_NOTICE("We will now build [xeno.selected_design.name].")) - if(rem) - to_chat(xeno, SPAN_NOTICE("We will now remotely [xeno.selected_design.name].")) +/obj/structure/mineral_door/resin/weedbound/Destroy() + if(bound_weed) + UnregisterSignal(bound_weed, COMSIG_PARENT_QDELETING) + bound_weed = null - xeno.update_icons() - button.overlays.Cut() - button.overlays += image(icon_file, button, xeno.selected_design.icon_state) + var/turf/Turf = get_turf(src) + if(Turf) + visible_message(SPAN_ALERT("The weedbound wall collapses into a puddle of sticky slime.")) + spawn_nutriplasm(Turf) return ..() -// Below is UI for old players. +/obj/structure/mineral_door/resin/weedbound/proc/spawn_nutriplasm(turf/Turf) + return -/datum/action/xeno_action/onclick/change_design/give_to(mob/living/carbon/xenomorph/xeno) - . = ..() +/obj/structure/mineral_door/resin/weedbound/proc/on_weed_expire() + SIGNAL_HANDLER - button.overlays.Cut() - button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, initial(xeno.selected_design.icon_state)) - button.overlays += image(icon_file, button, action_icon_state) + if(!old_hivenumber) + Dismantle() + return -/datum/action/xeno_action/onclick/change_design/ui_assets(mob/user) - return list(get_asset_datum(/datum/asset/spritesheet/choose_design)) + addtimer(CALLBACK(src, PROC_REF(check_weed_replacement)), 1 DECISECONDS) -/datum/action/xeno_action/onclick/change_design/ui_static_data(mob/user) - var/mob/living/carbon/xenomorph/xeno = user - if(!istype(xeno)) +/obj/structure/mineral_door/resin/weedbound/proc/check_weed_replacement() + var/turf/Turf = get_turf(src) + if(!Turf) + Dismantle() return - . = list() - - var/list/design_list = list() - for(var/obj/effect/alien/resin/design/design as anything in xeno.available_design) - var/list/entry = list() + var/obj/effect/alien/weeds/new_weed = locate(/obj/effect/alien/weeds) in Turf - entry["name"] = initial(design.name) - entry["desc"] = initial(design.desc) - entry["image"] = replacetext(initial(design.icon_state), " ", "-") - entry["id"] = "[design]" - design_list += list(entry) + if(new_weed && new_weed.hivenumber == old_hivenumber) + bound_weed = new_weed + RegisterSignal(bound_weed, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_expire)) + else + playsound(src, "alien_resin_break", 25) + Dismantle() - .["design"] = design_list +/obj/structure/mineral_door/resin/weedbound/normal/spawn_nutriplasm(turf/Turf) + new /obj/effect/alien/resin/sticky/weak_nutriplasm(Turf) -/datum/action/xeno_action/onclick/change_design/ui_data(mob/user) - var/mob/living/carbon/xenomorph/xeno = user - if(!istype(xeno)) - return +/obj/structure/mineral_door/resin/weedbound/normal/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this strange door appears to have merged with the resin below to hold itself together.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that this resin door will collapse if the weeds it is merged with disappear.") - . = list() - .["selected_design"] = xeno.selected_design +/obj/structure/mineral_door/resin/weedbound/thick + name = "thick weedbound resin door" + desc = "A weird thick resin door that solidified strangely, forming a petal-like pattern." + icon_state = "thick weedbound resin" + mineralType = "thick weedbound resin" + health = HEALTH_DOOR_XENO_THICK + hardness = 1.9 -/datum/action/xeno_action/onclick/change_design/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "ChooseDesign", "Choose Design") - ui.set_autoupdate(FALSE) - ui.open() +/obj/structure/mineral_door/resin/weedbound/thick/spawn_nutriplasm(turf/Turf) + new /obj/effect/alien/resin/sticky/strong_nutriplasm(Turf) -/datum/action/xeno_action/onclick/change_design/Destroy() - SStgui.close_uis(src) - return ..() +/obj/structure/mineral_door/resin/weedbound/thick/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this strange darker door appears to have merged with the resin below to hold itself together.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("You sense that this thick resin door will collapse if the weeds it is merged with disappear.") -/datum/action/xeno_action/onclick/change_design/ui_state(mob/user) - return GLOB.always_state +/obj/effect/alien/resin/sticky/weak_nutriplasm + name = "thin sticky nutriplasm" + desc = "A thin layer of disgusting sticky slime." + icon_state = "weak_nutriplasm" + slow_amt = 5 -/datum/action/xeno_action/onclick/change_design/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) +/obj/effect/alien/resin/sticky/weak_nutriplasm/get_examine_text(mob/user) . = ..() - if(.) - return + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this thin, sticky substance reminds you of sticky resin.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("We stare at the remains of weedbound walls - nutriplasm. As edible as it sounds, it's just another kind of sticky resin.") - var/mob/living/carbon/xenomorph/xeno = ui.user - if(!istype(xeno)) - return +/obj/effect/alien/resin/sticky/strong_nutriplasm + name = "sticky nutriplasm" + desc = "A thick layer of disgusting sticky slime." + icon_state = "strong_nutriplasm" + slow_amt = 10 - switch(action) - if("choose_design") - var/selected_type = text2path(params["type"]) - if(!(selected_type in xeno.available_design)) - return +/obj/effect/alien/resin/sticky/strong_nutriplasm/get_examine_text(mob/user) + . = ..() + if(ishuman(user)) + . += SPAN_NOTICE("On closer examination, this thick, sticky substance reminds you of sticky resin.") + if(isxeno(user) || isobserver(user)) + . += SPAN_NOTICE("We stare at thick nutriplasm, the remains from weedbound resin, it sound delicious but you remember, its just different sticky resin.") - var/obj/effect/alien/resin/design/design = selected_type - to_chat(xeno, SPAN_NOTICE("We will now build [initial(design.name)] when designing.")) - //update the button's overlay with new choice - xeno.update_icons() - button.overlays.Cut() - button.overlays += image(icon_file, button, action_icon_state) - button.overlays += image('icons/mob/hud/actions_xeno.dmi', button, initial(design.icon_state)) - xeno.selected_design = selected_type - . = TRUE +/obj/effect/alien/resin/design/upgrade + name = "Thicken Resin (60)" + desc = "Channel our plasma and nutrients to thicken structures." + icon = 'icons/mob/hud/actions_xeno.dmi' + icon_state = "upgrade_resin" + plasma_cost = 60 - if("refresh_ui") - . = TRUE +/obj/effect/alien/resin/design/remove + name = "Remove Design Node (25)" + desc = "Channel our plasma to revert design node back to weeds." + icon = 'icons/mob/hud/actions_xeno.dmi' + icon_state = "remove_node" + plasma_cost = 25 diff --git a/colonialmarines.dme b/colonialmarines.dme index 06628b4475f4..ce5ceb1c965a 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -2227,6 +2227,7 @@ #include "code\modules\mob\living\carbon\xenomorph\abilities\facehugger\facehugger_powers.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\hellhound\hellhound_abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\hivelord\hivelord_abilities.dm" +#include "code\modules\mob\living\carbon\xenomorph\abilities\hivelord\hivelord_macros.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\king\king_abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\king\king_macros.dm" #include "code\modules\mob\living\carbon\xenomorph\abilities\lesser_drone\lesser_drone_abilities.dm"