From f9666ab6c992ed3259b5c605668f9e47864facb3 Mon Sep 17 00:00:00 2001 From: AnturK Date: Mon, 5 Feb 2018 23:59:18 +0100 Subject: [PATCH 1/7] Slaughter demon, Morph, ERT / Deathsquad antag datums. --- code/__DEFINES/antagonists.dm | 17 +- code/modules/admin/check_antagonists.dm | 5 +- code/modules/admin/verbs/one_click_antag.dm | 219 +++++---------- .../antagonists/_common/antag_datum.dm | 11 +- .../antagonists/_common/antag_spawner.dm | 255 ++++++++++++++++++ .../modules/antagonists/_common/antag_team.dm | 21 +- code/modules/antagonists/ert/ert.dm | 87 ++++++ code/modules/antagonists/morph/morph_antag.dm | 6 + code/modules/antagonists/ninja/ninja.dm | 5 +- .../antagonists/slaughter/slaughter_antag.dm | 31 +++ tgstation.dme | 3 + 11 files changed, 498 insertions(+), 162 deletions(-) create mode 100644 code/modules/antagonists/ert/ert.dm create mode 100644 code/modules/antagonists/morph/morph_antag.dm create mode 100644 code/modules/antagonists/slaughter/slaughter_antag.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index c82404fd00..97d4126e35 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -11,4 +11,19 @@ #define APPRENTICE_DESTRUCTION "destruction" #define APPRENTICE_BLUESPACE "bluespace" #define APPRENTICE_ROBELESS "robeless" -#define APPRENTICE_HEALING "healing" \ No newline at end of file +#define APPRENTICE_HEALING "healing" + + +//ERT Types +#define ERT_BLUE "Blue" +#define ERT_RED "Red" +#define ERT_AMBER "Amber" +#define ERT_DEATHSQUAD "Deathsquad" + +//ERT subroles +#define ERT_SEC "sec" +#define ERT_MED "med" +#define ERT_ENG "eng" +#define ERT_LEADER "leader" +#define DEATHSQUAD "ds" +#define DEATHSQUAD_LEADER "ds_leader" \ No newline at end of file diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm index f1ad21ded3..b4c72d2f0e 100644 --- a/code/modules/admin/check_antagonists.dm +++ b/code/modules/admin/check_antagonists.dm @@ -40,7 +40,10 @@ // Jim (Status) FLW PM TP /datum/antagonist/proc/antag_listing_entry() var/list/parts = list() - parts += antag_listing_name() + if(show_name_in_check_antagonists) + parts += "[antag_listing_name()]([name])" + else + parts += antag_listing_name() parts += antag_listing_status() parts += antag_listing_commands() return "[parts.Join("")]" diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 759cc97dbb..c886a77e88 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -271,77 +271,7 @@ // DEATH SQUADS /datum/admins/proc/makeDeathsquad() - var/mission = input("Assign a mission to the deathsquad", "Assign Mission", "Leave no witnesses.") - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for an elite Nanotrasen Strike Team?", "deathsquad", null) - var/squadSpawned = 0 - - if(candidates.len >= 2) //Minimum 2 to be considered a squad - //Pick the lucky players - var/numagents = min(5,candidates.len) //How many commandos to spawn - var/list/spawnpoints = GLOB.emergencyresponseteamspawn - while(numagents && candidates.len) - if (numagents > spawnpoints.len) - numagents-- - continue // This guy's unlucky, not enough spawn points, we skip him. - var/spawnloc = spawnpoints[numagents] - var/mob/dead/observer/chosen_candidate = pick(candidates) - candidates -= chosen_candidate - if(!chosen_candidate.key) - continue - - //Spawn and equip the commando - var/mob/living/carbon/human/Commando = new(spawnloc) - chosen_candidate.client.prefs.copy_to(Commando) - if(numagents == 1) //If Squad Leader - Commando.real_name = "Officer [pick(GLOB.commando_names)]" - Commando.equipOutfit(/datum/outfit/death_commando/officer) - else - Commando.real_name = "Trooper [pick(GLOB.commando_names)]" - Commando.equipOutfit(/datum/outfit/death_commando) - Commando.dna.update_dna_identity() - Commando.key = chosen_candidate.key - Commando.mind.assigned_role = "Death Commando" - for(var/obj/machinery/door/poddoor/ert/door in GLOB.airlocks) - spawn(0) - door.open() - - //Assign antag status and the mission - Commando.mind.special_role = "deathsquad" - - var/datum/objective/missionobj = new - missionobj.owner = Commando.mind - missionobj.explanation_text = mission - missionobj.completed = 1 - Commando.mind.objectives += missionobj - - Commando.mind.add_antag_datum(/datum/antagonist/auto_custom) - - //Greet the commando - to_chat(Commando, "You are the [numagents==1?"Deathsquad Officer":"Death Commando"].") - var/missiondesc = "Your squad is being sent on a mission to [station_name()] by Nanotrasen's Security Division." - if(numagents == 1) //If Squad Leader - missiondesc += " Lead your squad to ensure the completion of the mission. Board the shuttle when your team is ready." - else - missiondesc += " Follow orders given to you by your squad leader." - missiondesc += "
Your Mission: [mission]" - to_chat(Commando, missiondesc) - - if(CONFIG_GET(flag/enforce_human_authority)) - Commando.set_species(/datum/species/human) - - //Logging and cleanup - if(numagents == 1) - message_admins("The deathsquad has spawned with the mission: [mission].") - log_game("[key_name(Commando)] has been selected as a Death Commando") - numagents-- - squadSpawned++ - - if (squadSpawned) - return 1 - else - return 0 - - return + return makeEmergencyresponseteam(ERT_DEATHSQUAD) /datum/admins/proc/makeOfficial() var/mission = input("Assign a task for the official", "Assign Task", "Conduct a routine preformance review of [station_name()] and its Captain.") @@ -386,38 +316,70 @@ return 0 // CENTCOM RESPONSE TEAM -/datum/admins/proc/makeEmergencyresponseteam() - var/alert = input("Which team should we send?", "Select Response Level") as null|anything in list("Green: CentCom Official", "Blue: Light ERT (No Armoury Access)", "Amber: Full ERT (Armoury Access)", "Red: Elite ERT (Armoury Access + Pulse Weapons)", "Delta: Deathsquad") - if(!alert) - return +/datum/admins/proc/makeEmergencyresponseteam(alert_type) + var/alert + if(!alert_type) + alert = input("Which team should we send?", "Select Response Level") as null|anything in list("Green: CentCom Official", "Blue: Light ERT (No Armoury Access)", "Amber: Full ERT (Armoury Access)", "Red: Elite ERT (Armoury Access + Pulse Weapons)", "Delta: Deathsquad") + if(!alert) + return + else + alert = alert_type + + var/teamsize = 0 + var/deathsquad = FALSE + switch(alert) if("Delta: Deathsquad") - return makeDeathsquad() + alert = ERT_DEATHSQUAD + teamsize = 5 + deathsquad = TRUE if("Red: Elite ERT (Armoury Access + Pulse Weapons)") - alert = "Red" + alert = ERT_RED if("Amber: Full ERT (Armoury Access)") - alert = "Amber" + alert = ERT_AMBER if("Blue: Light ERT (No Armoury Access)") - alert = "Blue" + alert = ERT_BLUE if("Green: CentCom Official") return makeOfficial() - var/teamcheck = input("Maximum size of team? (7 max)", "Select Team Size",4) as null|num - if(isnull(teamcheck)) - return - var/teamsize = min(7,teamcheck) - var/mission = input("Assign a mission to the Emergency Response Team", "Assign Mission", "Assist the station.") as null|text + else + return + + if(!teamsize) + var/teamcheck = input("Maximum size of team? (7 max)", "Select Team Size",4) as null|num + if(isnull(teamcheck)) + return + teamsize = min(7,teamcheck) + + + var/default_mission = deathsquad ? "Leave no witnesses." : "Assist the station." + var/mission = input("Assign a mission to the Emergency Response Team", "Assign Mission", default_mission) as null|text if(!mission) return - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a Code [alert] Nanotrasen Emergency Response Team?", "deathsquad", null) + + var/prompt_name = deathsquad ? "an elite Nanotrasen Strike Team" : "a Code [alert] Nanotrasen Emergency Response Team" + var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [prompt_name] ?", "deathsquad", null) var/teamSpawned = 0 if(candidates.len > 0) //Pick the (un)lucky players var/numagents = min(teamsize,candidates.len) //How many officers to spawn - var/redalert //If the ert gets super weapons - if (alert == "Red") - numagents = min(teamsize,candidates.len) - redalert = 1 + + //Create team + var/datum/team/ert/ert_team = new + if(deathsquad) + ert_team.name = "Death Squad" + + //Asign team objective + var/datum/objective/missionobj = new + missionobj.team = ert_team + missionobj.explanation_text = mission + missionobj.completed = 1 + ert_team.objectives += missionobj + ert_team.mission = missionobj + + //We give these out in order, then back from the start if there's more than 3 + var/list/role_order = list(ERT_SEC,ERT_MED,ERT_ENG) + var/list/spawnpoints = GLOB.emergencyresponseteamspawn while(numagents && candidates.len) if (numagents > spawnpoints.len) @@ -429,75 +391,38 @@ if(!chosen_candidate.key) continue - //Spawn and equip the officer + //Spawn the body var/mob/living/carbon/human/ERTOperative = new(spawnloc) - var/list/lastname = GLOB.last_names chosen_candidate.client.prefs.copy_to(ERTOperative) - var/ertname = pick(lastname) - switch(numagents) - if(1) - ERTOperative.real_name = "Commander [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/commander/alert : /datum/outfit/ert/commander) - if(2) - ERTOperative.real_name = "Security Officer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/security/alert : /datum/outfit/ert/security) - if(3) - ERTOperative.real_name = "Medical Officer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/medic/alert : /datum/outfit/ert/medic) - if(4) - ERTOperative.real_name = "Engineer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/engineer/alert : /datum/outfit/ert/engineer) - if(5) - ERTOperative.real_name = "Security Officer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/security/alert : /datum/outfit/ert/security) - if(6) - ERTOperative.real_name = "Medical Officer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/medic/alert : /datum/outfit/ert/medic) - if(7) - ERTOperative.real_name = "Engineer [ertname]" - ERTOperative.equipOutfit(redalert ? /datum/outfit/ert/engineer/alert : /datum/outfit/ert/engineer) - ERTOperative.dna.update_dna_identity() ERTOperative.key = chosen_candidate.key - ERTOperative.mind.assigned_role = "ERT" - - //Open the Armory doors - if(alert != "Blue") - for(var/obj/machinery/door/poddoor/ert/door in GLOB.airlocks) - spawn(0) - door.open() - - //Assign antag status and the mission - ERTOperative.mind.special_role = "ERT" - - var/datum/objective/missionobj = new - missionobj.owner = ERTOperative.mind - missionobj.explanation_text = mission - missionobj.completed = 1 - ERTOperative.mind.objectives += missionobj - - ERTOperative.mind.add_antag_datum(/datum/antagonist/auto_custom) - - //Greet the commando - to_chat(ERTOperative, "You are [numagents==1?"the Emergency Response Team Commander":"an Emergency Response Officer"].") - var/missiondesc = "Your squad is being sent on a Code [alert] mission to [station_name()] by Nanotrasen's Security Division." - if(numagents == 1) //If Squad Leader - missiondesc += " Lead your squad to ensure the completion of the mission. Avoid civilian casualites when possible. Board the shuttle when your team is ready." - else - missiondesc += " Follow orders given to you by your commander. Avoid civilian casualites when possible." - missiondesc += "
Your Mission: [mission]" - to_chat(ERTOperative, missiondesc) - + if(CONFIG_GET(flag/enforce_human_authority)) ERTOperative.set_species(/datum/species/human) - //Logging and cleanup + //Give antag datum + var/datum/antagonist/ert/ert_antag = new + ert_antag.high_alert = alert == ERT_RED if(numagents == 1) - message_admins("A Code [alert] emergency response team has spawned with the mission: [mission]") - log_game("[key_name(ERTOperative)] has been selected as an Emergency Response Officer") + ert_antag.role = deathsquad ? DEATHSQUAD_LEADER : ERT_LEADER + else + ert_antag.role = deathsquad ? DEATHSQUAD : role_order[WRAP(numagents,1,role_order.len + 1)] + ERTOperative.mind.add_antag_datum(ert_antag,ert_team) + + ERTOperative.mind.assigned_role = ert_antag.name + + //Logging and cleanup + log_game("[key_name(ERTOperative)] has been selected as an [ert_antag.name]") numagents-- teamSpawned++ if (teamSpawned) + message_admins("[prompt_name] has spawned with the mission: [mission]") + + //Open the Armory doors + if(alert != ERT_BLUE) + for(var/obj/machinery/door/poddoor/ert/door in GLOB.airlocks) + spawn(0) + door.open() return 1 else return 0 diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 7d090bfd63..ee15730278 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(antagonists) //Antag panel properties var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED + var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type /datum/antagonist/New() GLOB.antagonists += src @@ -206,6 +207,7 @@ GLOBAL_LIST_EMPTY(antagonists) /datum/antagonist/auto_custom show_in_antagpanel = FALSE antagpanel_category = "Other" + show_name_in_check_antagonists = TRUE /datum/antagonist/auto_custom/on_gain() ..() @@ -219,12 +221,10 @@ GLOBAL_LIST_EMPTY(antagonists) already_registered_objectives |= A.objectives objectives = owner.objectives - already_registered_objectives -/datum/antagonist/auto_custom/antag_listing_name() - return ..() + "([name])" - //This one is created by admin tools for custom objectives /datum/antagonist/custom antagpanel_category = "Custom" + show_name_in_check_antagonists = TRUE //They're all different /datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin) var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist") @@ -232,7 +232,4 @@ GLOBAL_LIST_EMPTY(antagonists) name = custom_name else return - ..() - -/datum/antagonist/custom/antag_listing_name() - return ..() + "([name])" \ No newline at end of file + ..() \ No newline at end of file diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index fd49bc72a3..942d33797d 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /obj/item/antag_spawner throw_speed = 1 throw_range = 5 @@ -264,3 +265,257 @@ veil_msg = "You sense an adorable presence lurking just beyond the veil..." objective_verb = "Hug and Tickle" demon_type = /mob/living/simple_animal/slaughter/laughter +======= +/obj/item/antag_spawner + throw_speed = 1 + throw_range = 5 + w_class = WEIGHT_CLASS_TINY + var/used = FALSE + +/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user) + return + +/obj/item/antag_spawner/proc/equip_antag(mob/target) + return + + +///////////WIZARD + +/obj/item/antag_spawner/contract + name = "contract" + desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid." + icon = 'icons/obj/wizard.dmi' + icon_state ="scroll2" + +/obj/item/antag_spawner/contract/attack_self(mob/user) + user.set_machine(src) + var/dat + if(used) + dat = "You have already summoned your apprentice.
" + else + dat = "Contract of Apprenticeship:
" + dat += "Using this contract, you may summon an apprentice to aid you on your mission.
" + dat += "If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.
" + dat += "Which school of magic is your apprentice studying?:
" + dat += "Destruction
" + dat += "Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.
" + dat += "Bluespace Manipulation
" + dat += "Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.
" + dat += "Healing
" + dat += "Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.
" + dat += "Robeless
" + dat += "Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.
" + user << browse(dat, "window=radio") + onclose(user, "radio") + return + +/obj/item/antag_spawner/contract/Topic(href, href_list) + ..() + var/mob/living/carbon/human/H = usr + + if(H.stat || H.restrained()) + return + if(!ishuman(H)) + return 1 + + if(loc == H || (in_range(src, H) && isturf(loc))) + H.set_machine(src) + if(href_list["school"]) + if(used) + to_chat(H, "You already used this contract!") + return + var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src) + if(LAZYLEN(candidates)) + if(used) + to_chat(H, "You already used this contract!") + return + used = TRUE + var/client/C = pick(candidates) + spawn_antag(C, get_turf(src), href_list["school"],H.mind) + else + to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.") + +/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user) + new /obj/effect/particle_effect/smoke(T) + var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) + C.prefs.copy_to(M) + M.key = C.key + var/datum/mind/app_mind = M.mind + + var/datum/antagonist/wizard/apprentice/app = new() + app.master = user + app.school = kind + + var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard) + if(master_wizard) + if(!master_wizard.wiz_team) + master_wizard.create_wiz_team() + app.wiz_team = master_wizard.wiz_team + master_wizard.wiz_team.add_member(app_mind) + app_mind.add_antag_datum(app) + //TODO Kill these if possible + app_mind.assigned_role = "Apprentice" + app_mind.special_role = "apprentice" + // + SEND_SOUND(M, sound('sound/effects/magic.ogg')) + +///////////BORGS AND OPERATIVES + + +/obj/item/antag_spawner/nuke_ops + name = "syndicate operative teleporter" + desc = "A single-use teleporter designed to quickly reinforce operatives in the field." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + var/borg_to_spawn + +/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user) + if(used) + to_chat(user, "[src] is out of power!") + return FALSE + if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)) + to_chat(user, "AUTHENTICATION FAILURE. ACCESS DENIED.") + return FALSE + if(!user.onSyndieBase()) + to_chat(user, "[src] is out of range! It can only be used at your base!") + return FALSE + return TRUE + + +/obj/item/antag_spawner/nuke_ops/attack_self(mob/user) + if(!(check_usability(user))) + return + + to_chat(user, "You activate [src] and wait for confirmation.") + var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE) + if(LAZYLEN(nuke_candidates)) + if(!(check_usability(user))) + return + used = TRUE + var/client/C = pick(nuke_candidates) + spawn_antag(C, get_turf(src), "syndieborg", user.mind) + do_sparks(4, TRUE, src) + qdel(src) + else + to_chat(user, "Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.") + +/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user) + var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) + C.prefs.copy_to(M) + M.key = C.key + + var/datum/antagonist/nukeop/new_op = new() + new_op.send_to_spawnpoint = FALSE + new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals + + var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE) + if(creator_op) + M.mind.add_antag_datum(new_op,creator_op.nuke_team) + M.mind.special_role = "Nuclear Operative" + +//////SYNDICATE BORG +/obj/item/antag_spawner/nuke_ops/borg_tele + name = "syndicate cyborg teleporter" + desc = "A single-use teleporter designed to quickly reinforce operatives in the field.." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + +/obj/item/antag_spawner/nuke_ops/borg_tele/assault + name = "syndicate assault cyborg teleporter" + borg_to_spawn = "Assault" + +/obj/item/antag_spawner/nuke_ops/borg_tele/medical + name = "syndicate medical teleporter" + borg_to_spawn = "Medical" + +/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user) + var/mob/living/silicon/robot/R + var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE) + if(!creator_op) + return + + switch(borg_to_spawn) + if("Medical") + R = new /mob/living/silicon/robot/modules/syndicate/medical(T) + else + R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default + + var/brainfirstname = pick(GLOB.first_names_male) + if(prob(50)) + brainfirstname = pick(GLOB.first_names_female) + var/brainopslastname = pick(GLOB.last_names) + if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops. + brainopslastname = creator_op.nuke_team.syndicate_name + var/brainopsname = "[brainfirstname] [brainopslastname]" + + R.mmi.name = "Man-Machine Interface: [brainopsname]" + R.mmi.brain.name = "[brainopsname]'s brain" + R.mmi.brainmob.real_name = brainopsname + R.mmi.brainmob.name = brainopsname + R.real_name = R.name + + R.key = C.key + + var/datum/antagonist/nukeop/new_borg = new() + new_borg.send_to_spawnpoint = FALSE + R.mind.add_antag_datum(new_borg,creator_op.nuke_team) + R.mind.special_role = "Syndicate Cyborg" + +///////////SLAUGHTER DEMON + +/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game + name = "vial of blood" + desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures." + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + + var/shatter_msg = "You shatter the bottle, no turning back now!" + var/veil_msg = "You sense a dark presence lurking just beyond the veil..." + var/mob/living/demon_type = /mob/living/simple_animal/slaughter + var/antag_type = /datum/antagonist/slaughter + + +/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user) + if(!is_station_level(user.z)) + to_chat(user, "You should probably wait until you reach the station.") + return + if(used) + return + var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src) + if(LAZYLEN(candidates)) + if(used) + return + used = TRUE + var/client/C = pick(candidates) + spawn_antag(C, get_turf(src), initial(demon_type.name),user.mind) + to_chat(user, shatter_msg) + to_chat(user, veil_msg) + playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1) + qdel(src) + else + to_chat(user, "You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.") + + +/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user) + var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T) + var/mob/living/simple_animal/slaughter/S = new demon_type(holder) + S.holder = holder + S.key = C.key + S.mind.assigned_role = S.name + S.mind.special_role = S.name + S.mind.add_antag_datum(antag_type) + to_chat(S, S.playstyle_string) + to_chat(S, "You are currently not currently in the same plane of existence as the station. \ + Ctrl+Click a blood pool to manifest.") + +/obj/item/antag_spawner/slaughter_demon/laughter + name = "vial of tickles" + desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures." + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + color = "#FF69B4" // HOT PINK + + veil_msg = "You sense an adorable presence lurking just beyond the veil..." + demon_type = /mob/living/simple_animal/slaughter/laughter + antag_type = /datum/antagonist/slaughter/laughter +>>>>>>> 126a544... Slaughter demon, Morph, ERT / Deathsquad antag datums. (#35156) diff --git a/code/modules/antagonists/_common/antag_team.dm b/code/modules/antagonists/_common/antag_team.dm index c458b5a9fb..486b5b0414 100644 --- a/code/modules/antagonists/_common/antag_team.dm +++ b/code/modules/antagonists/_common/antag_team.dm @@ -27,8 +27,25 @@ /datum/team/proc/roundend_report() var/list/report = list() - report += "[name]:" + report += "[name]:" report += "The [member_name]s were:" report += printplayerlist(members) - return report.Join("
") + if(objectives.len) + report += "Team had following objectives:" + var/win = TRUE + var/objective_count = 1 + for(var/datum/objective/objective in objectives) + if(objective.check_completion()) + report += "Objective #[objective_count]: [objective.explanation_text] Success!" + else + report += "Objective #[objective_count]: [objective.explanation_text] Fail." + win = FALSE + objective_count++ + if(win) + report += "The [name] was successful!" + else + report += "The [name] have failed!" + + + return "
[report.Join("
")]
" diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm new file mode 100644 index 0000000000..c49b724633 --- /dev/null +++ b/code/modules/antagonists/ert/ert.dm @@ -0,0 +1,87 @@ +//Both ERT and DS are handled by the same datums since they mostly differ in equipment in objective. +/datum/team/ert + name = "Emergency Response Team" + var/datum/objective/mission //main mission + +/datum/antagonist/ert + name = "Emergency Response Officer" + var/datum/team/ert/ert_team + var/role = ERT_SEC + var/high_alert = FALSE + show_in_antagpanel = FALSE + +/datum/antagonist/ert/on_gain() + update_name() + forge_objectives() + equipERT() + . = ..() + +/datum/antagonist/ert/get_team() + return ert_team + +/datum/antagonist/ert/proc/update_name() + var/new_name + switch(role) + if(ERT_ENG) + new_name = "Engineer [pick(GLOB.last_names)]" + if(ERT_MED) + new_name = "Medical Officer [pick(GLOB.last_names)]" + if(ERT_SEC) + new_name = "Security Officer [pick(GLOB.last_names)]" + if(ERT_LEADER) + new_name = "Commander [pick(GLOB.last_names)]" + name = "Emergency Response Commander" + if(DEATHSQUAD) + new_name = "Trooper [pick(GLOB.commando_names)]" + name = "Deathsquad Trooper" + if(DEATHSQUAD_LEADER) + new_name = "Officer [pick(GLOB.commando_names)]" + name = "Deathsquad Officer" + owner.current.fully_replace_character_name(owner.current.real_name,new_name) + +/datum/antagonist/ert/create_team(datum/team/ert/new_team) + if(istype(new_team)) + ert_team = new_team + +/datum/antagonist/ert/proc/forge_objectives() + if(ert_team) + objectives |= ert_team.objectives + +/datum/antagonist/ert/proc/equipERT() + var/mob/living/carbon/human/H = owner.current + if(!istype(H)) + return + var/outfit + switch(role) + if(ERT_LEADER) + outfit = high_alert ? /datum/outfit/ert/commander/alert : /datum/outfit/ert/commander + if(ERT_ENG) + outfit = high_alert ? /datum/outfit/ert/engineer/alert : /datum/outfit/ert/engineer + if(ERT_MED) + outfit = high_alert ? /datum/outfit/ert/medic/alert : /datum/outfit/ert/medic + if(ERT_SEC) + outfit = high_alert ? /datum/outfit/ert/security/alert : /datum/outfit/ert/security + if(DEATHSQUAD) + outfit = /datum/outfit/death_commando/officer + if(DEATHSQUAD_LEADER) + outfit = /datum/outfit/death_commando + H.equipOutfit(outfit) + +/datum/antagonist/ert/greet() + if(!ert_team) + return + + var/leader = role == ERT_LEADER || role == DEATHSQUAD_LEADER + + to_chat(owner, "You are the [name].") + + var/missiondesc = "Your squad is being sent on a mission to [station_name()] by Nanotrasen's Security Division." + if(leader) //If Squad Leader + missiondesc += " Lead your squad to ensure the completion of the mission. Board the shuttle when your team is ready." + else + missiondesc += " Follow orders given to you by your squad leader." + if(role != DEATHSQUAD && role != DEATHSQUAD_LEADER) + missiondesc += "Avoid civilian casualites when possible." + + missiondesc += "
Your Mission : [ert_team.mission.explanation_text]" + to_chat(owner,missiondesc) diff --git a/code/modules/antagonists/morph/morph_antag.dm b/code/modules/antagonists/morph/morph_antag.dm new file mode 100644 index 0000000000..e01751946d --- /dev/null +++ b/code/modules/antagonists/morph/morph_antag.dm @@ -0,0 +1,6 @@ +/datum/antagonist/morph + name = "Morph" + show_name_in_check_antagonists = TRUE + show_in_antagpanel = FALSE + +//It does nothing! (Besides tracking) \ No newline at end of file diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm index 8124b8c5b8..22f1d96cd3 100644 --- a/code/modules/antagonists/ninja/ninja.dm +++ b/code/modules/antagonists/ninja/ninja.dm @@ -2,11 +2,11 @@ name = "Ninja" antagpanel_category = "Ninja" job_rank = ROLE_NINJA + show_name_in_check_antagonists = TRUE var/helping_station = FALSE var/give_objectives = TRUE var/give_equipment = TRUE - /datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override) var/mob/living/M = mob_override || owner.current update_ninja_icons_added(M) @@ -141,9 +141,6 @@ message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].") log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].") -/datum/antagonist/ninja/antag_listing_name() - return ..() + "(Ninja)" - /datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja) var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA] ninjahud.join_hud(ninja) diff --git a/code/modules/antagonists/slaughter/slaughter_antag.dm b/code/modules/antagonists/slaughter/slaughter_antag.dm new file mode 100644 index 0000000000..a018603cf1 --- /dev/null +++ b/code/modules/antagonists/slaughter/slaughter_antag.dm @@ -0,0 +1,31 @@ +/datum/antagonist/slaughter + name = "Slaughter demon" + show_name_in_check_antagonists = TRUE + var/objective_verb = "Kill" + var/datum/mind/summoner + job_rank = ROLE_ALIEN + show_in_antagpanel = FALSE + +/datum/antagonist/slaughter/on_gain() + forge_objectives() + . = ..() + +/datum/antagonist/slaughter/greet() + . = ..() + owner.announce_objectives() + +/datum/antagonist/slaughter/proc/forge_objectives() + if(summoner) + var/datum/objective/assassinate/new_objective = new /datum/objective/assassinate + new_objective.owner = owner + new_objective.target = summoner + new_objective.explanation_text = "[objective_verb] [summoner.name], the one who summoned you." + objectives += new_objective + var/datum/objective/new_objective2 = new /datum/objective + new_objective2.owner = owner + new_objective2.explanation_text = "[objective_verb] everyone[summoner ? " else while you're at it":""]." + objectives += new_objective2 + +/datum/antagonist/slaughter/laughter + name = "Laughter demon" + objective_verb = "Hug and Tickle" \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index 826b39d6af..0cc1963db5 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1204,8 +1204,10 @@ #include "code\modules\antagonists\devil\sintouched\objectives.dm" #include "code\modules\antagonists\devil\true_devil\_true_devil.dm" #include "code\modules\antagonists\devil\true_devil\inventory.dm" +#include "code\modules\antagonists\ert\ert.dm" #include "code\modules\antagonists\monkey\monkey.dm" #include "code\modules\antagonists\morph\morph.dm" +#include "code\modules\antagonists\morph\morph_antag.dm" #include "code\modules\antagonists\ninja\ninja.dm" #include "code\modules\antagonists\nukeop\nukeop.dm" #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" @@ -1218,6 +1220,7 @@ #include "code\modules\antagonists\revenant\revenant_spawn_event.dm" #include "code\modules\antagonists\revolution\revolution.dm" #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\swarmer\swarmer.dm" #include "code\modules\antagonists\swarmer\swarmer_event.dm" From 156fa1da1a9aa2913f5b8ae724c35debde8cc793 Mon Sep 17 00:00:00 2001 From: deathride58 Date: Mon, 5 Feb 2018 21:47:53 -0500 Subject: [PATCH 2/7] Update antag_spawner.dm --- .../antagonists/_common/antag_spawner.dm | 269 ------------------ 1 file changed, 269 deletions(-) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 942d33797d..5695a8c480 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -1,271 +1,3 @@ -<<<<<<< HEAD -/obj/item/antag_spawner - throw_speed = 1 - throw_range = 5 - w_class = WEIGHT_CLASS_TINY - var/used = FALSE - -/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user) - return - -/obj/item/antag_spawner/proc/equip_antag(mob/target) - return - - -///////////WIZARD - -/obj/item/antag_spawner/contract - name = "contract" - desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid." - icon = 'icons/obj/wizard.dmi' - icon_state ="scroll2" - -/obj/item/antag_spawner/contract/attack_self(mob/user) - user.set_machine(src) - var/dat - if(used) - dat = "You have already summoned your apprentice.
" - else - dat = "Contract of Apprenticeship:
" - dat += "Using this contract, you may summon an apprentice to aid you on your mission.
" - dat += "If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.
" - dat += "Which school of magic is your apprentice studying?:
" - dat += "Destruction
" - dat += "Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.
" - dat += "Bluespace Manipulation
" - dat += "Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.
" - dat += "Healing
" - dat += "Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.
" - dat += "Robeless
" - dat += "Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.
" - user << browse(dat, "window=radio") - onclose(user, "radio") - return - -/obj/item/antag_spawner/contract/Topic(href, href_list) - ..() - var/mob/living/carbon/human/H = usr - - if(H.stat || H.restrained()) - return - if(!ishuman(H)) - return 1 - - if(loc == H || (in_range(src, H) && isturf(loc))) - H.set_machine(src) - if(href_list["school"]) - if(used) - to_chat(H, "You already used this contract!") - return - var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src) - if(LAZYLEN(candidates)) - if(used) - to_chat(H, "You already used this contract!") - return - used = TRUE - var/client/C = pick(candidates) - spawn_antag(C, get_turf(src), href_list["school"],H.mind) - else - to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.") - -/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user) - new /obj/effect/particle_effect/smoke(T) - var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) - C.prefs.copy_to(M) - M.key = C.key - var/datum/mind/app_mind = M.mind - - var/datum/antagonist/wizard/apprentice/app = new() - app.master = user - app.school = kind - - var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard) - if(master_wizard) - if(!master_wizard.wiz_team) - master_wizard.create_wiz_team() - app.wiz_team = master_wizard.wiz_team - master_wizard.wiz_team.add_member(app_mind) - app_mind.add_antag_datum(app) - //TODO Kill these if possible - app_mind.assigned_role = "Apprentice" - app_mind.special_role = "apprentice" - // - SEND_SOUND(M, sound('sound/effects/magic.ogg')) - -///////////BORGS AND OPERATIVES - - -/obj/item/antag_spawner/nuke_ops - name = "syndicate operative teleporter" - desc = "A single-use teleporter designed to quickly reinforce operatives in the field." - icon = 'icons/obj/device.dmi' - icon_state = "locator" - var/borg_to_spawn - -/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user) - if(used) - to_chat(user, "[src] is out of power!") - return FALSE - if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)) - to_chat(user, "AUTHENTICATION FAILURE. ACCESS DENIED.") - return FALSE - if(!user.onSyndieBase()) - to_chat(user, "[src] is out of range! It can only be used at your base!") - return FALSE - return TRUE - - -/obj/item/antag_spawner/nuke_ops/attack_self(mob/user) - if(!(check_usability(user))) - return - - to_chat(user, "You activate [src] and wait for confirmation.") - var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE) - if(LAZYLEN(nuke_candidates)) - if(!(check_usability(user))) - return - used = TRUE - var/client/C = pick(nuke_candidates) - spawn_antag(C, get_turf(src), "syndieborg", user.mind) - do_sparks(4, TRUE, src) - qdel(src) - else - to_chat(user, "Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.") - -/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user) - var/mob/living/carbon/human/M = new/mob/living/carbon/human(T) - C.prefs.copy_to(M) - M.key = C.key - - var/datum/antagonist/nukeop/new_op = new() - new_op.send_to_spawnpoint = FALSE - new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals - - var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE) - if(creator_op) - M.mind.add_antag_datum(new_op,creator_op.nuke_team) - M.mind.special_role = "Nuclear Operative" - -//////SYNDICATE BORG -/obj/item/antag_spawner/nuke_ops/borg_tele - name = "syndicate cyborg teleporter" - desc = "A single-use teleporter designed to quickly reinforce operatives in the field.." - icon = 'icons/obj/device.dmi' - icon_state = "locator" - -/obj/item/antag_spawner/nuke_ops/borg_tele/assault - name = "syndicate assault cyborg teleporter" - borg_to_spawn = "Assault" - -/obj/item/antag_spawner/nuke_ops/borg_tele/medical - name = "syndicate medical teleporter" - borg_to_spawn = "Medical" - -/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user) - var/mob/living/silicon/robot/R - var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE) - if(!creator_op) - return - - switch(borg_to_spawn) - if("Medical") - R = new /mob/living/silicon/robot/modules/syndicate/medical(T) - else - R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default - - var/brainfirstname = pick(GLOB.first_names_male) - if(prob(50)) - brainfirstname = pick(GLOB.first_names_female) - var/brainopslastname = pick(GLOB.last_names) - if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops. - brainopslastname = creator_op.nuke_team.syndicate_name - var/brainopsname = "[brainfirstname] [brainopslastname]" - - R.mmi.name = "Man-Machine Interface: [brainopsname]" - R.mmi.brain.name = "[brainopsname]'s brain" - R.mmi.brainmob.real_name = brainopsname - R.mmi.brainmob.name = brainopsname - R.real_name = R.name - - R.key = C.key - - var/datum/antagonist/nukeop/new_borg = new() - new_borg.send_to_spawnpoint = FALSE - R.mind.add_antag_datum(new_borg,creator_op.nuke_team) - R.mind.special_role = "Syndicate Cyborg" - -///////////SLAUGHTER DEMON - -/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game - name = "vial of blood" - desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures." - icon = 'icons/obj/wizard.dmi' - icon_state = "vial" - - var/shatter_msg = "You shatter the bottle, no turning back now!" - var/veil_msg = "You sense a dark presence lurking just beyond the veil..." - var/objective_verb = "Kill" - var/mob/living/demon_type = /mob/living/simple_animal/slaughter - - -/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user) - if(!is_station_level(user.z)) - to_chat(user, "You should probably wait until you reach the station.") - return - if(used) - return - var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src) - if(LAZYLEN(candidates)) - if(used) - return - used = TRUE - var/client/C = pick(candidates) - spawn_antag(C, get_turf(src), initial(demon_type.name),user.mind) - to_chat(user, shatter_msg) - to_chat(user, veil_msg) - playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1) - qdel(src) - else - to_chat(user, "You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.") - - -/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user) - var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T) - var/mob/living/simple_animal/slaughter/S = new demon_type(holder) - S.holder = holder - S.key = C.key - S.mind.assigned_role = S.name - S.mind.special_role = S.name - var/datum/objective/assassinate/new_objective - if(user) - new_objective = new /datum/objective/assassinate - new_objective.owner = S.mind - new_objective.target = user - new_objective.explanation_text = "[objective_verb] [user.name], the one who summoned you." - S.mind.objectives += new_objective - var/datum/objective/new_objective2 = new /datum/objective - new_objective2.owner = S.mind - new_objective2.explanation_text = "[objective_verb] everyone[user ? " else while you're at it":""]." - S.mind.objectives += new_objective2 - S.mind.add_antag_datum(/datum/antagonist/auto_custom) - to_chat(S, S.playstyle_string) - to_chat(S, "You are currently not currently in the same plane of existence as the station. \ - Ctrl+Click a blood pool to manifest.") - if(new_objective) - to_chat(S, "Objective #[1]: [new_objective.explanation_text]") - to_chat(S, "Objective #[new_objective ? "[2]":"[1]"]: [new_objective2.explanation_text]") - -/obj/item/antag_spawner/slaughter_demon/laughter - name = "vial of tickles" - desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures." - icon = 'icons/obj/wizard.dmi' - icon_state = "vial" - color = "#FF69B4" // HOT PINK - - veil_msg = "You sense an adorable presence lurking just beyond the veil..." - objective_verb = "Hug and Tickle" - demon_type = /mob/living/simple_animal/slaughter/laughter -======= /obj/item/antag_spawner throw_speed = 1 throw_range = 5 @@ -518,4 +250,3 @@ veil_msg = "You sense an adorable presence lurking just beyond the veil..." demon_type = /mob/living/simple_animal/slaughter/laughter antag_type = /datum/antagonist/slaughter/laughter ->>>>>>> 126a544... Slaughter demon, Morph, ERT / Deathsquad antag datums. (#35156) From 1cea674509d1e2f1656af000f4c40bfcee4552a0 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Mon, 5 Feb 2018 21:35:15 -0600 Subject: [PATCH 3/7] Update antag_spawner.dm --- .../antagonists/_common/antag_spawner.dm | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 5695a8c480..b508151d3b 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -2,7 +2,7 @@ throw_speed = 1 throw_range = 5 w_class = WEIGHT_CLASS_TINY - var/used = FALSE + var/used = 0 /obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user) return @@ -57,13 +57,13 @@ to_chat(H, "You already used this contract!") return var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src) - if(LAZYLEN(candidates)) + if(candidates.len) if(used) to_chat(H, "You already used this contract!") return - used = TRUE - var/client/C = pick(candidates) - spawn_antag(C, get_turf(src), href_list["school"],H.mind) + used = 1 + var/mob/dead/observer/theghost = pick(candidates) + spawn_antag(theghost.client, get_turf(src), href_list["school"],H.mind) else to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.") @@ -120,12 +120,12 @@ to_chat(user, "You activate [src] and wait for confirmation.") var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE) - if(LAZYLEN(nuke_candidates)) + if(nuke_candidates.len) if(!(check_usability(user))) return used = TRUE - var/client/C = pick(nuke_candidates) - spawn_antag(C, get_turf(src), "syndieborg", user.mind) + var/mob/dead/observer/theghost = pick(nuke_candidates) + spawn_antag(theghost.client, get_turf(src), "syndieborg", user.mind) do_sparks(4, TRUE, src) qdel(src) else @@ -213,13 +213,13 @@ return if(used) return - var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src) - if(LAZYLEN(candidates)) + var/list/demon_candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", null, null, ROLE_ALIEN, 50, src) + if(demon_candidates.len) if(used) return - used = TRUE - var/client/C = pick(candidates) - spawn_antag(C, get_turf(src), initial(demon_type.name),user.mind) + used = 1 + var/mob/dead/observer/theghost = pick(demon_candidates) + spawn_antag(theghost.client, get_turf(src), initial(demon_type.name),user.mind) to_chat(user, shatter_msg) to_chat(user, veil_msg) playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1) From 79cb10f8ec6f2b9d9ca57f4b8a20fdb8fefd196e Mon Sep 17 00:00:00 2001 From: Poojawa Date: Tue, 6 Feb 2018 09:49:46 -0600 Subject: [PATCH 4/7] Update morph.dm --- code/modules/antagonists/morph/morph.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm index 52f9682717..145a135a4e 100644 --- a/code/modules/antagonists/morph/morph.dm +++ b/code/modules/antagonists/morph/morph.dm @@ -126,6 +126,7 @@ form = null alpha = initial(alpha) color = initial(color) + maptext = null visible_message("[src] suddenly collapses in on itself, dissolving into a pile of green flesh!", \ "You reform to your normal body.") @@ -226,7 +227,7 @@ player_mind.transfer_to(S) player_mind.assigned_role = "Morph" player_mind.special_role = "Morph" - player_mind.add_antag_datum(/datum/antagonist/auto_custom) + player_mind.add_antag_datum(/datum/antagonist/morph) to_chat(S, S.playstyle_string) SEND_SOUND(S, sound('sound/magic/mutate.ogg')) message_admins("[key_name_admin(S)] has been made into a morph by an event.") From 35dcf5dce11696048c4f50092c2697b2d7156acd Mon Sep 17 00:00:00 2001 From: Poojawa Date: Tue, 6 Feb 2018 09:50:12 -0600 Subject: [PATCH 5/7] Update slaughter.dm --- .../antagonists/slaughter/slaughter.dm | 219 +++--------------- 1 file changed, 38 insertions(+), 181 deletions(-) diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index e8eb95aa7b..175e8ad31e 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -1,190 +1,47 @@ -//////////////////The Monster - -/mob/living/simple_animal/slaughter - name = "slaughter demon" - real_name = "slaughter demon" - desc = "A large, menacing creature covered in armored black scales." - speak_emote = list("gurgles") - emote_hear = list("wails","screeches") - response_help = "thinks better of touching" - response_disarm = "flails at" - response_harm = "punches" - icon = 'icons/mob/mob.dmi' - icon_state = "daemon" - icon_living = "daemon" - speed = 1 - a_intent = INTENT_HARM - stop_automated_movement = 1 - status_flags = CANPUSH - attack_sound = 'sound/magic/demon_attack1.ogg' - var/feast_sound = 'sound/magic/demon_consume.ogg' - death_sound = 'sound/magic/demon_dies.ogg' - atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = INFINITY - faction = list("slaughter") - attacktext = "wildly tears into" - maxHealth = 200 - health = 200 - healable = 0 - environment_smash = ENVIRONMENT_SMASH_STRUCTURES - obj_damage = 50 - melee_damage_lower = 30 - melee_damage_upper = 30 - see_in_dark = 8 - lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE - var/boost = 0 - bloodcrawl = BLOODCRAWL_EAT - var/playstyle_string = "You are a slaughter demon, a terrible creature from another realm. You have a single desire: To kill. \ - You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and disappearing from the station at will. \ - Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \ - You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. " - - loot = list(/obj/effect/decal/cleanable/blood, \ - /obj/effect/decal/cleanable/blood/innards, \ - /obj/item/organ/heart/demon) - del_on_death = 1 - deathmessage = "screams in anger as it collapses into a puddle of viscera!" - -/mob/living/simple_animal/slaughter/Initialize() - ..() - var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new - AddSpell(bloodspell) - if(istype(loc, /obj/effect/dummy/slaughter)) - bloodspell.phased = 1 - -/mob/living/simple_animal/slaughter/Life() - ..() - if(boost[user] raises [src] to their mouth and tears into it with their teeth!", \ - "An unnatural hunger consumes you. You raise [src] your mouth and devour it!") - playsound(user, 'sound/magic/demon_consume.ogg', 50, 1) - for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list) - if(knownspell.type == /obj/effect/proc_holder/spell/bloodcrawl) - to_chat(user, "...and you don't feel any different.") - qdel(src) - return - user.visible_message("[user]'s eyes flare a deep crimson!", \ - "You feel a strange power seep into your body... you have absorbed the demon's blood-travelling powers!") - user.temporarilyRemoveItemFromInventory(src, TRUE) - src.Insert(user) //Consuming the heart literally replaces your heart with a demon heart. H A R D C O R E +/datum/round_event/ghost_role/slaughter/spawn_role() + var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS -/obj/item/organ/heart/demon/Insert(mob/living/carbon/M, special = 0) - ..() - if(M.mind) - M.mind.AddSpell(new /obj/effect/proc_holder/spell/bloodcrawl(null)) + var/mob/dead/selected = pick_n_take(candidates) -/obj/item/organ/heart/demon/Remove(mob/living/carbon/M, special = 0) - ..() - if(M.mind) - M.mind.RemoveSpell(/obj/effect/proc_holder/spell/bloodcrawl) + var/datum/mind/player_mind = new /datum/mind(selected.key) + player_mind.active = 1 -/obj/item/organ/heart/demon/Stop() - return 0 // Always beating. + var/list/spawn_locs = list() + for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) + if(isturf(L.loc)) + spawn_locs += L.loc -/mob/living/simple_animal/slaughter/laughter - // The laughter demon! It's everyone's best friend! It just wants to hug - // them so much, it wants to hug everyone at once! - name = "laughter demon" - real_name = "laughter demon" - desc = "A large, adorable creature covered in armor with pink bows." - speak_emote = list("giggles","titters","chuckles") - emote_hear = list("guffaws","laughs") - response_help = "hugs" - attacktext = "wildly tickles" + if(!spawn_locs) + message_admins("No valid spawn locations found, aborting...") + return MAP_ERROR - attack_sound = 'sound/items/bikehorn.ogg' - feast_sound = 'sound/spookoween/scary_horn2.ogg' - death_sound = 'sound/misc/sadtrombone.ogg' - - icon_state = "bowmon" - icon_living = "bowmon" - deathmessage = "fades out, as all of its friends are released from its \ - prison of hugs." - loot = list(/mob/living/simple_animal/pet/cat/kitten{name = "Laughter"}) - - // Keep the people we hug! - var/list/consumed_mobs = list() - - playstyle_string = "You are a laughter \ - demon, a wonderful creature from another realm. You have a single \ - desire: To hug and tickle.
\ - You may use the \"Blood Crawl\" ability near blood pools to travel \ - through them, appearing and disappearing from the station at will. \ - Pulling a dead or unconscious mob while you enter a pool will pull \ - them in with you, allowing you to hug them and regain your health.
\ - You move quickly upon leaving a pool of blood, but the material world \ - will soon sap your strength and leave you sluggish.
\ - What makes you a little sad is that people seem to die when you tickle \ - them; but don't worry! When you die, everyone you hugged will be \ - released and fully healed, because in the end it's just a jape, \ - sibling!
" - -/mob/living/simple_animal/slaughter/laughter/Destroy() - release_friends() - . = ..() - -/mob/living/simple_animal/slaughter/laughter/ex_act(severity) - switch(severity) - if(1) - death() - if(2) - adjustBruteLoss(60) - if(3) - adjustBruteLoss(30) - -/mob/living/simple_animal/slaughter/laughter/proc/release_friends() - if(!consumed_mobs) - return - - for(var/mob/living/M in consumed_mobs) - if(!M) - continue - var/turf/T = find_safe_turf() - if(!T) - T = get_turf(src) - M.forceMove(T) - if(M.revive(full_heal = TRUE, admin_revive = TRUE)) - M.grab_ghost(force = TRUE) - playsound(T, feast_sound, 50, 1, -1) - to_chat(M, "You leave [src]'s warm embrace, and feel ready to take on the world.") - -/mob/living/simple_animal/slaughter/laughter/bloodcrawl_swallow(var/mob/living/victim) - if(consumed_mobs) - // Keep their corpse so rescue is possible - consumed_mobs += victim - else - // Be safe and just eject the corpse - victim.forceMove(get_turf(victim)) - victim.exit_blood_effect() - victim.visible_message("[victim] falls out of the air, covered in blood, looking highly confused. And dead.") + var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter((pick(spawn_locs))) + var/mob/living/simple_animal/slaughter/S = new (holder) + S.holder = holder + player_mind.transfer_to(S) + player_mind.assigned_role = "Slaughter Demon" + player_mind.special_role = "Slaughter Demon" + player_mind.add_antag_datum(/datum/antagonist/slaughter) + to_chat(S, S.playstyle_string) + to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") + SEND_SOUND(S, 'sound/magic/demon_dies.ogg') + message_admins("[key_name_admin(S)] has been made into a slaughter demon by an event.") + log_game("[key_name(S)] was spawned as a slaughter demon by an event.") + spawned_mobs += S + return SUCCESSFUL_SPAWN From 1bf0cdac64c1aa352095643ab637f1602ceb4520 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Tue, 6 Feb 2018 09:56:10 -0600 Subject: [PATCH 6/7] Update slaughterevent.dm --- code/modules/antagonists/slaughter/slaughterevent.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index 1af01e05ea..175e8ad31e 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -37,7 +37,7 @@ player_mind.transfer_to(S) player_mind.assigned_role = "Slaughter Demon" player_mind.special_role = "Slaughter Demon" - player_mind.add_antag_datum(/datum/antagonist/auto_custom) + player_mind.add_antag_datum(/datum/antagonist/slaughter) to_chat(S, S.playstyle_string) to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") SEND_SOUND(S, 'sound/magic/demon_dies.ogg') From 1d4e0d3511955c60cedc116f7ac29dc7d35c3782 Mon Sep 17 00:00:00 2001 From: Poojawa Date: Tue, 6 Feb 2018 09:56:36 -0600 Subject: [PATCH 7/7] Oops, copy paste fail --- .../antagonists/slaughter/slaughter.dm | 219 +++++++++++++++--- 1 file changed, 181 insertions(+), 38 deletions(-) diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm index 175e8ad31e..e8eb95aa7b 100644 --- a/code/modules/antagonists/slaughter/slaughter.dm +++ b/code/modules/antagonists/slaughter/slaughter.dm @@ -1,47 +1,190 @@ -/datum/round_event_control/slaughter - name = "Spawn Slaughter Demon" - typepath = /datum/round_event/ghost_role/slaughter - weight = 1 //Very rare - max_occurrences = 1 - earliest_start = 36000 //1 hour - min_players = 20 +//////////////////The Monster + +/mob/living/simple_animal/slaughter + name = "slaughter demon" + real_name = "slaughter demon" + desc = "A large, menacing creature covered in armored black scales." + speak_emote = list("gurgles") + emote_hear = list("wails","screeches") + response_help = "thinks better of touching" + response_disarm = "flails at" + response_harm = "punches" + icon = 'icons/mob/mob.dmi' + icon_state = "daemon" + icon_living = "daemon" + speed = 1 + a_intent = INTENT_HARM + stop_automated_movement = 1 + status_flags = CANPUSH + attack_sound = 'sound/magic/demon_attack1.ogg' + var/feast_sound = 'sound/magic/demon_consume.ogg' + death_sound = 'sound/magic/demon_dies.ogg' + atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minbodytemp = 0 + maxbodytemp = INFINITY + faction = list("slaughter") + attacktext = "wildly tears into" + maxHealth = 200 + health = 200 + healable = 0 + environment_smash = ENVIRONMENT_SMASH_STRUCTURES + obj_damage = 50 + melee_damage_lower = 30 + melee_damage_upper = 30 + see_in_dark = 8 + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + var/boost = 0 + bloodcrawl = BLOODCRAWL_EAT + var/playstyle_string = "You are a slaughter demon, a terrible creature from another realm. You have a single desire: To kill. \ + You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and disappearing from the station at will. \ + Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \ + You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. " + + loot = list(/obj/effect/decal/cleanable/blood, \ + /obj/effect/decal/cleanable/blood/innards, \ + /obj/item/organ/heart/demon) + del_on_death = 1 + deathmessage = "screams in anger as it collapses into a puddle of viscera!" + +/mob/living/simple_animal/slaughter/Initialize() + ..() + var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new + AddSpell(bloodspell) + if(istype(loc, /obj/effect/dummy/slaughter)) + bloodspell.phased = 1 + +/mob/living/simple_animal/slaughter/Life() + ..() + if(boost[user] raises [src] to their mouth and tears into it with their teeth!", \ + "An unnatural hunger consumes you. You raise [src] your mouth and devour it!") + playsound(user, 'sound/magic/demon_consume.ogg', 50, 1) + for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list) + if(knownspell.type == /obj/effect/proc_holder/spell/bloodcrawl) + to_chat(user, "...and you don't feel any different.") + qdel(src) + return + user.visible_message("[user]'s eyes flare a deep crimson!", \ + "You feel a strange power seep into your body... you have absorbed the demon's blood-travelling powers!") + user.temporarilyRemoveItemFromInventory(src, TRUE) + src.Insert(user) //Consuming the heart literally replaces your heart with a demon heart. H A R D C O R E - var/mob/dead/selected = pick_n_take(candidates) +/obj/item/organ/heart/demon/Insert(mob/living/carbon/M, special = 0) + ..() + if(M.mind) + M.mind.AddSpell(new /obj/effect/proc_holder/spell/bloodcrawl(null)) - var/datum/mind/player_mind = new /datum/mind(selected.key) - player_mind.active = 1 +/obj/item/organ/heart/demon/Remove(mob/living/carbon/M, special = 0) + ..() + if(M.mind) + M.mind.RemoveSpell(/obj/effect/proc_holder/spell/bloodcrawl) - var/list/spawn_locs = list() - for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list) - if(isturf(L.loc)) - spawn_locs += L.loc +/obj/item/organ/heart/demon/Stop() + return 0 // Always beating. - if(!spawn_locs) - message_admins("No valid spawn locations found, aborting...") - return MAP_ERROR +/mob/living/simple_animal/slaughter/laughter + // The laughter demon! It's everyone's best friend! It just wants to hug + // them so much, it wants to hug everyone at once! + name = "laughter demon" + real_name = "laughter demon" + desc = "A large, adorable creature covered in armor with pink bows." + speak_emote = list("giggles","titters","chuckles") + emote_hear = list("guffaws","laughs") + response_help = "hugs" + attacktext = "wildly tickles" - var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter((pick(spawn_locs))) - var/mob/living/simple_animal/slaughter/S = new (holder) - S.holder = holder - player_mind.transfer_to(S) - player_mind.assigned_role = "Slaughter Demon" - player_mind.special_role = "Slaughter Demon" - player_mind.add_antag_datum(/datum/antagonist/slaughter) - to_chat(S, S.playstyle_string) - to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.") - SEND_SOUND(S, 'sound/magic/demon_dies.ogg') - message_admins("[key_name_admin(S)] has been made into a slaughter demon by an event.") - log_game("[key_name(S)] was spawned as a slaughter demon by an event.") - spawned_mobs += S - return SUCCESSFUL_SPAWN + attack_sound = 'sound/items/bikehorn.ogg' + feast_sound = 'sound/spookoween/scary_horn2.ogg' + death_sound = 'sound/misc/sadtrombone.ogg' + + icon_state = "bowmon" + icon_living = "bowmon" + deathmessage = "fades out, as all of its friends are released from its \ + prison of hugs." + loot = list(/mob/living/simple_animal/pet/cat/kitten{name = "Laughter"}) + + // Keep the people we hug! + var/list/consumed_mobs = list() + + playstyle_string = "You are a laughter \ + demon, a wonderful creature from another realm. You have a single \ + desire: To hug and tickle.
\ + You may use the \"Blood Crawl\" ability near blood pools to travel \ + through them, appearing and disappearing from the station at will. \ + Pulling a dead or unconscious mob while you enter a pool will pull \ + them in with you, allowing you to hug them and regain your health.
\ + You move quickly upon leaving a pool of blood, but the material world \ + will soon sap your strength and leave you sluggish.
\ + What makes you a little sad is that people seem to die when you tickle \ + them; but don't worry! When you die, everyone you hugged will be \ + released and fully healed, because in the end it's just a jape, \ + sibling!
" + +/mob/living/simple_animal/slaughter/laughter/Destroy() + release_friends() + . = ..() + +/mob/living/simple_animal/slaughter/laughter/ex_act(severity) + switch(severity) + if(1) + death() + if(2) + adjustBruteLoss(60) + if(3) + adjustBruteLoss(30) + +/mob/living/simple_animal/slaughter/laughter/proc/release_friends() + if(!consumed_mobs) + return + + for(var/mob/living/M in consumed_mobs) + if(!M) + continue + var/turf/T = find_safe_turf() + if(!T) + T = get_turf(src) + M.forceMove(T) + if(M.revive(full_heal = TRUE, admin_revive = TRUE)) + M.grab_ghost(force = TRUE) + playsound(T, feast_sound, 50, 1, -1) + to_chat(M, "You leave [src]'s warm embrace, and feel ready to take on the world.") + +/mob/living/simple_animal/slaughter/laughter/bloodcrawl_swallow(var/mob/living/victim) + if(consumed_mobs) + // Keep their corpse so rescue is possible + consumed_mobs += victim + else + // Be safe and just eject the corpse + victim.forceMove(get_turf(victim)) + victim.exit_blood_effect() + victim.visible_message("[victim] falls out of the air, covered in blood, looking highly confused. And dead.")