Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heretic sacrifice refactor! #3279

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions code/__DEFINES/traits/monkestation/declarations.dm
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
#define TRAIT_CANT_STAMCRIT "cant_stamcrit"
/// This mob will automatically revive when healed enough.
#define TRAIT_REVIVES_BY_HEALING "trait_revives_by_healing"
/// This mob is a ghost critter.
#define TRAIT_GHOST_CRITTER "ghost_critter"

// /datum/mind + /mob/living
/// Prevents the user from casting spells using sign language. Works on both /datum/mind and /mob/living.
Expand Down
21 changes: 21 additions & 0 deletions code/__HELPERS/~monkestation-helpers/mobs.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Gets the mind from a variable, whether it be a mob, or a mind itself.
* Also works on brains - it will try to fetch the brainmob's mind.
* If [include_last] is true, then it will also return last_mind for carbons if there isn't a current mind.
*/
/proc/get_mind(target, include_last = FALSE) as /datum/mind
RETURN_TYPE(/datum/mind)
if(istype(target, /datum/mind))
return target
else if(ismob(target))
var/mob/mob_target = target
if(!QDELETED(mob_target.mind))
return mob_target.mind
if(include_last && iscarbon(mob_target))
var/mob/living/carbon/carbon_target = mob_target
if(!QDELETED(carbon_target.last_mind))
return carbon_target.last_mind
else if(istype(target, /obj/item/organ/internal/brain))
var/obj/item/organ/internal/brain/brain = target
if(!QDELETED(brain.brainmob?.mind))
return brain.brainmob.mind
1 change: 1 addition & 0 deletions code/_globalvars/traits/_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_GAMERGOD" = TRAIT_GAMERGOD,
"TRAIT_GARLIC_BREATH" = TRAIT_GARLIC_BREATH,
"TRAIT_GENELESS" = TRAIT_GENELESS,
"TRAIT_GHOST_CRITTER" = TRAIT_GHOST_CRITTER,
"TRAIT_GIANT" = TRAIT_GIANT,
"TRAIT_GONE_FISHING" = TRAIT_GONE_FISHING,
"TRAIT_GOURMAND" = TRAIT_GOURMAND,
Expand Down
3 changes: 3 additions & 0 deletions code/datums/mocking/client.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@

/datum/client_interface/proc/set_right_click_menu_mode()
return

/datum/client_interface/proc/is_afk(duration)
return FALSE
13 changes: 11 additions & 2 deletions code/modules/antagonists/heretic/heretic_antag.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@
var/total_sacrifices = 0
/// A list of TOTAL how many high value sacrifices completed. (Heads of staff)
var/high_value_sacrifices = 0
/* monkestation removal: sacrifice refactor (see [monkestation\code\modules\antagonists\heretic])
/// Lazy assoc list of [refs to humans] to [image previews of the human]. Humans that we have as sacrifice targets.
var/list/mob/living/carbon/human/sac_targets
/// List of all sacrifice target's names, used for end of round report
var/list/all_sac_targets = list()
monkestation end */
/// Whether we're drawing a rune or not
var/drawing_rune = FALSE
/// A static typecache of all tools we can scribe with.
Expand Down Expand Up @@ -82,9 +84,11 @@
PATH_MOON = COLOR_BLUE_LIGHT,
)

/* monkestation removal: sacrifice refactor
/datum/antagonist/heretic/Destroy()
LAZYNULL(sac_targets)
return ..()
monkestation end */

/datum/antagonist/heretic/ui_data(mob/user)
var/list/data = list()
Expand Down Expand Up @@ -428,6 +432,7 @@
other_sac_objective.owner = owner
objectives += other_sac_objective

/* monkestation removal: sacrifice refactor (see [monkestation\code\modules\antagonists\heretic])
/**
* Add [target] as a sacrifice target for the heretic.
* Generates a preview image and associates it with a weakref of the mob.
Expand Down Expand Up @@ -461,6 +466,7 @@
SIGNAL_HANDLER

remove_sacrifice_target(source)
monkestation end */

/**
* Increments knowledge by one.
Expand All @@ -479,7 +485,7 @@

parts += printplayer(owner)
parts += "<b>Sacrifices Made:</b> [total_sacrifices]"
parts += "The heretic's sacrifice targets were: [english_list(all_sac_targets, nothing_text = "No one")]."
parts += "The heretic's sacrifice targets were: [roundend_sac_list()]." // monkestation edit: sacrifice refactor
if(length(objectives))
var/count = 1
for(var/datum/objective/objective as anything in objectives)
Expand Down Expand Up @@ -565,6 +571,7 @@
to_chat(admin, span_warning("You shouldn't be using this!"))
return

var/list/sac_targets = get_current_target_bodies() // monkestation edit: heretic refactor
var/list/removable = list()
for(var/mob/living/carbon/human/old_target as anything in sac_targets)
removable[old_target.name] = old_target
Expand Down Expand Up @@ -626,10 +633,10 @@

. += "<br>"
. += "<i><b>Current Targets:</b></i><br>"
var/list/sac_targets = get_current_target_bodies() // monkestation edit: heretic refactor
if(LAZYLEN(sac_targets))
for(var/mob/living/carbon/human/target as anything in sac_targets)
. += " - <b>[target.real_name]</b>, the [target.mind?.assigned_role?.title || "human"].<br>"

else
. += "<i>None!</i><br>"
. += "<br>"
Expand Down Expand Up @@ -796,11 +803,13 @@
name = "summon monsters"
target_amount = 2
explanation_text = "Summon 2 monsters from the Mansus into this realm."
/* monkestation removal: refactored in [monkestation\code\modules\antagonists\heretic\heretic_antag.dm]
/// The total number of summons the objective owner has done
var/num_summoned = 0

/datum/objective/heretic_summon/check_completion()
return completed || (num_summoned >= target_amount)
monkestation end */

/datum/outfit/heretic
name = "Heretic (Preview only)"
Expand Down
2 changes: 2 additions & 0 deletions code/modules/antagonists/heretic/heretic_knowledge.dm
Original file line number Diff line number Diff line change
Expand Up @@ -576,8 +576,10 @@
var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
heretic_monster.set_owner(user.mind)

/* monkestation removal: heretic refactoring
var/datum/objective/heretic_summon/summon_objective = locate() in user.mind.get_all_objectives()
summon_objective?.num_summoned++
monkestation end */

return TRUE

Expand Down
4 changes: 4 additions & 0 deletions code/modules/antagonists/heretic/heretic_living_heart.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
right_clicked = !!(trigger_flags & TRIGGER_SECONDARY_ACTION)
return ..()

/* monkestation removal: replaced in [monkestation\code\modules\antagonists\heretic\heretic_living_heart.dm]
/datum/action/cooldown/track_target/Activate(atom/target)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(owner)
var/datum/heretic_knowledge/sac_knowledge = heretic_datum.get_knowledge(/datum/heretic_knowledge/hunt_and_sacrifice)
Expand Down Expand Up @@ -151,6 +152,7 @@

StartCooldown()
return TRUE
monkestation end */

/// Callback for the radial to ensure it's closed when not allowed.
/datum/action/cooldown/track_target/proc/check_menu()
Expand All @@ -160,6 +162,7 @@
return FALSE
return TRUE

/* monkestation removal: replaced in [monkestation\code\modules\antagonists\heretic\heretic_living_heart.dm]
/// Gets the balloon message for who we're tracking.
/datum/action/cooldown/track_target/proc/get_balloon_message(mob/living/carbon/human/tracked_mob)
var/balloon_message = "error text!"
Expand Down Expand Up @@ -218,3 +221,4 @@
balloon_message = "they're dead, " + balloon_message

return balloon_message
monkestation end */
3 changes: 1 addition & 2 deletions code/modules/antagonists/heretic/knowledge/general_side.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@

/datum/heretic_knowledge/reroll_targets/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
for(var/mob/living/carbon/human/target as anything in heretic_datum.sac_targets)
heretic_datum.remove_sacrifice_target(target)
LAZYNULL(heretic_datum.current_sac_targets)

var/datum/heretic_knowledge/hunt_and_sacrifice/target_finder = heretic_datum.get_knowledge(/datum/heretic_knowledge/hunt_and_sacrifice)
if(!target_finder)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* monkestation removal: refactored in [monkestation\code\modules\antagonists\heretic\knowledge\sacrifice_knowledge\sacrifice_knowledge.dm]
// The knowledge and process of heretic sacrificing.

/// How long we put the target so sleep for (during sacrifice).
Expand Down Expand Up @@ -526,3 +527,4 @@

#undef SACRIFICE_SLEEP_DURATION
#undef SACRIFICE_REALM_DURATION
monkestation end */
8 changes: 8 additions & 0 deletions monkestation/code/datums/mind/_mind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
/// The locked manifest entry for this crew member, if any.
var/datum/record/locked/lockfile

/datum/mind/Destroy()
crewfile = null
lockfile = null
return ..()

/datum/mind/proc/add_to_manifest(crew = TRUE, locked = FALSE)
if(crew && !QDELETED(crewfile))
GLOB.manifest.general |= crewfile
Expand All @@ -15,3 +20,6 @@
GLOB.manifest.general -= crewfile
if(locked && !QDELETED(lockfile))
GLOB.manifest.locked -= lockfile

/datum/mind/proc/operator""()
return trimtext(name || current?.real_name || current?.name)
119 changes: 119 additions & 0 deletions monkestation/code/modules/antagonists/heretic/heretic_antag.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/datum/antagonist/heretic
/// Weakrefs to the minds of monsters have been successfully summoned. Includes ghouls.
var/list/datum/weakref/monsters_summoned
/// Lazy assoc list of [weakrefs to minds] to [image previews of the human]. Humans that we have as sacrifice targets.
var/list/datum/weakref/current_sac_targets
/// List of [weakrefs to minds], containing all the minds we've ever had as sacrifice targets. Used for the end-of-round report.
var/list/datum/weakref/all_sac_targets
/// Lazy assoc list of [weakrefs to minds] that we've sacrificed. [weakref to mind] = TRUE
var/list/datum/weakref/completed_sacrifices

/datum/antagonist/heretic/Destroy()
LAZYNULL(monsters_summoned)
LAZYNULL(current_sac_targets)
LAZYNULL(all_sac_targets)
LAZYNULL(completed_sacrifices)
return ..()

/**
* Add [target] as a sacrifice target for the heretic.
* Generates a preview image and associates it with a weakref of the mob's mind.
*/
/datum/antagonist/heretic/proc/add_sacrifice_target(target)
. = FALSE
var/datum/mind/target_mind = get_mind(target, include_last = TRUE)
if(QDELETED(target_mind))
return FALSE
var/mob/living/carbon/target_body = target_mind.current
if(!istype(target_body))
return FALSE
var/datum/weakref/target_ref = WEAKREF(target_mind)
LAZYOR(all_sac_targets, target_ref)
LAZYSET(current_sac_targets, target_ref, getFlatIcon(target_body, defdir = SOUTH))
return TRUE

/**
* Remove [target] as a sacrifice target for the heretic.
*/
/datum/antagonist/heretic/proc/remove_sacrifice_target(target, remove_from_all = FALSE)
. = FALSE
var/datum/mind/target_mind = get_mind(target, include_last = TRUE)
if(!QDELETED(target_mind))
var/datum/weakref/target_ref = WEAKREF(target_mind)
LAZYREMOVE(current_sac_targets, target_ref)
if(remove_from_all)
LAZYREMOVE(all_sac_targets, target_ref)
return TRUE

/**
* Returns a list of minds of valid sacrifice targets from the current living players.
*/
/datum/antagonist/heretic/proc/possible_sacrifice_targets(include_current_targets = TRUE) as /list
RETURN_TYPE(/list)
. = list()
for(var/mob/living/carbon/human/player in GLOB.alive_player_list)
if(QDELETED(player.mind))
continue
var/datum/client_interface/player_client = GET_CLIENT(player)
if(QDELETED(player_client) || player_client.is_afk())
continue
var/datum/mind/possible_target = player.mind
if(possible_target == owner)
continue
if(possible_target.get_effective_opt_in_level() < OPT_IN_YES_KILL)
continue
if(!(possible_target.assigned_role?.job_flags & JOB_CREW_MEMBER))
continue
var/datum/weakref/target_weakref = WEAKREF(possible_target)
if(!include_current_targets && LAZYACCESS(current_sac_targets, target_weakref))
continue
if(LAZYACCESS(completed_sacrifices, target_weakref))
continue
var/turf/player_loc = get_turf(player)
if(!is_station_level(player_loc?.z))
continue
if(player.stat >= SOFT_CRIT)
continue
. += possible_target

/**
* Check to see if the given mob can be sacrificed.
*/
/datum/antagonist/heretic/proc/can_sacrifice(target)
. = FALSE
var/datum/mind/target_mind = get_mind(target, include_last = TRUE)
if(!istype(target_mind))
return
var/datum/weakref/mind_weakref = WEAKREF(target_mind)
if(LAZYACCESS(current_sac_targets, mind_weakref))
return TRUE
if(LAZYACCESS(completed_sacrifices, mind_weakref))
return FALSE
// You can ALWAYS sacrifice heads of staff if you need to do so.
var/datum/objective/major_sacrifice/major_sacc_objective = locate() in objectives
if(major_sacc_objective && !major_sacc_objective.check_completion() && (target_mind.assigned_role?.departments_bitflags & DEPARTMENT_BITFLAG_COMMAND))
return TRUE

/datum/antagonist/heretic/proc/get_current_target_bodies() as /list
RETURN_TYPE(/list)
. = list()
for(var/datum/weakref/mind_ref as anything in current_sac_targets)
var/datum/mind/target_mind = mind_ref?.resolve()
if(QDELETED(target_mind))
continue
if(ishuman(target_mind.current))
. += target_mind.current

/datum/antagonist/heretic/proc/roundend_sac_list()
. = @"[ ERROR, PLEASE REPORT TO GITHUB! ]"
var/list/names = list()
for(var/datum/weakref/target_ref as anything in all_sac_targets)
var/datum/mind/target = target_ref?.resolve()
if(QDELETED(target))
continue
names += LAZYACCESS(completed_sacrifices, target_ref) ? "<b>[target.name]</b>" : "[target.name]"
return english_list(names, nothing_text = "No one")

/datum/objective/heretic_summon/check_completion()
var/datum/antagonist/heretic/heretic_datum = owner?.has_antag_datum(/datum/antagonist/heretic)
return ..() || (LAZYLEN(heretic_datum?.monsters_summoned) >= target_amount)
Loading
Loading