mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-22 20:48:56 +01:00
[MANUAL MIRROR] Better groups for antagonists (#18839)
* Better groups for antagonists (#72576) Better categorizes antagonists into groups for the orbit UI, admin traitor panel. Permanently hostile antags were intermixed in the "Alive" section, and it was sometimes tough to see what's going on. To do this, many minor antags needed new antag datums which were added with fluff objectives as a bonus. Group Name | Antags --- | --- Syndicate | Nukies, battlecruiser crew, lone op Extradimensional Abominations | Nightmare⭐, morph⭐, pyro slime⭐ Spaceborne Leviathans | Space dragon, (spawned) carps⭐ Invasive Overgrowth | Venus human traps⭐ Arachnid Infestation | Spiders⭐ Eldritch Horrors | Cult constructs⭐, revenant (⭐ = New antag datum, proper orbit category, new objective text) <details> <summary>Screenshots (outdated)</summary> Antags get more tooltip info  Populating space dragon + carps (now leviathans)  Detail to distinguish job & rank  New categories in action  Organized Traitor Panel  </details> Better UI, observer experience, admin panel. It's now very obvious when something is hostile from the orbit panel. 🆑 qol: The orbit menu now sorts antagonists into groups more effectively. Some get new named groups. admin: Traitor panel should have slightly more sane categories. add: Many minor antagonists now have "objectives". refactor: Refactors code in several antag datums. /🆑 Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> * Fixes the compile issues * Also puts the drifting contractor in the syndicate group in the antag panel --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
This commit is contained in:
co-authored by
LemonInTheDark
Jeremiah
GoldenAlpharex
parent
50f6fb6716
commit
4999bdfd19
@@ -73,14 +73,92 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/Topic(href,href_list)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
//Some commands might delete/modify this datum clearing or changing owner
|
||||
var/datum/mind/persistent_owner = owner
|
||||
|
||||
var/commands = get_admin_commands()
|
||||
var/admin_command = href_list["command"]
|
||||
if(!(admin_command in commands))
|
||||
return
|
||||
var/datum/callback/call_async = commands[admin_command]
|
||||
call_async.Invoke(usr)
|
||||
persistent_owner.traitor_panel()
|
||||
|
||||
//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
|
||||
var/datum/team/custom_team
|
||||
|
||||
/datum/antagonist/custom/create_team(datum/team/team)
|
||||
custom_team = team
|
||||
|
||||
/datum/antagonist/custom/get_team()
|
||||
return custom_team
|
||||
|
||||
/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin)
|
||||
var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist")
|
||||
if(!custom_name)
|
||||
return
|
||||
name = custom_name
|
||||
..()
|
||||
|
||||
///ANTAGONIST UI STUFF
|
||||
|
||||
/datum/antagonist/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_name, name)
|
||||
ui.open()
|
||||
|
||||
/datum/antagonist/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/antagonist/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["antag_name"] = name
|
||||
data["objectives"] = get_objectives()
|
||||
return data
|
||||
|
||||
//button for antags to review their descriptions/info
|
||||
/datum/action/antag_info
|
||||
name = "Open Antag Information:"
|
||||
button_icon_state = "round_end"
|
||||
show_to_observers = FALSE
|
||||
|
||||
/datum/action/antag_info/New(Target)
|
||||
. = ..()
|
||||
name += " [target]"
|
||||
|
||||
/datum/action/antag_info/Trigger(trigger_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
target.ui_interact(owner)
|
||||
|
||||
/datum/action/antag_info/IsAvailable(feedback = FALSE)
|
||||
if(!target)
|
||||
stack_trace("[type] was used without a target antag datum!")
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!owner.mind || !(target in owner.mind.antag_datums))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
|
||||
. = TRUE
|
||||
var/datum/mind/tested = new_owner || owner
|
||||
if(tested.has_antag_datum(type))
|
||||
return FALSE
|
||||
for(var/i in tested.antag_datums)
|
||||
var/datum/antagonist/A = i
|
||||
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
|
||||
for(var/datum/antagonist/badguy as anything in tested.antag_datums)
|
||||
if(is_type_in_typecache(src, badguy.typecache_datum_blacklist))
|
||||
return FALSE
|
||||
|
||||
//This will be called in add_antag_datum before owner assignment.
|
||||
@@ -171,12 +249,12 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
* Proc that checks the sent mob aganst the banlistfor this antagonist.
|
||||
* Returns FALSE if no mob is sent, or the mob is not found to be banned.
|
||||
*
|
||||
* * mob/M: The mob that you are looking for on the banlist.
|
||||
* * mob/player: The mob that you are looking for on the banlist.
|
||||
*/
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
/datum/antagonist/proc/is_banned(mob/player)
|
||||
if(!player)
|
||||
return FALSE
|
||||
. = (is_banned_from(M.ckey, list(ROLE_SYNDICATE, job_rank)) || QDELETED(M))
|
||||
. = (is_banned_from(player.ckey, list(ROLE_SYNDICATE, job_rank)) || QDELETED(player))
|
||||
|
||||
/**
|
||||
* Proc that replaces a player who cannot play a specific antagonist due to being banned via a poll, and alerts the player of their being on the banlist.
|
||||
@@ -336,9 +414,9 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
/datum/antagonist/proc/antag_panel_data()
|
||||
return ""
|
||||
|
||||
/datum/antagonist/proc/enabled_in_preferences(datum/mind/M)
|
||||
/datum/antagonist/proc/enabled_in_preferences(datum/mind/noggin)
|
||||
if(job_rank)
|
||||
if(M.current && M.current.client && (job_rank in M.current.client.prefs.be_special))
|
||||
if(noggin.current && noggin.current.client && (job_rank in noggin.current.client.prefs.be_special))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
@@ -383,21 +461,6 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
return finish_preview_icon(render_preview_outfit(preview_outfit))
|
||||
|
||||
/datum/antagonist/Topic(href,href_list)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
//Some commands might delete/modify this datum clearing or changing owner
|
||||
var/datum/mind/persistent_owner = owner
|
||||
|
||||
var/commands = get_admin_commands()
|
||||
for(var/admin_command in commands)
|
||||
if(href_list["command"] == admin_command)
|
||||
var/datum/callback/C = commands[admin_command]
|
||||
C.Invoke(usr)
|
||||
persistent_owner.traitor_panel()
|
||||
return
|
||||
|
||||
/datum/antagonist/proc/edit_memory(mob/user)
|
||||
var/new_memo = tgui_input_text(user, "Write a new memory", "Antag Memory", antag_memory, multiline = TRUE)
|
||||
if (isnull(new_memo))
|
||||
@@ -435,37 +498,6 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
SET_PLANE_EXPLICIT(hud, ABOVE_GAME_PLANE, hud_loc)
|
||||
return hud
|
||||
|
||||
//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
|
||||
var/datum/team/custom_team
|
||||
|
||||
/datum/antagonist/custom/create_team(datum/team/team)
|
||||
custom_team = team
|
||||
|
||||
/datum/antagonist/custom/get_team()
|
||||
return custom_team
|
||||
|
||||
/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin)
|
||||
var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist")
|
||||
if(custom_name)
|
||||
name = custom_name
|
||||
else
|
||||
return
|
||||
..()
|
||||
|
||||
///ANTAGONIST UI STUFF
|
||||
|
||||
/datum/antagonist/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_name, name)
|
||||
ui.open()
|
||||
|
||||
/datum/antagonist/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
///generic helper to send objectives as data through tgui.
|
||||
/datum/antagonist/proc/get_objectives()
|
||||
var/objective_count = 1
|
||||
@@ -481,39 +513,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
objective_count++
|
||||
return objective_data
|
||||
|
||||
/datum/antagonist/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["antag_name"] = name
|
||||
data["objectives"] = get_objectives()
|
||||
return data
|
||||
/// Used to create objectives for the antagonist.
|
||||
/datum/antagonist/proc/forge_objectives()
|
||||
return
|
||||
|
||||
//button for antags to review their descriptions/info
|
||||
|
||||
/datum/action/antag_info
|
||||
name = "Open Antag Information:"
|
||||
button_icon_state = "round_end"
|
||||
show_to_observers = FALSE
|
||||
|
||||
/datum/action/antag_info/New(Target)
|
||||
. = ..()
|
||||
name += " [target]"
|
||||
|
||||
/datum/action/antag_info/Trigger(trigger_flags)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
target.ui_interact(owner)
|
||||
|
||||
/datum/action/antag_info/IsAvailable(feedback = FALSE)
|
||||
if(!target)
|
||||
stack_trace("[type] was used without a target antag datum!")
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(!owner.mind)
|
||||
return FALSE
|
||||
if(!(target in owner.mind.antag_datums))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/datum/antagonist/abductee
|
||||
name = "\improper Abductee"
|
||||
roundend_category = "abductees"
|
||||
antagpanel_category = "Other"
|
||||
antagpanel_category = ANTAG_GROUP_ABDUCTORS
|
||||
antag_hud_name = "abductee"
|
||||
|
||||
/datum/antagonist/abductee/on_gain()
|
||||
@@ -21,5 +21,5 @@
|
||||
|
||||
/datum/antagonist/abductee/proc/give_objective()
|
||||
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
|
||||
var/datum/objective/abductee/O = new objtype()
|
||||
objectives += O
|
||||
var/datum/objective/abductee/objective = new objtype()
|
||||
objectives += objective
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/datum/antagonist/abductor
|
||||
name = "\improper Abductor"
|
||||
roundend_category = "abductors"
|
||||
antagpanel_category = "Abductor"
|
||||
antagpanel_category = ANTAG_GROUP_ABDUCTORS
|
||||
job_rank = ROLE_ABDUCTOR
|
||||
antag_hud_name = "abductor"
|
||||
show_in_antagpanel = FALSE //should only show subtypes
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
prevent_roundtype_conversion = FALSE
|
||||
antagpanel_category = "Ash Walkers"
|
||||
antagpanel_category = ANTAG_GROUP_ASHWALKERS
|
||||
suicide_cry = "I HAVE NO IDEA WHAT THIS THING DOES!!"
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
var/datum/team/ashwalkers/ashie_team
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/datum/team/battlecruiser
|
||||
name = "\improper Battlecruiser Crew"
|
||||
member_name = "crewmember"
|
||||
/// The central objective of this battlecruiser
|
||||
var/core_objective = /datum/objective/nuclear
|
||||
/// The assigned nuke of this team
|
||||
var/obj/machinery/nuclearbomb/nuke
|
||||
|
||||
/datum/team/battlecruiser/proc/update_objectives()
|
||||
if(core_objective)
|
||||
var/datum/objective/objective = new core_objective()
|
||||
objective.team = src
|
||||
objectives += objective
|
||||
|
||||
/datum/antagonist/battlecruiser
|
||||
name = "Battlecruiser Crewmember"
|
||||
show_to_ghosts = TRUE
|
||||
roundend_category = "battlecruiser syndicate operatives"
|
||||
suicide_cry = "FOR THE SYNDICATE!!!"
|
||||
antag_hud_name = "battlecruiser_crew"
|
||||
antagpanel_category = ANTAG_GROUP_SYNDICATE
|
||||
job_rank = ROLE_BATTLECRUISER_CREW
|
||||
/// Team to place the crewmember on.
|
||||
var/datum/team/battlecruiser/battlecruiser_team
|
||||
|
||||
/datum/antagonist/battlecruiser/get_team()
|
||||
return battlecruiser_team
|
||||
|
||||
/datum/antagonist/battlecruiser/greet()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE)
|
||||
to_chat(owner, span_big("You are a [name]!"))
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/battlecruiser/ally
|
||||
name = "Battlecruiser Ally"
|
||||
show_to_ghosts = FALSE
|
||||
|
||||
/datum/antagonist/battlecruiser/captain
|
||||
name = "Battlecruiser Captain"
|
||||
antag_hud_name = "battlecruiser_lead"
|
||||
job_rank = ROLE_BATTLECRUISER_CAPTAIN
|
||||
|
||||
/datum/antagonist/battlecruiser/create_team(datum/team/battlecruiser/team)
|
||||
if(!team)
|
||||
return
|
||||
if(!istype(team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
battlecruiser_team = team
|
||||
|
||||
/datum/antagonist/battlecruiser/apply_innate_effects(mob/living/mob_override)
|
||||
add_team_hud(mob_override || owner.current, /datum/antagonist/battlecruiser)
|
||||
|
||||
/datum/antagonist/battlecruiser/on_gain()
|
||||
if(!battlecruiser_team)
|
||||
return ..()
|
||||
|
||||
objectives |= battlecruiser_team.objectives
|
||||
if(battlecruiser_team.nuke)
|
||||
var/obj/machinery/nuclearbomb/nuke = battlecruiser_team.nuke
|
||||
antag_memory += "<B>[nuke] Code</B>: [nuke.r_code]<br>"
|
||||
owner.add_memory(/datum/memory/key/nuke_code, nuclear_code = nuke.r_code)
|
||||
to_chat(owner, "The nuclear authorization code is: <B>[nuke.r_code]</B>")
|
||||
return ..()
|
||||
@@ -1,8 +1,9 @@
|
||||
/datum/antagonist/blob
|
||||
name = "\improper Blob"
|
||||
roundend_category = "blobs"
|
||||
antagpanel_category = "Biohazards"
|
||||
antagpanel_category = ANTAG_GROUP_BIOHAZARDS
|
||||
show_to_ghosts = TRUE
|
||||
show_in_antagpanel = FALSE
|
||||
job_rank = ROLE_BLOB
|
||||
ui_name = "AntagInfoBlob"
|
||||
/// Action to release a blob infection
|
||||
@@ -140,6 +141,8 @@
|
||||
|
||||
/// A subtype of blob meant to represent the infective version.
|
||||
/datum/antagonist/blob/infection
|
||||
name = "\improper Blob Infection"
|
||||
show_in_antagpanel = TRUE
|
||||
job_rank = ROLE_BLOB_INFECTION
|
||||
|
||||
/datum/antagonist/blob/infection/get_preview_icon()
|
||||
@@ -0,0 +1,42 @@
|
||||
/datum/antagonist/blob_minion
|
||||
name = "\improper Blob Minion"
|
||||
antagpanel_category = ANTAG_GROUP_BIOHAZARDS
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
show_in_antagpanel = FALSE
|
||||
/// The blob core that this minion is attached to
|
||||
var/datum/weakref/overmind
|
||||
|
||||
/datum/antagonist/blob_minion/New(mob/camera/blob/overmind)
|
||||
. = ..()
|
||||
src.overmind = WEAKREF(overmind)
|
||||
|
||||
/datum/antagonist/blob_minion/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/blob_minion/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
/datum/objective/blob_minion
|
||||
name = "protect the blob core"
|
||||
explanation_text = "Protect the blob core at all costs."
|
||||
var/datum/weakref/overmind
|
||||
|
||||
/datum/objective/blob_minion/check_completion()
|
||||
var/mob/camera/blob/resolved_overmind = overmind.resolve()
|
||||
if(!resolved_overmind)
|
||||
return FALSE
|
||||
return resolved_overmind.stat != DEAD
|
||||
|
||||
/datum/antagonist/blob_minion/forge_objectives()
|
||||
var/datum/objective/blob_minion/objective = new
|
||||
objective.owner = owner
|
||||
objective.overmind = overmind
|
||||
objectives += objective
|
||||
|
||||
/datum/antagonist/blob_minion/blobbernaut
|
||||
name = "\improper Blobbernaut"
|
||||
|
||||
/datum/antagonist/blob_minion/blob_zombie
|
||||
name = "\improper Blob Zombie"
|
||||
@@ -667,9 +667,7 @@
|
||||
|
||||
add_new_profile(owner.current)
|
||||
|
||||
|
||||
/// Generate objectives for our changeling.
|
||||
/datum/antagonist/changeling/proc/forge_objectives()
|
||||
/datum/antagonist/changeling/forge_objectives()
|
||||
//OBJECTIVES - random traitor objectives. Unique objectives "steal brain" and "identity theft".
|
||||
//No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting
|
||||
//If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
/datum/antagonist/nukeop/clownop
|
||||
name = ROLE_CLOWN_OPERATIVE
|
||||
roundend_category = "clown operatives"
|
||||
antagpanel_category = "ClownOp"
|
||||
antagpanel_category = ANTAG_GROUP_CLOWNOPS
|
||||
nukeop_outfit = /datum/outfit/syndicate/clownop
|
||||
suicide_cry = "HAPPY BIRTHDAY!!"
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
/datum/antagonist/nukeop/leader/clownop
|
||||
name = "Clown Operative Leader"
|
||||
roundend_category = "clown operatives"
|
||||
antagpanel_category = "ClownOp"
|
||||
antagpanel_category = ANTAG_GROUP_CLOWNOPS
|
||||
nukeop_outfit = /datum/outfit/syndicate/clownop/leader
|
||||
challengeitem = /obj/item/nuclear_challenge/clownops
|
||||
suicide_cry = "HAPPY BIRTHDAY!!"
|
||||
@@ -0,0 +1,6 @@
|
||||
/datum/antagonist/cult/construct
|
||||
name = "\improper Cult Construct"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
antagpanel_category = ANTAG_GROUP_HORRORS
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/antagonist/disease
|
||||
name = "Sentient Disease"
|
||||
roundend_category = "diseases"
|
||||
antagpanel_category = "Biohazards"
|
||||
antagpanel_category = ANTAG_GROUP_BIOHAZARDS
|
||||
show_to_ghosts = TRUE
|
||||
var/disease_name = ""
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
antagpanel_category = ANTAG_GROUP_ERT
|
||||
suicide_cry = "FOR NANOTRASEN!!"
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
var/datum/team/ert/ert_team
|
||||
@@ -223,7 +224,7 @@
|
||||
role = "Synthetic Bounty Hunter"
|
||||
outfit = /datum/outfit/bountysynth/ert
|
||||
|
||||
/datum/antagonist/ert/proc/forge_objectives()
|
||||
/datum/antagonist/ert/forge_objectives()
|
||||
if(ert_team)
|
||||
objectives |= ert_team.objectives
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/fugitive/proc/forge_objectives() //this isn't the actual survive objective because it's about who in the team survives
|
||||
/datum/antagonist/fugitive/forge_objectives() //this isn't the actual survive objective because it's about who in the team survives
|
||||
var/datum/objective/survive = new /datum/objective
|
||||
survive.owner = owner
|
||||
survive.explanation_text = "Avoid capture from the fugitive hunters."
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/fugitive_hunter/proc/forge_objectives() //this isn't an actual objective because it's about round end rosters
|
||||
/datum/antagonist/fugitive_hunter/forge_objectives() //this isn't an actual objective because it's about round end rosters
|
||||
var/datum/objective/capture = new /datum/objective
|
||||
capture.owner = owner
|
||||
capture.explanation_text = "Capture the fugitives in the station and put them into the bluespace capture machine on your ship."
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
suicide_cry = "FOR THE GREENTEXT!!" // This can never actually show up, but not including it is a missed opportunity
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
|
||||
/datum/antagonist/greentext/proc/forge_objectives()
|
||||
/datum/antagonist/greentext/forge_objectives()
|
||||
var/datum/objective/succeed_objective = new /datum/objective("Succeed")
|
||||
succeed_objective.completed = TRUE //YES!
|
||||
succeed_objective.owner = owner
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/datum/antagonist/heretic_monster
|
||||
name = "\improper Eldritch Horror"
|
||||
roundend_category = "Heretics"
|
||||
antagpanel_category = "Heretic Beast"
|
||||
antagpanel_category = ANTAG_GROUP_HORRORS
|
||||
antag_moodlet = /datum/mood_event/heretics
|
||||
job_rank = ROLE_HERETIC
|
||||
antag_hud_name = "heretic_beast"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
if(L.has_quirk(/datum/quirk/nonviolent))
|
||||
ADD_TRAIT(L, TRAIT_PACIFISM, ROUNDSTART_TRAIT)
|
||||
|
||||
/datum/antagonist/highlander/proc/forge_objectives()
|
||||
/datum/antagonist/highlander/forge_objectives()
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.set_target(new /datum/objective_item/steal/nukedisc)
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
show_in_antagpanel = FALSE
|
||||
antagpanel_category = ANTAG_GROUP_ABOMINATIONS
|
||||
ui_name = "AntagInfoMorph"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/antagonist/nightmare
|
||||
name = "\improper Nightmare"
|
||||
antagpanel_category = "Nightmare"
|
||||
antagpanel_category = ANTAG_GROUP_ABOMINATIONS
|
||||
job_rank = ROLE_NIGHTMARE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
@@ -9,8 +9,39 @@
|
||||
suicide_cry = "FOR THE DARKNESS!!"
|
||||
preview_outfit = /datum/outfit/nightmare
|
||||
|
||||
/datum/antagonist/nightmare/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/nightmare/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/outfit/nightmare
|
||||
name = "Nightmare (Preview only)"
|
||||
|
||||
/datum/outfit/nightmare/post_equip(mob/living/carbon/human/human, visualsOnly)
|
||||
human.set_species(/datum/species/shadow/nightmare)
|
||||
|
||||
/datum/objective/nightmare_fluff
|
||||
|
||||
/datum/objective/nightmare_fluff/New()
|
||||
var/list/explanation_texts = list(
|
||||
"Consume the last glimmer of light from the space station.",
|
||||
"Bring judgment upon the daywalkers.",
|
||||
"Extinguish the flame of this hellscape.",
|
||||
"Reveal the true nature of the shadows.",
|
||||
"From the shadows, all shall perish.",
|
||||
"Conjure nightfall by blade or by flame.",
|
||||
"Bring the darkness to the light."
|
||||
)
|
||||
explanation_text = pick(explanation_texts)
|
||||
..()
|
||||
|
||||
/datum/objective/nightmare_fluff/check_completion()
|
||||
return owner.current.stat != DEAD
|
||||
|
||||
/datum/antagonist/nightmare/forge_objectives()
|
||||
var/datum/objective/nightmare_fluff/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/antagonist/nukeop
|
||||
name = ROLE_NUCLEAR_OPERATIVE
|
||||
roundend_category = "syndicate operatives" //just in case
|
||||
antagpanel_category = "NukeOp"
|
||||
antagpanel_category = ANTAG_GROUP_SYNDICATE
|
||||
job_rank = ROLE_OPERATIVE
|
||||
antag_hud_name = "synd"
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
@@ -122,7 +122,7 @@
|
||||
else
|
||||
to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
|
||||
|
||||
/datum/antagonist/nukeop/proc/forge_objectives()
|
||||
/datum/antagonist/nukeop/forge_objectives()
|
||||
if(nuke_team)
|
||||
objectives |= nuke_team.objectives
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@
|
||||
carried_item.add_mob_blood(H)//Oh yes, there will be blood...
|
||||
H.regenerate_icons()
|
||||
|
||||
/datum/antagonist/obsessed/proc/forge_objectives(datum/mind/obsessionmind)
|
||||
/datum/antagonist/obsessed/forge_objectives(datum/mind/obsessionmind)
|
||||
var/list/objectives_left = list("spendtime", "polaroid", "hug")
|
||||
var/datum/objective/assassinate/obsessed/kill = new
|
||||
kill.owner = owner
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "\improper Space Pirate"
|
||||
job_rank = ROLE_TRAITOR
|
||||
roundend_category = "space pirates"
|
||||
antagpanel_category = ANTAG_GROUP_PIRATES
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
suicide_cry = "FOR ME MATEYS!!"
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/datum/antagonist/pyro_slime
|
||||
name = "\improper Pyroclastic Anomaly"
|
||||
antagpanel_category = ANTAG_GROUP_ABOMINATIONS
|
||||
show_in_roundend = FALSE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/pyro_slime/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/pyro_slime/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/objective/pyro_slime
|
||||
explanation_text = "All I know fire. I speak in tongues of flame. Why is everyone so cold?"
|
||||
|
||||
/datum/objective/pyro_slime/check_completion()
|
||||
return owner.current.stat != DEAD
|
||||
|
||||
/datum/antagonist/pyro_slime/forge_objectives()
|
||||
var/datum/objective/pyro_slime/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
@@ -3,22 +3,23 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
antagpanel_category = ANTAG_GROUP_HORRORS
|
||||
|
||||
/datum/antagonist/revenant/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/revenant/proc/forge_objectives()
|
||||
var/datum/objective/revenant/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
var/datum/objective/revenant_fluff/objective2 = new
|
||||
objective2.owner = owner
|
||||
objectives += objective2
|
||||
|
||||
/datum/antagonist/revenant/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/revenant/get_preview_icon()
|
||||
return finish_preview_icon(icon('icons/mob/simple/mob.dmi', "revenant_idle"))
|
||||
|
||||
/datum/antagonist/revenant/forge_objectives()
|
||||
var/datum/objective/revenant/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
var/datum/objective/revenant_fluff/objective2 = new
|
||||
objective2.owner = owner
|
||||
objectives += objective2
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
suicide_cry = "FOR NANOTRASEN, NOW AND FOREVER!!"
|
||||
|
||||
/datum/antagonist/enemy_of_the_revolution/proc/forge_objectives()
|
||||
/datum/antagonist/enemy_of_the_revolution/forge_objectives()
|
||||
var/datum/objective/survive/survive = new
|
||||
survive.owner = owner
|
||||
survive.explanation_text = "The station has been overrun by revolutionaries, stay alive until the end."
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
hijack_speed = 2 //not like they have much to do
|
||||
suicide_cry = "FOR THE ETERNAL REVOLUTION!!"
|
||||
|
||||
/datum/antagonist/enemy_of_the_state/proc/forge_objectives()
|
||||
/datum/antagonist/enemy_of_the_state/forge_objectives()
|
||||
|
||||
var/datum/objective/exile/exile_choice = new
|
||||
exile_choice.owner = owner
|
||||
|
||||
@@ -237,6 +237,8 @@
|
||||
ckey_list += user.ckey
|
||||
newcarp.key = user.key
|
||||
newcarp.set_name()
|
||||
var/datum/antagonist/space_carp/carp_antag = new(src)
|
||||
newcarp.mind.add_antag_datum(carp_antag)
|
||||
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--
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/datum/antagonist/space_carp
|
||||
name = "\improper Space Carp"
|
||||
antagpanel_category = ANTAG_GROUP_LEVIATHANS
|
||||
show_in_roundend = FALSE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
/// The rift to protect
|
||||
var/datum/weakref/rift
|
||||
|
||||
/datum/antagonist/space_carp/New(obj/structure/carp_rift/rift)
|
||||
. = ..()
|
||||
src.rift = WEAKREF(rift)
|
||||
|
||||
/datum/antagonist/space_carp/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/space_carp/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/objective/space_carp
|
||||
explanation_text = "Protect the rift to summon more carps."
|
||||
var/datum/weakref/rift
|
||||
|
||||
/datum/objective/space_carp/check_completion()
|
||||
if(!rift.resolve())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/antagonist/space_carp/forge_objectives()
|
||||
var/datum/objective/space_carp/objective = new
|
||||
objective.owner = owner
|
||||
objective.rift = rift
|
||||
objectives += objective
|
||||
@@ -1,9 +1,9 @@
|
||||
/datum/antagonist/space_dragon
|
||||
name = "\improper Space Dragon"
|
||||
roundend_category = "space dragons"
|
||||
antagpanel_category = "Space Dragon"
|
||||
antagpanel_category = ANTAG_GROUP_LEVIATHANS
|
||||
job_rank = ROLE_SPACE_DRAGON
|
||||
show_in_antagpanel = TRUE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
/// All space carps created by this antagonist space dragon
|
||||
@@ -35,8 +35,8 @@
|
||||
owner.announce_objectives()
|
||||
SEND_SOUND(owner.current, sound('sound/magic/demon_attack1.ogg'))
|
||||
|
||||
/datum/antagonist/space_dragon/proc/forge_objectives()
|
||||
var/datum/objective/summon_carp/summon = new()
|
||||
/datum/antagonist/space_dragon/forge_objectives()
|
||||
var/datum/objective/summon_carp/summon = new
|
||||
summon.dragon = src
|
||||
objectives += summon
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/datum/antagonist/ninja
|
||||
name = "\improper Space Ninja"
|
||||
antagpanel_category = "Space Ninja"
|
||||
antagpanel_category = ANTAG_GROUP_NINJAS
|
||||
job_rank = ROLE_NINJA
|
||||
antag_hud_name = "space_ninja"
|
||||
hijack_speed = 1
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/datum/antagonist/spider
|
||||
name = "\improper Spider"
|
||||
antagpanel_category = ANTAG_GROUP_ARACHNIDS
|
||||
show_in_roundend = FALSE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
/// Orders given to us by the queen
|
||||
var/directive
|
||||
|
||||
/datum/antagonist/spider/New(directive)
|
||||
. = ..()
|
||||
src.directive = directive
|
||||
|
||||
/datum/antagonist/spider/on_gain()
|
||||
forge_objectives(directive)
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/spider/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/objective/spider
|
||||
explanation_text = "Spread the infestation."
|
||||
|
||||
/datum/objective/spider/New(directive)
|
||||
..()
|
||||
if(directive)
|
||||
explanation_text = "Your queen has given you a directive! Follow it at all costs: [directive]"
|
||||
|
||||
/datum/objective/spider/check_completion()
|
||||
return owner.current.stat != DEAD
|
||||
|
||||
/datum/antagonist/spider/forge_objectives()
|
||||
var/datum/objective/spider/objective = new(directive)
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
@@ -5,7 +5,7 @@
|
||||
suicide_cry = "FOR MYSELF!!"
|
||||
var/greet_message = ""
|
||||
|
||||
/datum/antagonist/survivalist/proc/forge_objectives()
|
||||
/datum/antagonist/survivalist/forge_objectives()
|
||||
var/datum/objective/survive/survive = new
|
||||
survive.owner = owner
|
||||
objectives += survive
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
show_name_in_check_antagonists = TRUE
|
||||
suicide_cry = "FOR LONELINESS!!"
|
||||
|
||||
/datum/antagonist/heartbreaker/proc/forge_objectives()
|
||||
/datum/antagonist/heartbreaker/forge_objectives()
|
||||
var/datum/objective/martyr/normiesgetout = new
|
||||
normiesgetout.owner = owner
|
||||
objectives += normiesgetout
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
var/datum/mind/date
|
||||
count_against_dynamic_roll_chance = FALSE
|
||||
|
||||
/datum/antagonist/valentine/proc/forge_objectives()
|
||||
/datum/antagonist/valentine/forge_objectives()
|
||||
var/datum/objective/protect/protect_objective = new /datum/objective/protect
|
||||
protect_objective.owner = owner
|
||||
protect_objective.target = date
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/datum/antagonist/venus_human_trap
|
||||
name = "\improper Venus Human Trap"
|
||||
antagpanel_category = ANTAG_GROUP_OVERGROWTH
|
||||
show_in_roundend = FALSE
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/venus_human_trap/on_gain()
|
||||
forge_objectives()
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/venus_human_trap/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/objective/venus_human_trap
|
||||
explanation_text = "Spread the infestation."
|
||||
|
||||
/datum/objective/venus_human_trap/check_completion()
|
||||
return owner.current.stat != DEAD
|
||||
|
||||
/datum/antagonist/venus_human_trap/forge_objectives()
|
||||
var/datum/objective/venus_human_trap/objective = new
|
||||
objective.owner = owner
|
||||
objectives += objective
|
||||
@@ -5,7 +5,7 @@
|
||||
hijack_speed = 2 //You literally are here to do nothing else. Might as well be fast about it.
|
||||
suicide_cry = "HAHAHAHAHA!!"
|
||||
|
||||
/datum/antagonist/wishgranter/proc/forge_objectives()
|
||||
/datum/antagonist/wishgranter/forge_objectives()
|
||||
var/datum/objective/hijack/hijack = new
|
||||
hijack.owner = owner
|
||||
objectives += hijack
|
||||
|
||||
@@ -516,7 +516,7 @@
|
||||
newstruct.key = target.key
|
||||
var/atom/movable/screen/alert/bloodsense/BS
|
||||
if(newstruct.mind && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker?.mode)
|
||||
newstruct.mind.add_antag_datum(/datum/antagonist/cult)
|
||||
newstruct.mind.add_antag_datum(/datum/antagonist/cult/construct)
|
||||
if(IS_CULTIST(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs.</b>")
|
||||
else if(stoner)
|
||||
|
||||
+1
@@ -9,6 +9,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_in_roundend = FALSE
|
||||
ui_name = "AntagInfoDemon"
|
||||
antagpanel_category = ANTAG_GROUP_WIZARDS
|
||||
|
||||
/datum/antagonist/imp/on_gain()
|
||||
. = ..()
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
job_rank = ROLE_ALIEN
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
antagpanel_category = ANTAG_GROUP_WIZARDS
|
||||
var/fluff = "You're a Demon of Wrath, often dragged into reality by wizards to terrorize their enemies."
|
||||
var/objective_verb = "Kill"
|
||||
var/datum/mind/summoner
|
||||
@@ -18,7 +19,7 @@
|
||||
owner.announce_objectives()
|
||||
to_chat(owner, span_warning("You have a powerful alt-attack that slams people backwards that you can activate by right-clicking your target!"))
|
||||
|
||||
/datum/antagonist/slaughter/proc/forge_objectives()
|
||||
/datum/antagonist/slaughter/forge_objectives()
|
||||
if(summoner)
|
||||
var/datum/objective/assassinate/new_objective = new /datum/objective/assassinate
|
||||
new_objective.owner = owner
|
||||
@@ -4,7 +4,7 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key)
|
||||
/datum/antagonist/wizard
|
||||
name = "\improper Space Wizard"
|
||||
roundend_category = "wizards/witches"
|
||||
antagpanel_category = "Wizard"
|
||||
antagpanel_category = ANTAG_GROUP_WIZARDS
|
||||
job_rank = ROLE_WIZARD
|
||||
antag_hud_name = "wizard"
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
@@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key)
|
||||
|
||||
/datum/antagonist/wizard_minion
|
||||
name = "Wizard Minion"
|
||||
antagpanel_category = "Wizard"
|
||||
antagpanel_category = "Wizard Federation"
|
||||
antag_hud_name = "apprentice"
|
||||
show_in_roundend = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
name = "\improper Xenomorph"
|
||||
job_rank = ROLE_ALIEN
|
||||
show_in_antagpanel = FALSE
|
||||
antagpanel_category = ANTAG_GROUP_XENOS
|
||||
prevent_roundtype_conversion = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
var/datum/team/xeno/xeno_team
|
||||
|
||||
@@ -104,6 +104,7 @@ GLOBAL_DATUM_INIT(orbit_menu, /datum/orbit_menu, new)
|
||||
if (antag_datum.show_to_ghosts)
|
||||
was_antagonist = TRUE
|
||||
serialized["antag"] = antag_datum.name
|
||||
serialized["antag_group"] = antag_datum.antagpanel_category
|
||||
antagonists += list(serialized)
|
||||
break
|
||||
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/construct
|
||||
name = "Construct"
|
||||
real_name = "Construct"
|
||||
desc = ""
|
||||
gender = NEUTER
|
||||
mob_biotypes = NONE
|
||||
speak_emote = list("hisses")
|
||||
response_help_continuous = "thinks better of touching"
|
||||
response_help_simple = "think better of touching"
|
||||
response_disarm_continuous = "flails at"
|
||||
response_disarm_simple = "flail at"
|
||||
response_harm_continuous = "punches"
|
||||
response_harm_simple = "punch"
|
||||
speak_chance = 1
|
||||
icon = 'icons/mob/nonhuman-player/cult.dmi'
|
||||
speed = 0
|
||||
combat_mode = TRUE
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
see_in_dark = 7
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
healable = 0
|
||||
faction = list("cult")
|
||||
pressure_resistance = 100
|
||||
unique_name = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
loot = list(/obj/item/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
death_message = "collapses in a shattered heap."
|
||||
var/list/construct_spells = list()
|
||||
var/playstyle_string = "<span class='big bold'>You are a generic construct!</span><b> Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
var/master = null
|
||||
var/seeking = FALSE
|
||||
/// Whether this construct can repair other constructs or cult buildings.
|
||||
var/can_repair = FALSE
|
||||
/// Whether this construct can repair itself. Works independently of can_repair.
|
||||
var/can_repair_self = FALSE
|
||||
/// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue
|
||||
var/theme = THEME_CULT
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/simple_flying)
|
||||
ADD_TRAIT(src, TRAIT_HEALS_FROM_CULT_PYLONS, INNATE_TRAIT)
|
||||
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
|
||||
for(var/spell in construct_spells)
|
||||
var/datum/action/new_spell = new spell(src)
|
||||
new_spell.Grant(src)
|
||||
|
||||
var/spellnum = 1
|
||||
for(var/datum/action/spell as anything in actions)
|
||||
if(!(spell.type in construct_spells))
|
||||
continue
|
||||
|
||||
var/pos = 2 + spellnum * 31
|
||||
if(construct_spells.len >= 4)
|
||||
pos -= 31 * (construct_spells.len - 4)
|
||||
spell.default_button_position = "6:[pos],4:-2" // Set the default position to this random position
|
||||
spellnum++
|
||||
update_action_buttons()
|
||||
|
||||
if(icon_state)
|
||||
add_overlay("glow_[icon_state]_[theme]")
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Login()
|
||||
. = ..()
|
||||
if(!. || !client)
|
||||
return FALSE
|
||||
to_chat(src, playstyle_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/text_span
|
||||
switch(theme)
|
||||
if(THEME_CULT)
|
||||
text_span = "cult"
|
||||
if(THEME_WIZARD)
|
||||
text_span = "purple"
|
||||
if(THEME_HOLY)
|
||||
text_span = "blue"
|
||||
. = list("<span class='[text_span]'>This is [icon2html(src, user)] \a <b>[src]</b>!\n[desc]", EXAMINE_SECTION_BREAK) //SKYRAT EDIT CHANGE
|
||||
if(health < maxHealth)
|
||||
if(health >= maxHealth/2)
|
||||
. += span_warning("[t_He] look[t_s] slightly dented.")
|
||||
else
|
||||
. += span_warning("<b>[t_He] look[t_s] severely dented!</b>")
|
||||
. += "</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/user, list/modifiers)
|
||||
if(isconstruct(user)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/doll = user
|
||||
if(!doll.can_repair || (doll == src && !doll.can_repair_self))
|
||||
return ..()
|
||||
if(theme != doll.theme)
|
||||
return ..()
|
||||
if(health < maxHealth)
|
||||
adjustHealth(-5)
|
||||
if(src != user)
|
||||
Beam(user, icon_state="sendbeam", time = 4)
|
||||
user.visible_message(span_danger("[user] repairs some of \the <b>[src]'s</b> dents."), \
|
||||
span_cult("You repair some of <b>[src]'s</b> dents, leaving <b>[src]</b> at <b>[health]/[maxHealth]</b> health."))
|
||||
else
|
||||
user.visible_message(span_danger("[user] repairs some of [p_their()] own dents."), \
|
||||
span_cult("You repair some of your own dents, leaving you at <b>[user.health]/[user.maxHealth]</b> health."))
|
||||
else
|
||||
if(src != user)
|
||||
to_chat(user, span_cult("You cannot repair <b>[src]'s</b> dents, as [p_they()] [p_have()] none!"))
|
||||
else
|
||||
to_chat(user, span_cult("You cannot repair your own dents, as you have none!"))
|
||||
else if(src != user)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
|
||||
return 0
|
||||
|
||||
/////////////////Juggernaut///////////////
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut
|
||||
name = "Juggernaut"
|
||||
real_name = "Juggernaut"
|
||||
desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire."
|
||||
icon_state = "juggernaut"
|
||||
icon_living = "juggernaut"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
response_harm_continuous = "harmlessly punches"
|
||||
response_harm_simple = "harmlessly punch"
|
||||
harm_intent_damage = 0
|
||||
obj_damage = 90
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attack_verb_continuous = "smashes their armored gauntlet into"
|
||||
attack_verb_simple = "smash your armored gauntlet into"
|
||||
speed = 2.5
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
attack_sound = 'sound/weapons/punch3.ogg'
|
||||
status_flags = 0
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
force_threshold = 10
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/forcewall/cult,
|
||||
/datum/action/cooldown/spell/basic_projectile/juggernaut,
|
||||
/datum/action/innate/cult/create_rune/wall,
|
||||
)
|
||||
playstyle_string = "<b>You are a Juggernaut. Though slow, your shell can withstand heavy punishment, \
|
||||
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/bullet_act(obj/projectile/P)
|
||||
if(istype(P, /obj/projectile/energy) || istype(P, /obj/projectile/beam))
|
||||
var/reflectchance = 40 - round(P.damage/3)
|
||||
if(prob(reflectchance))
|
||||
apply_damage(P.damage * 0.5, P.damage_type)
|
||||
visible_message(span_danger("The [P.name] is reflected by [src]'s armored shell!"), \
|
||||
span_userdanger("The [P.name] is reflected by your armored shell!"))
|
||||
|
||||
// Find a turf near or on the original location to bounce to
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
P.original = locate(new_x, new_y, P.z)
|
||||
P.starting = curloc
|
||||
P.firer = src
|
||||
P.yo = new_y - curloc.y
|
||||
P.xo = new_x - curloc.x
|
||||
var/new_angle_s = P.Angle + rand(120,240)
|
||||
while(new_angle_s > 180) // Translate to regular projectile degrees
|
||||
new_angle_s -= 360
|
||||
P.set_angle(new_angle_s)
|
||||
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
return ..()
|
||||
|
||||
//////////////////////////Juggernaut-alts////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/angelic
|
||||
theme = THEME_HOLY
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/mystic
|
||||
theme = THEME_WIZARD
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/noncult
|
||||
|
||||
////////////////////////Wraith/////////////////////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/wraith
|
||||
name = "Wraith"
|
||||
real_name = "Wraith"
|
||||
desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines."
|
||||
icon_state = "wraith"
|
||||
icon_living = "wraith"
|
||||
maxHealth = 65
|
||||
health = 65
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
retreat_distance = 2 //AI wraiths will move in and out of combat
|
||||
attack_verb_continuous = "slashes"
|
||||
attack_verb_simple = "slash"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
playstyle_string = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, \
|
||||
can phase through walls, and your attacks will lower the cooldown on phasing.</b>"
|
||||
|
||||
// Accomplishing various things gives you a refund on jaunt, to jump in and out.
|
||||
/// The seconds refunded per attack
|
||||
var/attack_refund = 1 SECONDS
|
||||
/// The seconds refunded when putting a target into critical
|
||||
var/crit_refund = 5 SECONDS
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/AttackingTarget() //refund jaunt cooldown when attacking living targets
|
||||
var/prev_stat
|
||||
var/mob/living/living_target = target
|
||||
|
||||
if(isliving(living_target) && !IS_CULTIST(living_target))
|
||||
prev_stat = living_target.stat
|
||||
|
||||
. = ..()
|
||||
|
||||
if(. && isnum(prev_stat))
|
||||
var/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/jaunt = locate() in actions
|
||||
if(!jaunt)
|
||||
return
|
||||
|
||||
var/total_refund = 0 SECONDS
|
||||
// they're dead, and you killed them - full refund
|
||||
if(QDELETED(living_target) || (living_target.stat == DEAD && prev_stat != DEAD))
|
||||
total_refund += jaunt.cooldown_time
|
||||
// you knocked them into critical
|
||||
else if(HAS_TRAIT(living_target, TRAIT_CRITICAL_CONDITION) && prev_stat == CONSCIOUS)
|
||||
total_refund += crit_refund
|
||||
|
||||
if(living_target.stat != DEAD && prev_stat != DEAD)
|
||||
total_refund += attack_refund
|
||||
|
||||
jaunt.next_use_time -= total_refund
|
||||
jaunt.build_all_button_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
|
||||
//////////////////////////Wraith-alts////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/wraith/angelic
|
||||
theme = THEME_HOLY
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/angelic,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/mystic
|
||||
theme = THEME_WIZARD
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/mystic,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/noncult
|
||||
|
||||
/////////////////////////////Artificer/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/artificer
|
||||
name = "Artificer"
|
||||
real_name = "Artificer"
|
||||
desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar'Sie's armies."
|
||||
icon_state = "artificer"
|
||||
icon_living = "artificer"
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
response_harm_continuous = "viciously beats"
|
||||
response_harm_simple = "viciously beat"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
retreat_distance = 10
|
||||
minimum_distance = 10 //AI artificers will flee like fuck
|
||||
attack_verb_continuous = "rams"
|
||||
attack_verb_simple = "ram"
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
attack_sound = 'sound/weapons/punch2.ogg'
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
playstyle_string = "<b>You are an Artificer. You are incredibly weak and fragile, \
|
||||
but you are able to construct fortifications, use magic missile, and repair allied constructs, shades, \
|
||||
and yourself (by clicking on them). Additionally, <i>and most important of all,</i> you can create new constructs \
|
||||
by producing soulstones to capture souls, and shells to place those soulstones into.</b>"
|
||||
|
||||
can_repair = TRUE
|
||||
can_repair_self = TRUE
|
||||
///The health HUD applied to this mob.
|
||||
var/health_hud = DATA_HUD_MEDICAL_ADVANCED
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/atom_hud/datahud = GLOB.huds[health_hud]
|
||||
datahud.show_to(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Found(atom/A) //what have we found here?
|
||||
if(isconstruct(A)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = A
|
||||
if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/CanAttack(atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible
|
||||
return TRUE //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/MoveToTarget(list/possible_targets)
|
||||
..()
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(isconstruct(L) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
LoseTarget()
|
||||
return
|
||||
if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Aggro()
|
||||
..()
|
||||
if(isconstruct(target)) //oh the target is a construct no need to flee
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/LoseAggro()
|
||||
..()
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/hostile //actually hostile, will move around, hit things, heal other constructs
|
||||
AIStatus = AI_ON
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/////////////////////////////Artificer-alts/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/artificer/angelic
|
||||
desc = "A bulbous construct dedicated to building and maintaining holy armies."
|
||||
theme = THEME_HOLY
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/soulstone/purified,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
/mob/living/simple_animal/hostile/construct/artificer/mystic
|
||||
theme = THEME_WIZARD
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone/mystic,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/noncult
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone/noncult,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
|
||||
/////////////////////////////Harvester/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/harvester
|
||||
name = "Harvester"
|
||||
real_name = "Harvester"
|
||||
desc = "A long, thin construct built to herald Nar'Sie's rise. It'll be all over soon."
|
||||
icon_state = "harvester"
|
||||
icon_living = "harvester"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
sight = SEE_MOBS
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attack_verb_continuous = "butchers"
|
||||
attack_verb_simple = "butcher"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/aoe/area_conversion,
|
||||
/datum/action/cooldown/spell/forcewall/cult,
|
||||
)
|
||||
playstyle_string = "<B>You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \
|
||||
Bring those who still cling to this world of illusion back to the Geometer so they may know Truth. Your form and any you are pulling can pass through runed walls effortlessly.</B>"
|
||||
can_repair = TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/AM)
|
||||
. = ..()
|
||||
if(istype(AM, /turf/closed/wall/mineral/cult) && AM != loc) //we can go through cult walls
|
||||
var/atom/movable/stored_pulling = pulling
|
||||
if(stored_pulling)
|
||||
stored_pulling.setDir(get_dir(stored_pulling.loc, loc))
|
||||
stored_pulling.forceMove(loc)
|
||||
forceMove(AM)
|
||||
if(stored_pulling)
|
||||
start_pulling(stored_pulling, supress_message = TRUE) //drag anything we're pulling through the wall with us by magic
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget()
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(HAS_TRAIT(C, TRAIT_NODISMEMBER))
|
||||
return ..() //ATTACK!
|
||||
var/list/parts = list()
|
||||
var/undismembermerable_limbs = 0
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.body_part != HEAD && BP.body_part != CHEST)
|
||||
if(BP.dismemberable)
|
||||
parts += BP
|
||||
else
|
||||
undismembermerable_limbs++
|
||||
if(!LAZYLEN(parts))
|
||||
if(undismembermerable_limbs) //they have limbs we can't remove, and no parts we can, attack!
|
||||
return ..()
|
||||
C.Paralyze(60)
|
||||
visible_message(span_danger("[src] knocks [C] down!"))
|
||||
to_chat(src, span_cultlarge("\"Bring [C.p_them()] to me.\""))
|
||||
return FALSE
|
||||
do_attack_animation(C)
|
||||
var/obj/item/bodypart/BP = pick(parts)
|
||||
BP.dismember()
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/action/innate/seek_prey/seek = new()
|
||||
seek.Grant(src)
|
||||
seek.Activate()
|
||||
|
||||
///////////////////////Master-Tracker///////////////////////
|
||||
|
||||
/datum/action/innate/seek_master
|
||||
name = "Seek your Master"
|
||||
desc = "You and your master share a soul-link that informs you of their location"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
var/tracking = FALSE
|
||||
var/mob/living/simple_animal/hostile/construct/the_construct
|
||||
|
||||
|
||||
/datum/action/innate/seek_master/Grant(mob/living/C)
|
||||
the_construct = C
|
||||
..()
|
||||
|
||||
/datum/action/innate/seek_master/Activate()
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult)
|
||||
if(!C)
|
||||
return
|
||||
var/datum/objective/eldergod/summon_objective = locate() in C.cult_team.objectives
|
||||
|
||||
if(summon_objective.check_completion())
|
||||
the_construct.master = C.cult_team.blood_target
|
||||
|
||||
if(!the_construct.master)
|
||||
to_chat(the_construct, "<span class='cult italic'>You have no master to seek!</span>")
|
||||
the_construct.seeking = FALSE
|
||||
return
|
||||
if(tracking)
|
||||
tracking = FALSE
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, "<span class='cult italic'>You are no longer tracking your master.</span>")
|
||||
return
|
||||
else
|
||||
tracking = TRUE
|
||||
the_construct.seeking = TRUE
|
||||
to_chat(the_construct, "<span class='cult italic'>You are now tracking your master.</span>")
|
||||
|
||||
|
||||
/datum/action/innate/seek_prey
|
||||
name = "Seek the Harvest"
|
||||
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
|
||||
button_icon = 'icons/mob/actions/actions_cult.dmi'
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
|
||||
/datum/action/innate/seek_prey/Activate()
|
||||
if(GLOB.cult_narsie == null)
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/construct/harvester/the_construct = owner
|
||||
if(the_construct.seeking)
|
||||
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
|
||||
button_icon_state = "cult_mark"
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, "<span class='cult italic'>You are now tracking Nar'Sie, return to reap the harvest!</span>")
|
||||
return
|
||||
else
|
||||
if(LAZYLEN(GLOB.cult_narsie.souls_needed))
|
||||
the_construct.master = pick(GLOB.cult_narsie.souls_needed)
|
||||
var/mob/living/real_target = the_construct.master //We can typecast this way because Narsie only allows /mob/living into the souls list
|
||||
to_chat(the_construct, "<span class='cult italic'>You are now tracking your prey, [real_target.real_name] - harvest [real_target.p_them()]!</span>")
|
||||
else
|
||||
to_chat(the_construct, "<span class='cult italic'>Nar'Sie has completed her harvest!</span>")
|
||||
return
|
||||
desc = "Activate to track Nar'Sie!"
|
||||
button_icon_state = "sintouch"
|
||||
the_construct.seeking = TRUE
|
||||
-14
@@ -1,8 +1,3 @@
|
||||
|
||||
////////////////
|
||||
// BASE TYPE //
|
||||
////////////////
|
||||
|
||||
//Do not spawn
|
||||
/mob/living/simple_animal/hostile/blob
|
||||
icon = 'icons/mob/nonhuman-player/blob.dmi'
|
||||
@@ -100,12 +95,3 @@
|
||||
var/link = FOLLOW_LINK(creature, src)
|
||||
to_chat(creature, "[link] [rendered]")
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/proc/create_objectives(datum/antagonist/antagonist)
|
||||
if(!antagonist)
|
||||
return FALSE
|
||||
var/datum/objective/protect/new_objective = new
|
||||
new_objective.owner = mind
|
||||
new_objective.target = overmind
|
||||
new_objective.explanation_text = "Protect the core!"
|
||||
antagonist.objectives = list(new_objective)
|
||||
return TRUE
|
||||
+4
-16
@@ -1,13 +1,3 @@
|
||||
/datum/antagonist/blobbernaut
|
||||
name = "\improper Blobbernaut"
|
||||
antagpanel_category = "Biohazards"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/////////////////
|
||||
// BLOBBERNAUT //
|
||||
/////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut
|
||||
name = "blobbernaut"
|
||||
desc = "A hulking, mobile chunk of blobmass."
|
||||
@@ -38,12 +28,10 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/mind_initialize()
|
||||
. = ..()
|
||||
if(independent)
|
||||
return FALSE
|
||||
if(mind.has_antag_datum(/datum/antagonist/blobbernaut))
|
||||
return FALSE
|
||||
var/datum/antagonist/blobbernaut/blobbernaut = mind.add_antag_datum(/datum/antagonist/blobbernaut)
|
||||
create_objectives(blobbernaut)
|
||||
if(independent | !overmind)
|
||||
return
|
||||
var/datum/antagonist/blob_minion/blobbernaut/naut = new(overmind)
|
||||
mind.add_antag_datum(naut)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/add_cell_sample()
|
||||
AddElement(/datum/element/swabable, CELL_LINE_TABLE_BLOBBERNAUT, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5)
|
||||
+3
-15
@@ -1,13 +1,3 @@
|
||||
/datum/antagonist/blobspore
|
||||
name = "\improper Blob Spore"
|
||||
antagpanel_category = "Biohazards"
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
////////////////
|
||||
// BLOB SPORE //
|
||||
////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore
|
||||
name = "blob spore"
|
||||
desc = "A floating, fragile spore."
|
||||
@@ -54,12 +44,10 @@
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/mind_initialize()
|
||||
. = ..()
|
||||
if(independent)
|
||||
if(independent || !overmind)
|
||||
return FALSE
|
||||
if(mind.has_antag_datum(/datum/antagonist/blobspore))
|
||||
return FALSE
|
||||
var/datum/antagonist/blobspore/blobspore = mind.add_antag_datum(/datum/antagonist/blobspore)
|
||||
create_objectives(blobspore)
|
||||
var/datum/antagonist/blob_minion/blob_zombie/zombie = new(overmind)
|
||||
mind.add_antag_datum(zombie)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/Life(delta_time = SSMOBS_DT, times_fired)
|
||||
if(!is_zombie && isturf(loc))
|
||||
@@ -0,0 +1,117 @@
|
||||
/mob/living/simple_animal/hostile/construct/artificer
|
||||
name = "Artificer"
|
||||
real_name = "Artificer"
|
||||
desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar'Sie's armies."
|
||||
icon_state = "artificer"
|
||||
icon_living = "artificer"
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
response_harm_continuous = "viciously beats"
|
||||
response_harm_simple = "viciously beat"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
retreat_distance = 10
|
||||
minimum_distance = 10 //AI artificers will flee like fuck
|
||||
attack_verb_continuous = "rams"
|
||||
attack_verb_simple = "ram"
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
attack_sound = 'sound/weapons/punch2.ogg'
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
playstyle_string = "<b>You are an Artificer. You are incredibly weak and fragile, \
|
||||
but you are able to construct fortifications, use magic missile, and repair allied constructs, shades, \
|
||||
and yourself (by clicking on them). Additionally, <i>and most important of all,</i> you can create new constructs \
|
||||
by producing soulstones to capture souls, and shells to place those soulstones into.</b>"
|
||||
|
||||
can_repair = TRUE
|
||||
can_repair_self = TRUE
|
||||
///The health HUD applied to this mob.
|
||||
var/health_hud = DATA_HUD_MEDICAL_ADVANCED
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/atom_hud/datahud = GLOB.huds[health_hud]
|
||||
datahud.show_to(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Found(atom/thing) //what have we found here?
|
||||
if(!isconstruct(thing)) //is it a construct?
|
||||
return FALSE
|
||||
var/mob/living/simple_animal/hostile/construct/cultie = thing
|
||||
if(cultie.health < cultie.maxHealth) //is it hurt? let's go heal it if it is
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/CanAttack(atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return FALSE
|
||||
if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible
|
||||
return TRUE //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/MoveToTarget(list/possible_targets)
|
||||
..()
|
||||
if(!isliving(target))
|
||||
return
|
||||
|
||||
var/mob/living/victim = target
|
||||
if(isconstruct(victim) && victim.health >= victim.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
LoseTarget()
|
||||
return
|
||||
if(victim.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/Aggro()
|
||||
..()
|
||||
if(isconstruct(target)) //oh the target is a construct no need to flee
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/LoseAggro()
|
||||
..()
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/hostile //actually hostile, will move around, hit things, heal other constructs
|
||||
AIStatus = AI_ON
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/////////////////////////////Artificer-alts/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/artificer/angelic
|
||||
desc = "A bulbous construct dedicated to building and maintaining holy armies."
|
||||
theme = THEME_HOLY
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/soulstone/purified,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
/mob/living/simple_animal/hostile/construct/artificer/mystic
|
||||
theme = THEME_WIZARD
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone/mystic,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/artificer/noncult
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/conjure/cult_floor,
|
||||
/datum/action/cooldown/spell/conjure/cult_wall,
|
||||
/datum/action/cooldown/spell/conjure/soulstone/noncult,
|
||||
/datum/action/cooldown/spell/conjure/construct/lesser,
|
||||
/datum/action/cooldown/spell/aoe/magic_missile/lesser,
|
||||
/datum/action/innate/cult/create_rune/revive,
|
||||
)
|
||||
@@ -0,0 +1,135 @@
|
||||
/mob/living/simple_animal/hostile/construct
|
||||
name = "Construct"
|
||||
real_name = "Construct"
|
||||
desc = ""
|
||||
gender = NEUTER
|
||||
mob_biotypes = NONE
|
||||
speak_emote = list("hisses")
|
||||
response_help_continuous = "thinks better of touching"
|
||||
response_help_simple = "think better of touching"
|
||||
response_disarm_continuous = "flails at"
|
||||
response_disarm_simple = "flail at"
|
||||
response_harm_continuous = "punches"
|
||||
response_harm_simple = "punch"
|
||||
speak_chance = 1
|
||||
icon = 'icons/mob/nonhuman-player/cult.dmi'
|
||||
speed = 0
|
||||
combat_mode = TRUE
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
see_in_dark = 7
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
healable = 0
|
||||
faction = list("cult")
|
||||
pressure_resistance = 100
|
||||
unique_name = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
loot = list(/obj/item/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
death_message = "collapses in a shattered heap."
|
||||
/// List of spells that this construct can cast
|
||||
var/list/construct_spells = list()
|
||||
/// Flavor text shown to players when they spawn as this construct
|
||||
var/playstyle_string = "<span class='big bold'>You are a generic construct!</span><b> Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
/// The construct's master
|
||||
var/master = null
|
||||
/// Whether this construct is currently seeking nar nar
|
||||
var/seeking = FALSE
|
||||
/// Whether this construct can repair other constructs or cult buildings.
|
||||
var/can_repair = FALSE
|
||||
/// Whether this construct can repair itself. Works independently of can_repair.
|
||||
var/can_repair_self = FALSE
|
||||
/// Theme controls color. THEME_CULT is red THEME_WIZARD is purple and THEME_HOLY is blue
|
||||
var/theme = THEME_CULT
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Initialize(mapload)
|
||||
. = ..()
|
||||
AddElement(/datum/element/simple_flying)
|
||||
ADD_TRAIT(src, TRAIT_HEALS_FROM_CULT_PYLONS, INNATE_TRAIT)
|
||||
ADD_TRAIT(src, TRAIT_SPACEWALK, INNATE_TRAIT)
|
||||
for(var/spell in construct_spells)
|
||||
var/datum/action/new_spell = new spell(src)
|
||||
new_spell.Grant(src)
|
||||
|
||||
var/spell_count = 1
|
||||
for(var/datum/action/spell as anything in actions)
|
||||
if(!(spell.type in construct_spells))
|
||||
continue
|
||||
|
||||
var/pos = 2 + spell_count * 31
|
||||
if(construct_spells.len >= 4)
|
||||
pos -= 31 * (construct_spells.len - 4)
|
||||
spell.default_button_position = "6:[pos],4:-2" // Set the default position to this random position
|
||||
spell_count++
|
||||
update_action_buttons()
|
||||
|
||||
if(icon_state)
|
||||
add_overlay("glow_[icon_state]_[theme]")
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Login()
|
||||
. = ..()
|
||||
if(!. || !client)
|
||||
return FALSE
|
||||
to_chat(src, playstyle_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/examine(mob/user)
|
||||
var/pronoun = p_they(TRUE)
|
||||
var/plural = p_s()
|
||||
var/text_span
|
||||
switch(theme)
|
||||
if(THEME_CULT)
|
||||
text_span = "cult"
|
||||
if(THEME_WIZARD)
|
||||
text_span = "purple"
|
||||
if(THEME_HOLY)
|
||||
text_span = "blue"
|
||||
. = list("<span class='[text_span]'>This is [icon2html(src, user)] \a <b>[src]</b>!\n[desc]")
|
||||
if(health < maxHealth)
|
||||
if(health >= maxHealth/2)
|
||||
. += span_warning("[pronoun] look[plural] slightly dented.")
|
||||
else
|
||||
. += span_warning("<b>[pronoun] look[plural] severely dented!</b>")
|
||||
. += "</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/user, list/modifiers)
|
||||
if(!isconstruct(user))
|
||||
if(src != user)
|
||||
return ..()
|
||||
return
|
||||
|
||||
var/mob/living/simple_animal/hostile/construct/doll = user
|
||||
if(!doll.can_repair || (doll == src && !doll.can_repair_self))
|
||||
return ..()
|
||||
if(theme != doll.theme)
|
||||
return ..()
|
||||
|
||||
if(health >= maxHealth)
|
||||
if(src != user)
|
||||
to_chat(user, span_cult("You cannot repair <b>[src]'s</b> dents, as [p_they()] [p_have()] none!"))
|
||||
else
|
||||
to_chat(user, span_cult("You cannot repair your own dents, as you have none!"))
|
||||
return
|
||||
|
||||
adjustHealth(-5)
|
||||
if(src == user)
|
||||
user.visible_message(span_danger("[user] repairs some of [p_their()] own dents."), \
|
||||
span_cult("You repair some of your own dents, leaving you at <b>[user.health]/[user.maxHealth]</b> health."))
|
||||
return
|
||||
|
||||
Beam(user, icon_state="sendbeam", time = 4)
|
||||
user.visible_message(span_danger("[user] repairs some of \the <b>[src]'s</b> dents."), \
|
||||
span_cult("You repair some of <b>[src]'s</b> dents, leaving <b>[src]</b> at <b>[health]/[maxHealth]</b> health."))
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, source, siemens_coeff = 1, flags = NONE)
|
||||
return FALSE
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/mob/living/simple_animal/hostile/construct/harvester
|
||||
name = "Harvester"
|
||||
real_name = "Harvester"
|
||||
desc = "A long, thin construct built to herald Nar'Sie's rise. It'll be all over soon."
|
||||
icon_state = "harvester"
|
||||
icon_living = "harvester"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
sight = SEE_MOBS
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attack_verb_continuous = "butchers"
|
||||
attack_verb_simple = "butcher"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/aoe/area_conversion,
|
||||
/datum/action/cooldown/spell/forcewall/cult,
|
||||
)
|
||||
playstyle_string = "<B>You are a Harvester. You are incapable of directly killing humans, \
|
||||
but your attacks will remove their limbs: Bring those who still cling to this world \
|
||||
of illusion back to the Geometer so they may know Truth. Your form and any you are \
|
||||
pulling can pass through runed walls effortlessly.</B>"
|
||||
can_repair = TRUE
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/thing)
|
||||
. = ..()
|
||||
if(!istype(thing, /turf/closed/wall/mineral/cult) || thing == loc)
|
||||
return // we can go through cult walls
|
||||
var/atom/movable/stored_pulling = pulling
|
||||
|
||||
if(stored_pulling)
|
||||
stored_pulling.setDir(get_dir(stored_pulling.loc, loc))
|
||||
stored_pulling.forceMove(loc)
|
||||
forceMove(thing)
|
||||
|
||||
if(stored_pulling)
|
||||
start_pulling(stored_pulling, supress_message = TRUE) //drag anything we're pulling through the wall with us by magic
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget()
|
||||
if(!iscarbon(target))
|
||||
return ..()
|
||||
|
||||
var/mob/living/carbon/victim = target
|
||||
if(HAS_TRAIT(victim, TRAIT_NODISMEMBER))
|
||||
return ..() //ATTACK!
|
||||
|
||||
var/list/parts = list()
|
||||
var/strong_limbs = 0
|
||||
|
||||
for(var/obj/item/bodypart/limb as anything in victim.bodyparts)
|
||||
if(limb.body_part == HEAD || limb.body_part == CHEST)
|
||||
continue
|
||||
if(limb.dismemberable)
|
||||
parts += limb
|
||||
else
|
||||
strong_limbs++
|
||||
|
||||
if(!LAZYLEN(parts))
|
||||
if(strong_limbs) // they have limbs we can't remove, and no parts we can, attack!
|
||||
return ..()
|
||||
victim.Paralyze(60)
|
||||
visible_message(span_danger("[src] knocks [victim] down!"))
|
||||
to_chat(src, span_cultlarge("\"Bring [victim.p_them()] to me.\""))
|
||||
return FALSE
|
||||
|
||||
do_attack_animation(victim)
|
||||
var/obj/item/bodypart/limb = pick(parts)
|
||||
limb.dismember()
|
||||
return FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Initialize(mapload)
|
||||
. = ..()
|
||||
var/datum/action/innate/seek_prey/seek = new()
|
||||
seek.Grant(src)
|
||||
seek.Activate()
|
||||
|
||||
/datum/action/innate/seek_master
|
||||
name = "Seek your Master"
|
||||
desc = "You and your master share a soul-link that informs you of their location"
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
/// Where is nar nar? Are we even looking?
|
||||
var/tracking = FALSE
|
||||
/// The construct we're attached to
|
||||
var/mob/living/simple_animal/hostile/construct/the_construct
|
||||
|
||||
/datum/action/innate/seek_master/Grant(mob/living/player)
|
||||
the_construct = player
|
||||
..()
|
||||
|
||||
/datum/action/innate/seek_master/Activate()
|
||||
var/datum/antagonist/cult/cult_status = owner.mind.has_antag_datum(/datum/antagonist/cult)
|
||||
if(!cult_status)
|
||||
return
|
||||
var/datum/objective/eldergod/summon_objective = locate() in cult_status.cult_team.objectives
|
||||
|
||||
if(summon_objective.check_completion())
|
||||
the_construct.master = cult_status.cult_team.blood_target
|
||||
|
||||
if(!the_construct.master)
|
||||
to_chat(the_construct, span_cultitalic("You have no master to seek!"))
|
||||
the_construct.seeking = FALSE
|
||||
return
|
||||
if(tracking)
|
||||
tracking = FALSE
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, span_cultitalic("You are no longer tracking your master."))
|
||||
return
|
||||
else
|
||||
tracking = TRUE
|
||||
the_construct.seeking = TRUE
|
||||
to_chat(the_construct, span_cultitalic("You are now tracking your master."))
|
||||
|
||||
|
||||
/datum/action/innate/seek_prey
|
||||
name = "Seek the Harvest"
|
||||
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
|
||||
button_icon = 'icons/mob/actions/actions_cult.dmi'
|
||||
background_icon_state = "bg_demon"
|
||||
overlay_icon_state = "bg_demon_border"
|
||||
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
|
||||
/datum/action/innate/seek_prey/Activate()
|
||||
if(GLOB.cult_narsie == null)
|
||||
return
|
||||
var/mob/living/simple_animal/hostile/construct/harvester/the_construct = owner
|
||||
|
||||
if(the_construct.seeking)
|
||||
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
|
||||
button_icon_state = "cult_mark"
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, span_cultitalic("You are now tracking Nar'Sie, return to reap the harvest!"))
|
||||
return
|
||||
|
||||
if(!LAZYLEN(GLOB.cult_narsie.souls_needed))
|
||||
to_chat(the_construct, span_cultitalic("Nar'Sie has completed her harvest!"))
|
||||
return
|
||||
|
||||
the_construct.master = pick(GLOB.cult_narsie.souls_needed)
|
||||
var/mob/living/real_target = the_construct.master //We can typecast this way because Narsie only allows /mob/living into the souls list
|
||||
to_chat(the_construct, span_cultitalic("You are now tracking your prey, [real_target.real_name] - harvest [real_target.p_them()]!"))
|
||||
desc = "Activate to track Nar'Sie!"
|
||||
button_icon_state = "sintouch"
|
||||
the_construct.seeking = TRUE
|
||||
@@ -0,0 +1,75 @@
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut
|
||||
name = "Juggernaut"
|
||||
real_name = "Juggernaut"
|
||||
desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire."
|
||||
icon_state = "juggernaut"
|
||||
icon_living = "juggernaut"
|
||||
maxHealth = 150
|
||||
health = 150
|
||||
response_harm_continuous = "harmlessly punches"
|
||||
response_harm_simple = "harmlessly punch"
|
||||
harm_intent_damage = 0
|
||||
obj_damage = 90
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attack_verb_continuous = "smashes their armored gauntlet into"
|
||||
attack_verb_simple = "smash your armored gauntlet into"
|
||||
speed = 2.5
|
||||
environment_smash = ENVIRONMENT_SMASH_WALLS
|
||||
attack_sound = 'sound/weapons/punch3.ogg'
|
||||
status_flags = 0
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
force_threshold = 10
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/forcewall/cult,
|
||||
/datum/action/cooldown/spell/basic_projectile/juggernaut,
|
||||
/datum/action/innate/cult/create_rune/wall,
|
||||
)
|
||||
playstyle_string = "<b>You are a Juggernaut. Though slow, your shell can withstand heavy punishment, \
|
||||
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/bullet_act(obj/projectile/bullet)
|
||||
if(!istype(bullet, /obj/projectile/energy) && !istype(bullet, /obj/projectile/beam))
|
||||
return ..()
|
||||
if(!prob(40 - round(bullet.damage / 3))) // reflect chance
|
||||
return ..()
|
||||
|
||||
apply_damage(bullet.damage * 0.5, bullet.damage_type)
|
||||
visible_message(span_danger("The [bullet.name] is reflected by [src]'s armored shell!"), \
|
||||
span_userdanger("The [bullet.name] is reflected by your armored shell!"))
|
||||
|
||||
if(!bullet.starting)
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
// Find a turf near or on the original location to bounce to
|
||||
var/new_x = bullet.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/new_y = bullet.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/turf/current_tile = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
bullet.original = locate(new_x, new_y, bullet.z)
|
||||
bullet.starting = current_tile
|
||||
bullet.firer = src
|
||||
bullet.yo = new_y - current_tile.y
|
||||
bullet.xo = new_x - current_tile.x
|
||||
var/new_angle_s = bullet.Angle + rand(120,240)
|
||||
while(new_angle_s > 180) // Translate to regular projectile degrees
|
||||
new_angle_s -= 360
|
||||
bullet.set_angle(new_angle_s)
|
||||
|
||||
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
|
||||
|
||||
|
||||
//////////////////////////Juggernaut-alts////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/angelic
|
||||
theme = THEME_HOLY
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/mystic
|
||||
theme = THEME_WIZARD
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/juggernaut/noncult
|
||||
@@ -0,0 +1,78 @@
|
||||
/mob/living/simple_animal/hostile/construct/wraith
|
||||
name = "Wraith"
|
||||
real_name = "Wraith"
|
||||
desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines."
|
||||
icon_state = "wraith"
|
||||
icon_living = "wraith"
|
||||
maxHealth = 65
|
||||
health = 65
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
retreat_distance = 2 //AI wraiths will move in and out of combat
|
||||
attack_verb_continuous = "slashes"
|
||||
attack_verb_simple = "slash"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_vis_effect = ATTACK_EFFECT_SLASH
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
playstyle_string = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, \
|
||||
can phase through walls, and your attacks will lower the cooldown on phasing.</b>"
|
||||
|
||||
// Accomplishing various things gives you a refund on jaunt, to jump in and out.
|
||||
/// The seconds refunded per attack
|
||||
var/attack_refund = 1 SECONDS
|
||||
/// The seconds refunded when putting a target into critical
|
||||
var/crit_refund = 5 SECONDS
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/AttackingTarget() //refund jaunt cooldown when attacking living targets
|
||||
var/prev_stat
|
||||
var/mob/living/living_target = target
|
||||
|
||||
if(isliving(living_target) && !IS_CULTIST(living_target))
|
||||
prev_stat = living_target.stat
|
||||
|
||||
. = ..()
|
||||
if(!. || !isnum(prev_stat))
|
||||
return
|
||||
|
||||
var/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/jaunt = locate() in actions
|
||||
if(!jaunt)
|
||||
return
|
||||
|
||||
var/total_refund = 0 SECONDS
|
||||
// they're dead, and you killed them - full refund
|
||||
if(QDELETED(living_target) || (living_target.stat == DEAD && prev_stat != DEAD))
|
||||
total_refund += jaunt.cooldown_time
|
||||
// you knocked them into critical
|
||||
else if(HAS_TRAIT(living_target, TRAIT_CRITICAL_CONDITION) && prev_stat == CONSCIOUS)
|
||||
total_refund += crit_refund
|
||||
|
||||
if(living_target.stat != DEAD && prev_stat != DEAD)
|
||||
total_refund += attack_refund
|
||||
|
||||
jaunt.next_use_time -= total_refund
|
||||
jaunt.build_all_button_icons()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
|
||||
//////////////////////////Wraith-alts////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/wraith/angelic
|
||||
theme = THEME_HOLY
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/angelic,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
loot = list(/obj/item/ectoplasm/angelic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/mystic
|
||||
theme = THEME_WIZARD
|
||||
construct_spells = list(
|
||||
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/shift/mystic,
|
||||
/datum/action/innate/cult/create_rune/tele,
|
||||
)
|
||||
loot = list(/obj/item/ectoplasm/mystic)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/noncult
|
||||
@@ -76,9 +76,8 @@
|
||||
. = ..()
|
||||
if(!. || !client)
|
||||
return FALSE
|
||||
if(directive)
|
||||
to_chat(src, span_spider("Your mother left you a directive! Follow it at all costs."))
|
||||
to_chat(src, span_spider("<b>[directive]</b>"))
|
||||
var/datum/antagonist/spider/spider_antag = new(directive)
|
||||
mind.add_antag_datum(spider_antag)
|
||||
GLOB.spidermobs[src] = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/giant_spider/Destroy()
|
||||
|
||||
+3
-2
@@ -525,7 +525,7 @@
|
||||
/datum/objective/revenant_fluff
|
||||
|
||||
/datum/objective/revenant_fluff/New()
|
||||
var/list/explanationTexts = list(
|
||||
var/list/explanation_texts = list(
|
||||
"Assist and exacerbate existing threats at critical moments.", \
|
||||
"Impersonate or be worshipped as a god.", \
|
||||
"Cause as much chaos and anger as you can without being killed.", \
|
||||
@@ -538,8 +538,9 @@
|
||||
"Make the captain as miserable as possible.", \
|
||||
"Prevent the use of energy weapons where possible.",
|
||||
)
|
||||
explanation_text = pick(explanationTexts)
|
||||
explanation_text = pick(explanation_texts)
|
||||
..()
|
||||
|
||||
/datum/objective/revenant_fluff/check_completion()
|
||||
return TRUE
|
||||
|
||||
@@ -132,66 +132,6 @@
|
||||
mob_mind.add_antag_datum(antag_datum_to_give, antag_team)
|
||||
antag_team.players_spawned += (spawned_mob.ckey)
|
||||
|
||||
/datum/team/battlecruiser
|
||||
name = "\improper Battlecruiser Crew"
|
||||
member_name = "crewmember"
|
||||
/// The central objective of this battlecruiser
|
||||
var/core_objective = /datum/objective/nuclear
|
||||
/// The assigned nuke of this team
|
||||
var/obj/machinery/nuclearbomb/nuke
|
||||
|
||||
/datum/team/battlecruiser/proc/update_objectives()
|
||||
if(core_objective)
|
||||
var/datum/objective/objective = new core_objective()
|
||||
objective.team = src
|
||||
objectives += objective
|
||||
|
||||
/datum/antagonist/battlecruiser
|
||||
name = "Battlecruiser Crewmember"
|
||||
show_to_ghosts = TRUE
|
||||
roundend_category = "battlecruiser syndicate operatives"
|
||||
suicide_cry = "FOR THE SYNDICATE!!!"
|
||||
antag_hud_name = "battlecruiser_crew"
|
||||
job_rank = ROLE_BATTLECRUISER_CREW
|
||||
var/datum/team/battlecruiser/battlecruiser_team
|
||||
|
||||
/datum/antagonist/battlecruiser/get_team()
|
||||
return battlecruiser_team
|
||||
|
||||
/datum/antagonist/battlecruiser/greet()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE)
|
||||
to_chat(owner, span_big("You are a [name]!"))
|
||||
owner.announce_objectives()
|
||||
|
||||
/datum/antagonist/battlecruiser/ally
|
||||
name = "Battlecruiser Ally"
|
||||
show_to_ghosts = FALSE
|
||||
|
||||
/datum/antagonist/battlecruiser/captain
|
||||
name = "Battlecruiser Captain"
|
||||
antag_hud_name = "battlecruiser_lead"
|
||||
job_rank = ROLE_BATTLECRUISER_CAPTAIN
|
||||
|
||||
/datum/antagonist/battlecruiser/create_team(datum/team/battlecruiser/team)
|
||||
if(!team)
|
||||
return
|
||||
if(!istype(team))
|
||||
stack_trace("Wrong team type passed to [type] initialization.")
|
||||
battlecruiser_team = team
|
||||
|
||||
/datum/antagonist/battlecruiser/apply_innate_effects(mob/living/mob_override)
|
||||
add_team_hud(mob_override || owner.current, /datum/antagonist/battlecruiser)
|
||||
|
||||
/datum/antagonist/battlecruiser/on_gain()
|
||||
if(battlecruiser_team)
|
||||
objectives |= battlecruiser_team.objectives
|
||||
if(battlecruiser_team.nuke)
|
||||
var/obj/machinery/nuclearbomb/nuke = battlecruiser_team.nuke
|
||||
antag_memory += "<B>[nuke] Code</B>: [nuke.r_code]<br>"
|
||||
owner.add_memory(/datum/memory/key/nuke_code, nuclear_code = nuke.r_code)
|
||||
to_chat(owner, "The nuclear authorization code is: <B>[nuke.r_code]</B>")
|
||||
return ..()
|
||||
|
||||
/datum/outfit/syndicate_empty/battlecruiser
|
||||
name = "Syndicate Battlecruiser Ship Operative"
|
||||
belt = /obj/item/storage/belt/military/assault
|
||||
|
||||
Reference in New Issue
Block a user