From ed4ffde5f4fa2049111baceccfa153148478ffe8 Mon Sep 17 00:00:00 2001 From: IndieanaJones <47086570+IndieanaJones@users.noreply.github.com> Date: Sun, 21 Aug 2022 19:08:09 -0700 Subject: [PATCH] Space Dragon Antag Datum Refactor Take 2 (#68988) * Space Dragon Antag Datum Refactor Take 2 Space Dragon's antag datum and the mob has been separated, so it is now possible to have non-dragon space dragons, with customizable spawned mobs and factions. --- code/game/objects/items/dna_probe.dm | 3 +- .../antagonists/space_dragon/carp_rift.dm | 239 ++++++++++++ .../antagonists/space_dragon/space_dragon.dm | 128 ++++++- .../simple_animal/hostile/space_dragon.dm | 340 ------------------ tgstation.dme | 1 + 5 files changed, 368 insertions(+), 343 deletions(-) create mode 100644 code/modules/antagonists/space_dragon/carp_rift.dm diff --git a/code/game/objects/items/dna_probe.dm b/code/game/objects/items/dna_probe.dm index 64bf1f8a191..8a2f61b6aa7 100644 --- a/code/game/objects/items/dna_probe.dm +++ b/code/game/objects/items/dna_probe.dm @@ -97,7 +97,8 @@ if(!do_after(user, CARP_MIX_DNA_TIMER)) return var/mob/living/simple_animal/hostile/space_dragon/new_dragon = user.change_mob_type(/mob/living/simple_animal/hostile/space_dragon, location = loc, delete_old_mob = TRUE) - new_dragon.permanant_empower() + new_dragon.add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 5)) + new_dragon.add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) priority_announce("A large organic energy flux has been recorded near of [station_name()], please stand-by.", "Lifesign Alert") qdel(src) diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm new file mode 100644 index 00000000000..85ed8eeb751 --- /dev/null +++ b/code/modules/antagonists/space_dragon/carp_rift.dm @@ -0,0 +1,239 @@ +/// The carp rift is currently charging. +#define CHARGE_ONGOING 0 +/// The carp rift is currently charging and has output a final warning. +#define CHARGE_FINALWARNING 1 +/// The carp rift is now fully charged. +#define CHARGE_COMPLETED 2 + +/datum/action/innate/summon_rift + name = "Summon Rift" + desc = "Summon a rift to bring forth a horde of space carp." + background_icon_state = "bg_default" + icon_icon = 'icons/mob/actions/actions_space_dragon.dmi' + button_icon_state = "carp_rift" + +/datum/action/innate/summon_rift/Activate() + var/datum/antagonist/space_dragon/dragon = owner.mind?.has_antag_datum(/datum/antagonist/space_dragon) + if(!dragon) + return + var/area/rift_location = get_area(owner) + if(!(rift_location.area_flags & VALID_TERRITORY)) + to_chat(owner, span_warning("You can't summon a rift here! Try summoning somewhere secure within the station!")) + return + for(var/obj/structure/carp_rift/rift as anything in dragon.rift_list) + var/area/used_location = get_area(rift) + if(used_location == rift_location) + to_chat(owner, span_warning("You've already summoned a rift in this area! You have to summon again somewhere else!")) + return + owner.balloon_alert(owner, "You begin to open a rift...") + if(!do_after(owner, 10 SECONDS, target = owner)) + return + if(locate(/obj/structure/carp_rift) in owner.loc) + return + var/obj/structure/carp_rift/new_rift = new(get_turf(owner)) + playsound(owner.loc, 'sound/vehicles/rocketlaunch.ogg', 100, TRUE) + dragon.riftTimer = -1 + new_rift.dragon = dragon + dragon.rift_list += new_rift + to_chat(owner, span_boldwarning("The rift has been summoned. Prevent the crew from destroying it at all costs!")) + notify_ghosts("The Space Dragon has opened a rift!", source = new_rift, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Rift Opened") + qdel(src) + +/** + * # Carp Rift + * + * The portals Space Dragon summons to bring carp onto the station. + * + * The portals Space Dragon summons to bring carp onto the station. His main objective is to summon 3 of them and protect them from being destroyed. + * The portals can summon sentient space carp in limited amounts. The portal also changes color based on whether or not a carp spawn is available. + * Once it is fully charged, it becomes indestructible, and intermitently spawns non-sentient carp. It is still destroyed if Space Dragon dies. + */ +/obj/structure/carp_rift + name = "carp rift" + desc = "A rift akin to the ones space carp use to travel long distances." + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) + max_integrity = 300 + icon = 'icons/obj/carp_rift.dmi' + icon_state = "carp_rift_carpspawn" + light_color = LIGHT_COLOR_PURPLE + light_range = 10 + anchored = TRUE + density = FALSE + plane = MASSIVE_OBJ_PLANE + /// The amount of time the rift has charged for. + var/time_charged = 0 + /// The maximum charge the rift can have. + var/max_charge = 300 + /// How many carp spawns it has available. + var/carp_stored = 1 + /// A reference to the Space Dragon antag that created it. + var/datum/antagonist/space_dragon/dragon + /// Current charge state of the rift. + var/charge_state = CHARGE_ONGOING + /// The interval for adding additional space carp spawns to the rift. + var/carp_interval = 60 + /// The time since an extra carp was added to the ghost role spawning pool. + var/last_carp_inc = 0 + /// A list of all the ckeys which have used this carp rift to spawn in as carps. + var/list/ckey_list = list() + +/obj/structure/carp_rift/Initialize(mapload) + . = ..() + + AddComponent( \ + /datum/component/aura_healing, \ + range = 0, \ + simple_heal = 5, \ + limit_to_trait = TRAIT_HEALS_FROM_CARP_RIFTS, \ + healing_color = COLOR_BLUE, \ + ) + + START_PROCESSING(SSobj, src) + +// Carp rifts always take heavy explosion damage. Discourages the use of maxcaps +// and favours more weaker explosives to destroy the portal +// as they have the same effect on the portal. +/obj/structure/carp_rift/ex_act(severity, target) + return ..(min(EXPLODE_HEAVY, severity)) + +/obj/structure/carp_rift/examine(mob/user) + . = ..() + if(time_charged < max_charge) + . += span_notice("It seems to be [(time_charged / max_charge) * 100]% charged.") + else + . += span_warning("This one is fully charged. In this state, it is poised to transport a much larger amount of carp than normal.") + + if(isobserver(user)) + . += span_notice("It has [carp_stored] carp available to spawn as.") + +/obj/structure/carp_rift/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + playsound(src, 'sound/magic/lightningshock.ogg', 50, TRUE) + +/obj/structure/carp_rift/Destroy() + STOP_PROCESSING(SSobj, src) + if(charge_state != CHARGE_COMPLETED) + if(dragon) + to_chat(dragon.owner.current, span_boldwarning("A rift has been destroyed! You have failed, and find yourself weakened.")) + dragon.destroy_rifts() + dragon = null + return ..() + +/obj/structure/carp_rift/process(delta_time) + // If we're fully charged, just start mass spawning carp and move around. + if(charge_state == CHARGE_COMPLETED) + if(DT_PROB(1.25, delta_time) && dragon) + var/mob/living/newcarp = new dragon.ai_to_spawn(loc) + newcarp.faction = dragon.owner.current.faction.Copy() + if(DT_PROB(1.5, delta_time)) + var/rand_dir = pick(GLOB.cardinals) + SSmove_manager.move_to(src, get_step(src, rand_dir), 1) + return + + // Increase time trackers and check for any updated states. + time_charged = min(time_charged + delta_time, max_charge) + last_carp_inc += delta_time + update_check() + +/obj/structure/carp_rift/attack_ghost(mob/user) + . = ..() + if(.) + return + summon_carp(user) + +/** + * Does a series of checks based on the portal's status. + * + * Performs a number of checks based on the current charge of the portal, and triggers various effects accordingly. + * If the current charge is a multiple of carp_interval, add an extra carp spawn. + * If we're halfway charged, announce to the crew our location in a CENTCOM announcement. + * If we're fully charged, tell the crew we are, change our color to yellow, become invulnerable, and give Space Dragon the ability to make another rift, if he hasn't summoned 3 total. + */ +/obj/structure/carp_rift/proc/update_check() + // If the rift is fully charged, there's nothing to do here anymore. + if(charge_state == CHARGE_COMPLETED) + return + + // Can we increase the carp spawn pool size? + if(last_carp_inc >= carp_interval) + carp_stored++ + icon_state = "carp_rift_carpspawn" + if(light_color != LIGHT_COLOR_PURPLE) + set_light_color(LIGHT_COLOR_PURPLE) + update_light() + notify_ghosts("The carp rift can summon an additional carp!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Spawn Available") + last_carp_inc -= carp_interval + + // Is the rift now fully charged? + if(time_charged >= max_charge) + charge_state = CHARGE_COMPLETED + var/area/A = get_area(src) + priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "Central Command Wildlife Observations") + atom_integrity = INFINITY + icon_state = "carp_rift_charged" + set_light_color(LIGHT_COLOR_YELLOW) + update_light() + armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100) + resistance_flags = INDESTRUCTIBLE + dragon.rifts_charged += 1 + if(dragon.rifts_charged != 3 && !dragon.objective_complete) + var/datum/action/innate/summon_rift/rift = new() + rift.Grant(dragon.owner.current) + dragon.riftTimer = 0 + dragon.rift_empower() + // Early return, nothing to do after this point. + return + + // Do we need to give a final warning to the station at the halfway mark? + if(charge_state < CHARGE_FINALWARNING && time_charged >= (max_charge * 0.5)) + charge_state = CHARGE_FINALWARNING + var/area/A = get_area(src) + priority_announce("A rift is causing an unnaturally large energy flux in [initial(A.name)]. Stop it at all costs!", "Central Command Wildlife Observations", ANNOUNCER_SPANOMALIES) + +/** + * Used to create carp controlled by ghosts when the option is available. + * + * Creates a carp for the ghost to control if we have a carp spawn available. + * Gives them prompt to control a carp, and if our circumstances still allow if when they hit yes, spawn them in as a carp. + * Also add them to the list of carps in Space Dragon's antgonist datum, so they'll be displayed as having assisted him on round end. + * Arguments: + * * mob/user - The ghost which will take control of the carp. + */ +/obj/structure/carp_rift/proc/summon_carp(mob/user) + if(carp_stored <= 0)//Not enough carp points + return FALSE + var/is_listed = FALSE + if (user.ckey in ckey_list) + if(carp_stored == 1) + to_chat(user, span_warning("You've already become a carp using this rift! Either wait for a backlog of carp spawns or until the next rift!")) + return FALSE + is_listed = TRUE + var/carp_ask = tgui_alert(user, "Become a carp?", "Carp Rift", list("Yes", "No")) + if(carp_ask != "Yes" || QDELETED(src) || QDELETED(user)) + return FALSE + if(carp_stored <= 0) + to_chat(user, span_warning("The rift already summoned enough carp!")) + return FALSE + + if(!dragon) + return + var/mob/living/newcarp = new dragon.minion_to_spawn(loc) + newcarp.faction = dragon.owner.current.faction + newcarp.AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) + newcarp.AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") + + if(!is_listed) + ckey_list += user.ckey + newcarp.key = user.key + newcarp.set_name() + dragon.carp += newcarp.mind + to_chat(newcarp, span_boldwarning("You have arrived in order to assist the space dragon with securing the rifts. Do not jeopardize the mission, and protect the rifts at all costs!")) + carp_stored-- + if(carp_stored <= 0 && charge_state < CHARGE_COMPLETED) + icon_state = "carp_rift" + set_light_color(LIGHT_COLOR_BLUE) + update_light() + return TRUE + +#undef CHARGE_ONGOING +#undef CHARGE_FINALWARNING +#undef CHARGE_COMPLETED diff --git a/code/modules/antagonists/space_dragon/space_dragon.dm b/code/modules/antagonists/space_dragon/space_dragon.dm index 41b39425526..5c570298f95 100644 --- a/code/modules/antagonists/space_dragon/space_dragon.dm +++ b/code/modules/antagonists/space_dragon/space_dragon.dm @@ -10,6 +10,20 @@ var/list/datum/mind/carp = list() /// The innate ability to summon rifts var/datum/action/innate/summon_rift/rift_ability + /// Current time since the the last rift was activated. If set to -1, does not increment. + var/riftTimer = 0 + /// Maximum amount of time which can pass without a rift before Space Dragon despawns. + var/maxRiftTimer = 300 + /// A list of all of the rifts created by Space Dragon. Used for setting them all to infinite carp spawn when Space Dragon wins, and removing them when Space Dragon dies. + var/list/obj/structure/carp_rift/rift_list = list() + /// How many rifts have been successfully charged + var/rifts_charged = 0 + /// Whether or not Space Dragon has completed their objective, and thus triggered the ending sequence. + var/objective_complete = FALSE + /// What mob to spawn from ghosts using this dragon's rifts + var/minion_to_spawn = /mob/living/simple_animal/hostile/carp + /// What AI mobs to spawn from this dragon's rifts + var/ai_to_spawn = /mob/living/simple_animal/hostile/carp /datum/antagonist/space_dragon/greet() . = ..() @@ -31,10 +45,21 @@ . = ..() rift_ability = new rift_ability.Grant(owner.current) + owner.current.faction |= "carp" + RegisterSignal(owner.current, COMSIG_LIVING_LIFE, .proc/rift_checks) + RegisterSignal(owner.current, COMSIG_LIVING_DEATH, .proc/destroy_rifts) /datum/antagonist/space_dragon/on_removal() . = ..() rift_ability.Remove(owner.current) + owner.current.faction -= "carp" + UnregisterSignal(owner.current, COMSIG_LIVING_LIFE) + UnregisterSignal(owner.current, COMSIG_LIVING_DEATH) + rift_list = null + +/datum/antagonist/space_dragon/Destroy() + rift_list = null + return ..() /datum/antagonist/space_dragon/get_preview_icon() var/icon/icon = icon('icons/mob/spacedragon.dmi', "spacedragon") @@ -47,6 +72,104 @@ return icon +/** + * Checks to see if we need to do anything with the current state of the dragon's rifts. + * + * A simple update check which sees if we need to do anything based on the current state of the dragon's rifts. + * + */ +/datum/antagonist/space_dragon/proc/rift_checks() + if((rifts_charged == 3 || (SSshuttle.emergency.mode == SHUTTLE_DOCKED && rifts_charged > 0)) && !objective_complete) + victory() + return + if(riftTimer == -1) + return + riftTimer = min(riftTimer + 1, maxRiftTimer + 1) + if(riftTimer == (maxRiftTimer - 60)) + to_chat(owner.current, span_boldwarning("You have a minute left to summon the rift! Get to it!")) + return + if(riftTimer >= maxRiftTimer) + to_chat(owner.current, span_boldwarning("You've failed to summon the rift in a timely manner! You're being pulled back from whence you came!")) + destroy_rifts() + SEND_SOUND(owner.current, sound('sound/magic/demon_dies.ogg')) + QDEL_NULL(owner.current) + +/** + * Destroys all of Space Dragon's current rifts. + * + * QDeletes all the current rifts after removing their references to other objects. + * Currently, the only reference they have is to the Dragon which created them, so we clear that before deleting them. + * Currently used when Space Dragon dies or one of his rifts is destroyed. + */ +/datum/antagonist/space_dragon/proc/destroy_rifts() + if(objective_complete) + return + rifts_charged = 0 + owner.current.add_movespeed_modifier(/datum/movespeed_modifier/dragon_depression) + riftTimer = -1 + SEND_SOUND(owner.current, sound('sound/vehicles/rocketlaunch.ogg')) + for(var/obj/structure/carp_rift/rift as anything in rift_list) + rift.dragon = null + rift_list -= rift + if(!QDELETED(rift)) + QDEL_NULL(rift) + +/** + * Sets up Space Dragon's victory for completing the objectives. + * + * Triggers when Space Dragon completes his objective. + * Calls the shuttle with a coefficient of 3, making it impossible to recall. + * Sets all of his rifts to allow for infinite sentient carp spawns + * Also plays appropiate sounds and CENTCOM messages. + */ +/datum/antagonist/space_dragon/proc/victory() + objective_complete = TRUE + permanant_empower() + var/datum/objective/summon_carp/main_objective = locate() in objectives + if(main_objective) + main_objective.completed = TRUE + priority_announce("A large amount of lifeforms have been detected approaching [station_name()] at extreme speeds. \ + Remaining crew are advised to evacuate as soon as possible.", "Central Command Wildlife Observations") + sound_to_playing_players('sound/creatures/space_dragon_roar.ogg') + for(var/obj/structure/carp_rift/rift as anything in rift_list) + rift.carp_stored = 999999 + rift.time_charged = rift.max_charge + +/** + * Gives Space Dragon their the rift speed buff permanantly and fully heals the user. + * + * Gives Space Dragon the enraged speed buff from charging rifts permanantly. + * Only happens in circumstances where Space Dragon completes their objective. + * Also gives them a full heal. + */ +/datum/antagonist/space_dragon/proc/permanant_empower() + owner.current.fully_heal() + owner.current.add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 5)) + owner.current.add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) + +/** + * Handles Space Dragon's temporary empowerment after boosting a rift. + * + * Empowers and depowers Space Dragon after a successful rift charge. + * Empowered, Space Dragon regains all his health and becomes temporarily faster for 30 seconds, along with being tinted red. + */ +/datum/antagonist/space_dragon/proc/rift_empower() + owner.current.fully_heal() + owner.current.add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 5)) + owner.current.add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) + addtimer(CALLBACK(src, .proc/rift_depower), 30 SECONDS) + +/** + * Removes Space Dragon's rift speed buff. + * + * Removes Space Dragon's speed buff from charging a rift. This is only called + * in rift_empower, which uses a timer to call this after 30 seconds. Also + * removes the red glow from Space Dragon which is synonymous with the speed buff. + */ +/datum/antagonist/space_dragon/proc/rift_depower() + owner.current.remove_filter("anger_glow") + owner.current.remove_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) + /datum/objective/summon_carp var/datum/antagonist/space_dragon/dragon explanation_text = "Summon and protect the rifts to flood the station with carp." @@ -68,6 +191,7 @@ parts += "The [name] was successful!" else parts += "The [name] has failed!" - parts += "The [name] was assisted by:" - parts += printplayerlist(carp) + if(carp.len) + parts += "The [name] was assisted by:" + parts += printplayerlist(carp) return "
[parts.Join("
")]
" diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm index 8ae81f16658..cefc59bd283 100644 --- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm +++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm @@ -1,9 +1,3 @@ -/// The carp rift is currently charging. -#define CHARGE_ONGOING 0 -/// The carp rift is currently charging and has output a final warning. -#define CHARGE_FINALWARNING 1 -/// The carp rift is now fully charged. -#define CHARGE_COMPLETED 2 /// The darkness threshold for space dragon when choosing a color #define DARKNESS_THRESHOLD 50 @@ -67,10 +61,6 @@ maxbodytemp = 1500 faction = list("carp") pressure_resistance = 200 - /// Current time since the the last rift was activated. If set to -1, does not increment. - var/riftTimer = 0 - /// Maximum amount of time which can pass without a rift before Space Dragon despawns. - var/maxRiftTimer = 300 /// How much endlag using Wing Gust should apply. Each use of wing gust increments this, and it decreases over time. var/tiredness = 0 /// A multiplier to how much each use of wing gust should add to the tiredness variable. Set to 5 if the current rift is destroyed. @@ -83,12 +73,6 @@ var/using_special = FALSE /// Determines whether or not Space Dragon is currently tearing through a wall. var/tearing_wall = FALSE - /// A list of all of the rifts created by Space Dragon. Used for setting them all to infinite carp spawn when Space Dragon wins, and removing them when Space Dragon dies. - var/list/obj/structure/carp_rift/rift_list = list() - /// How many rifts have been successfully charged - var/rifts_charged = 0 - /// Whether or not Space Dragon has completed their objective, and thus triggered the ending sequence. - var/objective_complete = FALSE /// The ability to make your sprite smaller var/datum/action/small_sprite/space_dragon/small_sprite /// The color of the space dragon. @@ -130,21 +114,6 @@ visible_message(span_danger("[src] vomits up [consumed_mob]!")) consumed_mob.forceMove(loc) consumed_mob.Paralyze(50) - if(!mind.has_antag_datum(/datum/antagonist/space_dragon)) - return - if((rifts_charged == 3 || (SSshuttle.emergency.mode == SHUTTLE_DOCKED && rifts_charged > 0)) && !objective_complete) - victory() - if(riftTimer == -1) - return - riftTimer = min(riftTimer + 1, maxRiftTimer + 1) - if(riftTimer == (maxRiftTimer - 60)) - to_chat(src, span_boldwarning("You have a minute left to summon the rift! Get to it!")) - return - if(riftTimer >= maxRiftTimer) - to_chat(src, span_boldwarning("You've failed to summon the rift in a timely manner! You're being pulled back from whence you came!")) - death(TRUE) - playsound(src, 'sound/magic/demon_dies.ogg', 100, TRUE) - qdel(src) /mob/living/simple_animal/hostile/space_dragon/AttackingTarget() if(using_special) @@ -202,8 +171,6 @@ /mob/living/simple_animal/hostile/space_dragon/death(gibbed) empty_contents() - if(!objective_complete) - destroy_rifts() ..() add_dragon_overlay() UnregisterSignal(small_sprite, COMSIG_ACTION_TRIGGER) @@ -392,59 +359,6 @@ using_special = FALSE add_dragon_overlay() -/** - * Handles Space Dragon's temporary empowerment after boosting a rift. - * - * Empowers and depowers Space Dragon after a successful rift charge. - * Empowered, Space Dragon regains all his health and becomes temporarily faster for 30 seconds, along with being tinted red. - */ -/mob/living/simple_animal/hostile/space_dragon/proc/rift_empower() - fully_heal() - add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 5)) - add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) - addtimer(CALLBACK(src, .proc/rift_depower), 30 SECONDS) - -/** - * Gives Space Dragon their the rift speed buff permanantly. - * - * Gives Space Dragon the enraged speed buff from charging rifts permanantly. - * Only happens in circumstances where Space Dragon completes their objective. - */ -/mob/living/simple_animal/hostile/space_dragon/proc/permanant_empower() - fully_heal() - add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 5)) - add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) - -/** - * Removes Space Dragon's rift speed buff. - * - * Removes Space Dragon's speed buff from charging a rift. This is only called - * in rift_empower, which uses a timer to call this after 30 seconds. Also - * removes the red glow from Space Dragon which is synonymous with the speed buff. - */ -/mob/living/simple_animal/hostile/space_dragon/proc/rift_depower() - remove_filter("anger_glow") - remove_movespeed_modifier(/datum/movespeed_modifier/dragon_rage) - -/** - * Destroys all of Space Dragon's current rifts. - * - * QDeletes all the current rifts after removing their references to other objects. - * Currently, the only reference they have is to the Dragon which created them, so we clear that before deleting them. - * Currently used when Space Dragon dies or one of his rifts is destroyed. - */ -/mob/living/simple_animal/hostile/space_dragon/proc/destroy_rifts() - rifts_charged = 0 - add_movespeed_modifier(/datum/movespeed_modifier/dragon_depression) - riftTimer = -1 - tiredness_mult = 5 - playsound(src, 'sound/vehicles/rocketlaunch.ogg', 100, TRUE) - for(var/obj/structure/carp_rift/rift in rift_list) - rift.dragon = null - rift_list -= rift - if(!QDELETED(rift)) - QDEL_NULL(rift) - /** * Handles wing gust from the windup all the way to the endlag at the end. * @@ -483,258 +397,4 @@ addtimer(CALLBACK(src, .proc/reset_status), 4 + ((tiredness * tiredness_mult) / 10)) tiredness = tiredness + (gust_tiredness * tiredness_mult) -/** - * Sets up Space Dragon's victory for completing the objectives. - * - * Triggers when Space Dragon completes his objective. - * Calls the shuttle with a coefficient of 3, making it impossible to recall. - * Sets all of his rifts to allow for infinite sentient carp spawns - * Also plays appropiate sounds and CENTCOM messages. - */ -/mob/living/simple_animal/hostile/space_dragon/proc/victory() - objective_complete = TRUE - permanant_empower() - var/datum/antagonist/space_dragon/S = mind.has_antag_datum(/datum/antagonist/space_dragon) - if(S) - var/datum/objective/summon_carp/main_objective = locate() in S.objectives - if(main_objective) - main_objective.completed = TRUE - priority_announce("A large amount of lifeforms have been detected approaching [station_name()] at extreme speeds. \ - Remaining crew are advised to evacuate as soon as possible.", "Central Command Wildlife Observations") - sound_to_playing_players('sound/creatures/space_dragon_roar.ogg') - for(var/obj/structure/carp_rift/rift in rift_list) - rift.carp_stored = 999999 - rift.time_charged = rift.max_charge - -/datum/action/innate/summon_rift - name = "Summon Rift" - desc = "Summon a rift to bring forth a horde of space carp." - background_icon_state = "bg_default" - icon_icon = 'icons/mob/actions/actions_space_dragon.dmi' - button_icon_state = "carp_rift" - -/datum/action/innate/summon_rift/Activate() - var/mob/living/simple_animal/hostile/space_dragon/S = owner - if(S.using_special) - return - if(S.riftTimer == -1) - to_chat(S, span_warning("Your death has left you unable to summon rifts!")) - return - var/area/A = get_area(S) - if(!(A.area_flags & VALID_TERRITORY)) - to_chat(S, span_warning("You can't summon a rift here! Try summoning somewhere secure within the station!")) - return - for(var/obj/structure/carp_rift/rift in S.rift_list) - var/area/RA = get_area(rift) - if(RA == A) - to_chat(S, span_warning("You've already summoned a rift in this area! You have to summon again somewhere else!")) - return - to_chat(S, span_warning("You begin to open a rift...")) - if(do_after(S, 100, target = S)) - for(var/obj/structure/carp_rift/c in S.loc.contents) - return - var/obj/structure/carp_rift/CR = new /obj/structure/carp_rift(S.loc) - playsound(S, 'sound/vehicles/rocketlaunch.ogg', 100, TRUE) - S.riftTimer = -1 - CR.dragon = S - S.rift_list += CR - to_chat(S, span_boldwarning("The rift has been summoned. Prevent the crew from destroying it at all costs!")) - notify_ghosts("The Space Dragon has opened a rift!", source = CR, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Rift Opened") - qdel(src) - -/** - * # Carp Rift - * - * The portals Space Dragon summons to bring carp onto the station. - * - * The portals Space Dragon summons to bring carp onto the station. His main objective is to summon 3 of them and protect them from being destroyed. - * The portals can summon sentient space carp in limited amounts. The portal also changes color based on whether or not a carp spawn is available. - * Once it is fully charged, it becomes indestructible, and intermitently spawns non-sentient carp. It is still destroyed if Space Dragon dies. - */ -/obj/structure/carp_rift - name = "carp rift" - desc = "A rift akin to the ones space carp use to travel long distances." - armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 50, BIO = 0, FIRE = 100, ACID = 100) - max_integrity = 300 - icon = 'icons/obj/carp_rift.dmi' - icon_state = "carp_rift_carpspawn" - light_color = LIGHT_COLOR_PURPLE - light_range = 10 - anchored = TRUE - density = FALSE - plane = MASSIVE_OBJ_PLANE - /// The amount of time the rift has charged for. - var/time_charged = 0 - /// The maximum charge the rift can have. - var/max_charge = 300 - /// How many carp spawns it has available. - var/carp_stored = 1 - /// A reference to the Space Dragon that created it. - var/mob/living/simple_animal/hostile/space_dragon/dragon - /// Current charge state of the rift. - var/charge_state = CHARGE_ONGOING - /// The interval for adding additional space carp spawns to the rift. - var/carp_interval = 60 - /// The time since an extra carp was added to the ghost role spawning pool. - var/last_carp_inc = 0 - /// A list of all the ckeys which have used this carp rift to spawn in as carps. - var/list/ckey_list = list() - -/obj/structure/carp_rift/Initialize(mapload) - . = ..() - - AddComponent( \ - /datum/component/aura_healing, \ - range = 0, \ - simple_heal = 5, \ - limit_to_trait = TRAIT_HEALS_FROM_CARP_RIFTS, \ - healing_color = COLOR_BLUE, \ - ) - - START_PROCESSING(SSobj, src) - -// Carp rifts always take heavy explosion damage. Discourages the use of maxcaps -// and favours more weaker explosives to destroy the portal -// as they have the same effect on the portal. -/obj/structure/carp_rift/ex_act(severity, target) - return ..(min(EXPLODE_HEAVY, severity)) - -/obj/structure/carp_rift/examine(mob/user) - . = ..() - if(time_charged < max_charge) - . += span_notice("It seems to be [(time_charged / max_charge) * 100]% charged.") - else - . += span_warning("This one is fully charged. In this state, it is poised to transport a much larger amount of carp than normal.") - - if(isobserver(user)) - . += span_notice("It has [carp_stored] carp available to spawn as.") - -/obj/structure/carp_rift/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - playsound(src, 'sound/magic/lightningshock.ogg', 50, TRUE) - -/obj/structure/carp_rift/Destroy() - STOP_PROCESSING(SSobj, src) - if(time_charged != max_charge + 1) - dragon?.destroy_rifts() - if(dragon) - to_chat(dragon, span_boldwarning("A rift has been destroyed! You have failed, and find yourself weakened.")) - return ..() - -/obj/structure/carp_rift/process(delta_time) - // If we're fully charged, just start mass spawning carp and move around. - if(charge_state == CHARGE_COMPLETED) - if(DT_PROB(1.25, delta_time)) - new /mob/living/simple_animal/hostile/carp(loc) - if(DT_PROB(1.5, delta_time)) - var/rand_dir = pick(GLOB.cardinals) - Move(get_step(src, rand_dir), rand_dir) - return - - // Increase time trackers and check for any updated states. - time_charged = min(time_charged + delta_time, max_charge) - last_carp_inc += delta_time - update_check() - -/obj/structure/carp_rift/attack_ghost(mob/user) - . = ..() - if(.) - return - summon_carp(user) - -/** - * Does a series of checks based on the portal's status. - * - * Performs a number of checks based on the current charge of the portal, and triggers various effects accordingly. - * If the current charge is a multiple of carp_interval, add an extra carp spawn. - * If we're halfway charged, announce to the crew our location in a CENTCOM announcement. - * If we're fully charged, tell the crew we are, change our color to yellow, become invulnerable, and give Space Dragon the ability to make another rift, if he hasn't summoned 3 total. - */ -/obj/structure/carp_rift/proc/update_check() - // If the rift is fully charged, there's nothing to do here anymore. - if(charge_state == CHARGE_COMPLETED) - return - - // Can we increase the carp spawn pool size? - if(last_carp_inc >= carp_interval) - carp_stored++ - icon_state = "carp_rift_carpspawn" - if(light_color != LIGHT_COLOR_PURPLE) - set_light_color(LIGHT_COLOR_PURPLE) - update_light() - notify_ghosts("The carp rift can summon an additional carp!", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "Carp Spawn Available") - last_carp_inc -= carp_interval - - // Is the rift now fully charged? - if(time_charged >= max_charge) - charge_state = CHARGE_COMPLETED - var/area/A = get_area(src) - priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "Central Command Wildlife Observations") - atom_integrity = INFINITY - icon_state = "carp_rift_charged" - set_light_color(LIGHT_COLOR_YELLOW) - update_light() - armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100) - resistance_flags = INDESTRUCTIBLE - dragon.rifts_charged += 1 - if(dragon.rifts_charged != 3 && !dragon.objective_complete) - var/datum/action/innate/summon_rift/rift = new() - rift.Grant(dragon) - dragon.riftTimer = 0 - dragon.rift_empower() - // Early return, nothing to do after this point. - return - - // Do we need to give a final warning to the station at the halfway mark? - if(charge_state < CHARGE_FINALWARNING && time_charged >= (max_charge * 0.5)) - charge_state = CHARGE_FINALWARNING - var/area/A = get_area(src) - priority_announce("A rift is causing an unnaturally large energy flux in [initial(A.name)]. Stop it at all costs!", "Central Command Wildlife Observations", ANNOUNCER_SPANOMALIES) - -/** - * Used to create carp controlled by ghosts when the option is available. - * - * Creates a carp for the ghost to control if we have a carp spawn available. - * Gives them prompt to control a carp, and if our circumstances still allow if when they hit yes, spawn them in as a carp. - * Also add them to the list of carps in Space Dragon's antgonist datum, so they'll be displayed as having assisted him on round end. - * Arguments: - * * mob/user - The ghost which will take control of the carp. - */ -/obj/structure/carp_rift/proc/summon_carp(mob/user) - if(carp_stored <= 0)//Not enough carp points - return FALSE - var/is_listed = FALSE - if (user.ckey in ckey_list) - if(carp_stored == 1) - to_chat(user, span_warning("You've already become a carp using this rift! Either wait for a backlog of carp spawns or until the next rift!")) - return FALSE - is_listed = TRUE - var/carp_ask = tgui_alert(user, "Become a carp?", "Carp Rift", list("Yes", "No")) - if(carp_ask != "Yes" || !src || QDELETED(src) || QDELETED(user)) - return FALSE - if(carp_stored <= 0) - to_chat(user, span_warning("The rift already summoned enough carp!")) - return FALSE - - var/mob/living/simple_animal/hostile/carp/newcarp = new /mob/living/simple_animal/hostile/carp(loc) - newcarp.AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move) - newcarp.AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!") - - if(!is_listed) - ckey_list += user.ckey - newcarp.key = user.key - newcarp.set_name() - var/datum/antagonist/space_dragon/S = dragon?.mind?.has_antag_datum(/datum/antagonist/space_dragon) - if(S) - S.carp += newcarp.mind - to_chat(newcarp, span_boldwarning("You have arrived in order to assist the space dragon with securing the rifts. Do not jeopardize the mission, and protect the rifts at all costs!")) - carp_stored-- - if(carp_stored <= 0 && charge_state < CHARGE_COMPLETED) - icon_state = "carp_rift" - set_light_color(LIGHT_COLOR_BLUE) - update_light() - return TRUE - -#undef CHARGE_ONGOING -#undef CHARGE_FINALWARNING -#undef CHARGE_COMPLETED #undef DARKNESS_THRESHOLD diff --git a/tgstation.dme b/tgstation.dme index fdcba44f64a..91f57d7f79a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2324,6 +2324,7 @@ #include "code\modules\antagonists\slaughter\slaughter.dm" #include "code\modules\antagonists\slaughter\slaughter_antag.dm" #include "code\modules\antagonists\slaughter\slaughterevent.dm" +#include "code\modules\antagonists\space_dragon\carp_rift.dm" #include "code\modules\antagonists\space_dragon\space_dragon.dm" #include "code\modules\antagonists\space_ninja\space_ninja.dm" #include "code\modules\antagonists\survivalist\survivalist.dm"