diff --git a/code/modules/antagonists/nightmare/nightmare.dm b/code/modules/antagonists/nightmare/nightmare.dm index 41a3f181..847ceeb6 100644 --- a/code/modules/antagonists/nightmare/nightmare.dm +++ b/code/modules/antagonists/nightmare/nightmare.dm @@ -1,4 +1,21 @@ +#define LIGHTSTOBREAK_MINIMUM 25 +#define LIGHTSTOBREAK_MAXIMUM 75 +#define LIGHTSTOBREAK_THRESHOLD 50 +#define LIGHTSTOBREAK_MAX_CHANCE 50 +#define LIGHTSTOBREAK_AREA_MIN 1 +#define LIGHTSTOBREAK_AREA_MAX 2 + /datum/antagonist/nightmare name = "Nightmare" show_in_antagpanel = FALSE - show_name_in_check_antagonists = TRUE \ No newline at end of file + show_name_in_check_antagonists = TRUE + +/datum/antagonist/nightmare/on_gain() + owner.objectives += forge_objective() + owner.objectives += new /datum/objective/survive + +/datum/antagonist/nightmare/proc/forge_objective() + var/datum/objective/break_lights/O = new + O.mode = prob(50) ? TRUE : FALSE + antag_memory = "Objectives:
1.
[O.apply_rules()]
2. Stay alive until the end." + return O diff --git a/code/modules/antagonists/nightmare/nightmare_objectives.dm b/code/modules/antagonists/nightmare/nightmare_objectives.dm new file mode 100644 index 00000000..dbcadc5e --- /dev/null +++ b/code/modules/antagonists/nightmare/nightmare_objectives.dm @@ -0,0 +1,105 @@ +/datum/objective/break_lights + var/mode = FALSE //If true, break all lights in determined area + var/list/area_targets = list() //Which areas we have to keep lights broken + target_amount = LIGHTSTOBREAK_AREA_MIN + var/lightsbroken = 0 + + var/safe_areas = list( + /area/space, + /area/maintenance/solars, + /area/maintenance/central, //HOP/Conference room APC + /area/ai_monitored, + /area/shuttle, + /area/engine/engine_smes, + /area/security/prison, //If you get unlucky, you'll have to break the lights in armory + /area/security/execution) + +/datum/objective/break_lights/proc/apply_rules() + if(mode) + var/list/valid_areas = list() + for(var/obj/machinery/power/apc/C in GLOB.apcs_list) + if(C.cell && is_station_level(C.z)) + var/is_safearea = 1 + for(var/A in safe_areas) + if(istype(C.area, A)) + is_safearea = 0 + break + if(is_safearea) + valid_areas += C.area + var/I = rand(LIGHTSTOBREAK_AREA_MIN, LIGHTSTOBREAK_AREA_MAX) + for(var/N in 1 to I) + var/area2add = pick(valid_areas) + if(!locate(area2add) in area_targets) + area_targets += area2add + else + target_amount = rand(LIGHTSTOBREAK_MINIMUM, LIGHTSTOBREAK_MAXIMUM) + if(prob(LIGHTSTOBREAK_MAX_CHANCE)) + if(target_amount > LIGHTSTOBREAK_THRESHOLD) + target_amount = LIGHTSTOBREAK_MAXIMUM + else if(target_amount > LIGHTSTOBREAK_THRESHOLD) + target_amount = LIGHTSTOBREAK_THRESHOLD + explanation_text = update_explanation_text() + return explanation_text + +/datum/objective/break_lights/update_explanation_text() + ..() + if(mode) + if(!area_targets.len) + return "Uh oh! Something broke! Report this." + . += "There must not be any light sources in the " + if(area_targets.len == 1) + var/area/A = area_targets[1] + . += "[A.name]" + else if(area_targets.len == 2) + var/area/A = area_targets[1] + var/area/B = area_targets[2] + . += "[A.name] and [B.name]" + else //Won't get here because of define values, but during development you can get here. leaving this here for future purposes + var/i = 1 + for(var/area/A in area_targets) + if(i != area_targets.len) . += "[A.name], " + else . += "and [A.name]" + + . += " before the end." + else + . += "Break at least [target_amount] lights with your light eater." + +/datum/objective/break_lights/check_completion() + if(completed) + return TRUE //An attempt to stop this from being called twice + if(!mode) + if(lightsbroken >= target_amount) + completed = TRUE + else + var/list/valid_turfs = list() + for(var/area/target in area_targets) + var/list/cached_area = get_area_turfs(target.type) + for(var/turf/A in cached_area) + if(!is_station_level(A.z)) + continue + valid_turfs += A + for(var/turf/T in valid_turfs) + for(var/atom/C in T.contents) + /*if(!C?.visibility) //Doesn't compile, add this another time + continue*/ + if(C.light_range > 0) + if(C.light_power <= SHADOW_SPECIES_LIGHT_THRESHOLD*2) //Give some leniency for not destroying that unbreakable requests console + completed = TRUE + else + completed = FALSE + break + if(!completed) + break + + return completed + +/datum/objective/break_lights/area + mode = TRUE + + +#undef LIGHTSTOBREAK_MINIMUM +#undef LIGHTSTOBREAK_MAXIMUM +#undef LIGHTSTOBREAK_THRESHOLD +#undef LIGHTSTOBREAK_MAX_CHANCE +#undef LIGHTSTOBREAK_AREA_MIN +#undef LIGHTSTOBREAK_AREA_MAX diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b8b62a8b..343cf07c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -82,6 +82,18 @@ if(changeling) sList2 += "Chemical Storage: " + "[changeling.chem_charges]/[changeling.chem_storage]" sList2 += "Absorbed DNA: "+ "[changeling.absorbedcount]" + var/datum/antagonist/nightmare/nightmare = mind.has_antag_datum(/datum/antagonist/nightmare) + if(nightmare) + for(var/datum/objective/O in mind.objectives) + if(istype(O, /datum/objective/break_lights)) + var/datum/objective/break_lights/BL = O + if(BL.mode) //Keeping lights out of areas + var/T = "Target Area(s): " + for(var/area/I in BL.area_targets) + T += "[initial(I.name)], " + sList2 += T + else //Break number of lights + sList2 += "Lights Broken: " + "[BL.lightsbroken]/[BL.target_amount]" if (sList2 != null) stat(null, "[sList2.Join("\n\n")]") diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index 3c716fa1..b1d2f5e1 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -183,9 +183,14 @@ . = ..() if(!proximity) return - if(isopenturf(AM)) //So you can actually melee with it + if(isopenturf(AM) && !istype(AM, /turf/open/space) && !istype(AM, /turf/open/lava)) + var/turf/T = AM + if(T.light_power || T.light_range) + to_chat(user, "[src] consumes the lights in [AM].") + T.set_light(0,0) + else if(isopenturf(AM)) return - if(isliving(AM)) + else if(isliving(AM)) var/mob/living/L = AM if(iscyborg(AM)) var/mob/living/silicon/robot/borg = AM @@ -194,20 +199,40 @@ to_chat(borg, "Your headlamp is fried! You'll need a human to help replace it.") else for(var/obj/item/O in AM) - if(O.light_range && O.light_power) - disintegrate(O) - if(L.pulling && L.pulling.light_range && isitem(L.pulling)) - disintegrate(L.pulling) + if(O.light_range && O.light_power && !check_plasmaman(O, AM)) + disintegrate(O, user) + if(L.pulling && L.pulling.light_range && isitem(L.pulling) && !check_plasmaman(L.pulling, L)) + disintegrate(L.pulling, user) else if(isitem(AM)) var/obj/item/I = AM - if(I.light_range && I.light_power) - disintegrate(I) + if(I.light_range && I.light_power && !check_plasmaman(AM)) + disintegrate(I, user) else if(istype(AM, /obj/structure/marker_beacon)) var/obj/structure/marker_beacon/I = AM - disintegrate(I) + disintegrate(I, user) //why the fuck is the marker beacon a structure? who. what. why. + else if(istype(AM, /obj/machinery/light)) + var/obj/machinery/light/L = AM + if(L.status == 2) //Assume we just broke the light + handle_objectives(user) + L.status = 1 //No tube + L.update(FALSE) -/obj/item/light_eater/proc/disintegrate(obj/item/O) +/obj/item/light_eater/proc/handle_objectives(mob/living/carbon/human/H) + if(!H.mind) + return + + if(!H.mind.objectives) + return + + for(var/O in H.mind.objectives) + if(!istype(O, /datum/objective/break_lights)) + continue + var/datum/objective/break_lights/BL = O + if(!BL.mode) + BL.lightsbroken++ + +/obj/item/light_eater/proc/disintegrate(obj/item/O, user) if(istype(O, /obj/item/pda)) var/obj/item/pda/PDA = O PDA.set_light(0) @@ -220,5 +245,21 @@ O.burn() playsound(src, 'sound/items/welder.ogg', 50, 1) + if(is_species(user, /datum/species/shadow/nightmare)) + handle_objectives(user) + +/obj/item/light_eater/proc/check_plasmaman(obj/item/O, mob/living/carbon/human/user) + if(!istype(O, /obj/item/clothing/head/helmet/space/plasmaman)) + return FALSE + var/obj/item/clothing/head/helmet/space/plasmaman/H = O + if(H.on) + H.on = FALSE + H.icon_state = "[initial(H.icon_state)][H.on ? "-light":""]" + H.item_state = H.icon_state + if(user) + user.update_inv_head() + to_chat(user, "Your [H]'s torch extinguishes!") + return TRUE + #undef HEART_SPECIAL_SHADOWIFY #undef HEART_RESPAWN_THRESHHOLD diff --git a/tgstation.dme b/tgstation.dme index fd4992bd..9562ec48 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1375,6 +1375,7 @@ #include "code\modules\antagonists\morph\morph.dm" #include "code\modules\antagonists\morph\morph_antag.dm" #include "code\modules\antagonists\nightmare\nightmare.dm" +#include "code\modules\antagonists\nightmare\nightmare_objectives.dm" #include "code\modules\antagonists\ninja\ninja.dm" #include "code\modules\antagonists\nukeop\clownop.dm" #include "code\modules\antagonists\nukeop\nukeop.dm"