Heretic Antagonist Full Overhaul. (#92119)

## About The Pull Request

Heretic has received a complete overhaul. This PR touches nearly every
aspect of the antagonist. For readability's sake, not every change is
going to be listed in this pull request.

For the full list of changes please refer to the design doc:
https://hackmd.io/@BiST8PJVRjiwVPY86U3bLQ/B11HyChz1g.

Code by Me, @Xander3359 and @Arturlang 

TGUI by @Arturlang 

Sprites by OrcaCora and GregorDM

Writing bits by @necromanceranne 

### Core changes

- Cross-pathing has been removed. Main knowledge spells are now
exclusive to their path (for the most part).

- For every main knowledge unlocked (save for the robes and the blade
upgrade), Heretics can choose one option from a draft of 3 random side
knowledges (this is a free point).

- Heretics can now purchase side knowledges from a new tab, the
"Knowledge Shop". Side-knowledges have been divided by tier (Stealth,
Defense, Summons, Combat and Main). Tiers are unlocked as you progress
toward your main path.

- Heretics now gain the grasp and mark upgrade immediately, but their
main knowledge choices cost twice as much (except for the first spell,
the robes and the blade upgrade).

- Path specific robes have been introduced! They come with their own set
of quirks.

- Each Path has received a passive ability. This passive is upgraded
when you first create your robes, and again when you complete the Ritual
of Knowledge.

- Paths have been rebalanced as a result of the removal of cross-path
progression. Cosmic and Moon paths have received soft reworks.

- Upon unlocking the path 2nd level or reaching a total of 8 points
worth of knowledge, Heretics will lose the ability to blade break (and
the limit on blades all together).

- Ascension now automatically calls the shuttle with no possibility of a
recall.

- Late join Heretic has been removed.

### New UI 
<img width="750" height="635" alt="moon path ui"
src="https://github.com/user-attachments/assets/184ef783-5c9c-48a1-a2f7-4807ca93e990"
/>


### Knowledge shop

<img width="787" height="669" alt="Knowledge shop"
src="https://github.com/user-attachments/assets/3dc89b84-8c70-4d47-b612-54396e3ea6e7"
/>




### Quality of life //General balance changes

- Heretics will now gain X-ray vision for a few seconds when nearby an
eldritch essence (this effect has a cooldown).

- Ritual of knowledge now requires 1 uncommon item instead of 2. You may
now use a stunprod instead of a baton to complete the ritual. Beartraps
have been removed from the list of possible reagents.

- The maximum number of possible sacrifices required to ascend has been
reduced from 6 to 5 while the minimum has been upped to 4.

- Codex Cicatrix no longer requires a special pen to be made.

### Passive abilities

- Heretics now start with a passive ability. You can find what it does
on the path info tab after a path has been selected, and what they gain
when upgraded.

- Crafting your first set of Eldritch robes will bump your passive to
level 2.

- Unlocking the 2nd level will subsequently unlock your "Ritual Of
Knowledge"

- Completing the ritual of knowledge or ascending will net you the final
level.

### Path Specific Robes

- Armorer's Ritual is no longer a side knowledge. Each path will have
their own unique version of the ritual. This is placed after the 2nd
spell in the tree.

- Robes can no longer be destroyed by fire and acid, grant t4 flash
protection (Moth Heretics stay winning) and protection against basic
syringes, to bring them on par with other antagonist's armor sets.

- The recipe to craft the robes is now a set of armor/vest, a mask (any
mask will do now, not just gas masks), plus the unique reagent required
for the blades (Plasma for Cosmic, Trash For Rust, match for Ash and so
on)

- Wearing the robes as a non-heretic may yield some unfortunate
side-effects.

### Moon Path Rework

Moon path  rework.

Moon Heretics gain immunity to brain traumas and slowly regenerate brain
health. Equipping the moon amulette channels its effects through the
moon blade; making it unblockable and cause sanity damage instead of
brute. Ring leader's Rise now summons an army of harmless clones that
explode when attacked; the explosion briefly stuns non-heretics and
cause sanity and brain damage to them. Moon blade can also now be used
when pacified and Moon spells are no longer blocked by regular anti
magic, only mind magic protection.


**Cosmic Path Rework**

Cosmic path has received the biggest batch of changes alongside Moon.
The path has been dead last in ascension and pickrate (less than 5%) for
almost 2 years. It did gain some popularity over the last few months,
reaching the highest ascension rate in the game (12%) while mantaining a
relatively low pickrate.

Cosmic sits in a weird spot, where pretty much every knowledge
surrounding the path is either mediocre or, in the case of the
ascension, dysfunctional. Yet it has maintained a smidge of relevancy
due to how quickly Cosmic heretics can capture and sacrifice targets
thanks to Star Touch.

As a result, the best course of action would be to rebalance the
entirety of the kit; granting the heretic more tools to manipulate space
and dictate the flow of a fight, while lessening their ability to end a
confrontation by instantly sleeping their opponents.

lastly The Star Gazer is now ghost controlled ; And they shoot lazers!

<img width="636" height="451" alt="gazer gag 3"
src="https://github.com/user-attachments/assets/601d6881-c042-4e42-8ce6-ac90cd27848b"
/>


## Why It's Good For The Game


### Ok...but why do we want this?

Again, if you want my full reasoning, please check my doc
https://hackmd.io/@BiST8PJVRjiwVPY86U3bLQ/B11HyChz1g.

To keep it short and concise; Heretic is too complex and unintuitive for
its own good. Too impenetrable for new players and too abusable for
experienced players. This can be chalked up to a lot of poor design
decisions. But ultimately, what I believe being the biggest contributor
to the current status of Heretic is the ability to move into different
paths, also known as "Cross-Pathing".

### Cross Pathing my beloathed.

Cross-pathing, while cool in theory, overcomplicates the antagonist and
overloads them with power. Players dealing with the heretic are
incapable of working out what a given heretic can do. This also leads to
late game heretics having 3 rows Worth of action buttons and virtually
no weakness.

Over the last year, I've often received the understandable but also kind
of unfair accusations of making Heretic too powerful without a clear aim
or purpose.

My goal with the paths I've reworked over the last year (Rust,Void and
Blade) wasn't necessarily to just make them stronger (although that was
also part of the goal, as they were paths that were underperforming),
but for them to have more interactions with the sandbox and to better
live up to the fantasy presented to the player.

If an harbringer of frost gets countered by a cup of coffee, we probably
messed something up.


Unfortunately, the current incarnation of Heretic doesn't really allow
for surgical balance changes to specific paths. Every time a knowledge
gets buffed, we make every path that can easily tap onto that knowledge
stronger by default. It doesn't take a genius to understand why this
system is ultimately unsustainable.

### Blade Breaking

I feel that after a heretic has reached the near peak of their power,
they no longer need the ability to instantly escape any encounter. Check
my doc for my full reasoning.

## Less versatile, more specialized paths.

By removing cross-pathing, we remove a huge maintainability burden from
the antagonist. Paths can now be designed around clearer strengths and
weaknesses. They become easier to balance and less of an headache to
understand for everyone.

It also means we can give paths some needed quality of life quirks
without having to worry how such a change might have a knock-on effect
for other paths.

Ash heretics can finally let loose without dying by their own flames.
Cosmic Heretic can go to space without having to carry a modsuit. Moon
Heretic can use their abilities without fear of one random trauma
ruining their day, and so on.

### What a horrible night to have a curse...., wait how do I curse
people again?

As of right now the heretic tree has quite a hefty amount of trinkets
that pretty much never see use.

Partly because the tree itself is a nightmare to navigate. And partly
because why would anyone set up an elaborate plan or scheme when they
can unleash 2 rows of spell in the span of bunch of seconds.

Heretics mostly gravitate towards powers that push them towards greater,
more potent combat strength. If it doesn't contribute to killing people
quicker, it isn't worth doing for most. And given the opportunity cost
associated for taking those powers, they will remain that way so long as
there are better choices to be poached.

The new draft system encourages Heretics to play more with the tools at
their disposal. If you want to go for a specific combo from the side
path options, you may now do so by tapping into the knowledge shop.

Yes, the shop does include a few knowledges from the other paths. But
these are limited to 1 per path, are very expensive and can only be
unlocked very late into the shift.

## Drip Of the Mansus

The iconic heretic robe is actually sequestered to a side path that is
most easily access by only two paths at a time. Since heretic paths are
being made to be much more specialized, the most obvious way in which
this can be showcased is through an easily
identifiable outfit.

By using the robes, we can both telegraph WHAT heretic you are looking
at, and just how much power they've accumulated and when it is
reasonable to take the kid gloves off and treat them as a genuine
threat. If a heretic is in their
robes, that heretic is now a significantly more prominent danger to the
station.

It also serves as a useful means for gating some of the more powerful
effects of a heretic's path behind the robes, AND enable options for
disarming them of that power should they be captured without making it
something endemic to their mob.

A major problem with heretics is a lack of certainty as to how powerful
they have become. A heretics robes is one of the milestones to help
players dealing with heretics identify that.

### Will this be 100% fair and balanced?

This is a massive overhaul to a pretty complex and bloated antagonist.
I've done my best to show the changes to several maintainers and other
members of the community for their feedback. But at some point we'll
have to see how this behave in the environment to get a feel if
something is over or undertuned. (that's my way of saying, yes this is
likely gonna require a testmerge or two).

What I will say is that I'm not trying to change the core identity of
Heretic.

Heretics should have the upperhand in single encounters early on, be
able to joust a small group of players after they unlock their final
spell, and end the round when they ascend. They're a progression
antagonist. They should retain their payoff as well as pose a danger as
they grow stronger.

But if more players feel like they are more reliably able to play the
antagonist in more varied and interesting ways, rather than the
antagonist largely existing as a measuring stick for 'robustness' due to
its elitist design philosophy, then the rework has been a success. There
should be something for
everyone in the antagonist, as is true for all of our antagonist roles.
This commit is contained in:
EnterTheJake
2025-10-16 00:34:51 +02:00
committed by GitHub
parent b739e1ed08
commit a2c7c8e57b
172 changed files with 6093 additions and 2244 deletions

2
.github/CODEOWNERS vendored
View File

@@ -225,6 +225,8 @@
/tools/build/ @scriptis @stylemistake
/tools/tgs_scripts/ @Cyberboss @scriptis
/code/modules/antagonists/heretic @Xander3359 @EnterTheJake
# Host Hell
/code/controllers/configuration/entries @scriptis

View File

@@ -101,15 +101,53 @@
#define HKT_NEXT "next"
#define HKT_BAN "ban"
#define HKT_DEPTH "depth"
#define HKT_PURCHASED_DEPTH "purchased_depth"
#define HKT_ROUTE "route"
#define HKT_UI_BGR "ui_bgr"
#define HKT_COST "cost"
#define HKT_CATEGORY "category"
/// Only present for already researched knowledge.
#define HKT_INSTANCE "instance"
/// unique identifier most commonly used for identifying what knowledge is researchable
#define HKT_ID "id"
#define BGR_SIDE "node_side"
#define MAGIC_RESISTANCE_MOON (MAGIC_RESISTANCE|MAGIC_RESISTANCE_MIND)
/// Defines are used in /proc/has_living_heart() to report if the heretic has no heart period, no living heart, or has a living heart.
#define HERETIC_NO_HEART_ORGAN -1
#define HERETIC_NO_LIVING_HEART 0
#define HERETIC_HAS_LIVING_HEART 1
#define HERETIC_DRAFT_TIER_MAX 5
/// The default drain speed for heretic rift's, anything below this will be considered a fast drain, and be very noticeable and cause a overlay
#define HERETIC_RIFT_DEFAULT_DRAIN_SPEED 10 SECONDS
/// Sources of knowledge purchased for heretics, used for positioning in the UI
#define HERETIC_KNOWLEDGE_TREE "tree"
#define HERETIC_KNOWLEDGE_SHOP "shop"
#define HERETIC_KNOWLEDGE_DRAFT "draft"
#define HERETIC_KNOWLEDGE_START "start"
/// defines for the depths of the heretic knowledge tree nodes
#define HKT_DEPTH_START 2
#define HKT_DEPTH_TIER_1 3
#define HKT_DEPTH_DRAFT_1 4
#define HKT_DEPTH_TIER_2 5
#define HKT_DEPTH_DRAFT_2 6
#define HKT_DEPTH_ROBES 7
#define HKT_DEPTH_TIER_3 8
#define HKT_DEPTH_DRAFT_3 9
#define HKT_DEPTH_ARMOR 10
#define HKT_DEPTH_TIER_4 11
#define HKT_DEPTH_DRAFT_4 12
#define HKT_DEPTH_ASCENSION 13
#define HERETIC_CAN_ASCEND "can_ascend"
/// A define used in ritual priority for heretics.
#define MAX_KNOWLEDGE_PRIORITY 100

View File

@@ -68,6 +68,7 @@
#define CALTROP_SILENT (1 << 2)
#define CALTROP_NOSTUN (1 << 3)
#define CALTROP_NOCRAWL (1 << 4)
#define CALTROP_ANTS (1 << 5)
//Ingredient type in datum/component/ingredients_holder
#define CUSTOM_INGREDIENT_TYPE_EDIBLE 1

View File

@@ -72,3 +72,10 @@
/// Called on the atom being hit, from /datum/component/anti_magic/on_attack() : (obj/item/weapon, mob/user, antimagic_flags)
#define COMSIG_ATOM_HOLYATTACK "atom_holyattacked"
/// Called from [/mob/living/proc/send_item_attack_message()]: (obj/item/weapon, /mob/living/victim, mob/living/attacker)
#define COMSIG_SEND_ITEM_ATTACK_MESSAGE_OBJECT "send_item_attack_message_object"
/// Called from [/mob/living/proc/send_item_attack_message()]: (mob/living/victim, obj/item/weapon, mob/living/user)
#define COMSIG_SEND_ITEM_ATTACK_MESSAGE_CARBON "send_item_attack_message_carbon"
/// Return value if the hitby messages are changed.
#define SIGNAL_MESSAGE_MODIFIED (1<<0)

View File

@@ -2,6 +2,8 @@
//Food
// Eating stuff
/// From datum/component/edible/proc/TakeBite: (atom/owner)
#define COMSIG_LIVING_EAT_FOOD "food_bit"
/// From datum/component/edible/proc/TakeBite: (mob/living/eater, mob/feeder, bitecount, bitesize)
#define COMSIG_FOOD_EATEN "food_eaten"
#define DESTROY_FOOD (1<<0)

View File

@@ -16,3 +16,11 @@
/// For [/datum/status_effect/protective_blades] to signal when it is triggered
#define COMSIG_BLADE_BARRIER_TRIGGERED "blade_barrier_triggered"
/// at the end of determine_drafted_knowledge
#define COMSIG_HERETIC_SHOP_SETUP "heretic_shop_finished"
/// called on the antagonist datum, upgrades the passive to level 2
#define COMSIG_HERETIC_PASSIVE_UPGRADE_FIRST "heretic_passive_upgrade_first"
/// called on the antagonist datum, upgrades the passive to level 3
#define COMSIG_HERETIC_PASSIVE_UPGRADE_FINAL "heretic_passive_upgrade_final"

View File

@@ -16,6 +16,8 @@
#define COMSIG_ORGAN_SURGICALLY_INSERTED "organ_surgically_inserted"
/// Called when an organ finishes inserting into a bodypart (obj/item/bodypart/limb, movement_flags)
#define COMSIG_ORGAN_BODYPART_INSERTED "organ_bodypart_inserted"
/// Called when a organ's damage is adjusted apply_organ_damage (damage_amount, maximum, required_organ_flag)
#define COMSIG_ORGAN_ADJUST_DAMAGE "organ_adjust_damage"
///Called when movement intent is toggled.
#define COMSIG_MOVE_INTENT_TOGGLED "move_intent_toggled"

View File

@@ -148,6 +148,8 @@
#define COMSIG_ITEM_DRIED "item_dried"
///from base of obj/item/dropped(): (mob/user)
#define COMSIG_ITEM_DROPPED "item_drop"
///a mob has just dropped an item
#define COMSIG_MOB_DROPPED_ITEM "mob_dropped_item"
///from base of obj/item/pickup(): (/mob/taker)
#define COMSIG_ITEM_PICKUP "item_pickup"
///from base of obj/item/on_outfit_equip(): (mob/equipper, visuals_only, slot)

View File

@@ -0,0 +1,2 @@
/// From /datum/status_effect/fire_handler/fire_stacks/tick()
#define COMSIG_FIRE_STACKS_UPDATED "fire_stacks_updated"

View File

@@ -175,6 +175,8 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
#define is_simian(A) (isgorilla(A) || ismonkey(A))
#define isstargazer(A) (istype(A, /mob/living/basic/heretic_summon/star_gazer))
/// returns whether or not the atom is either a basic mob OR simple animal
#define isanimal_or_basicmob(A) (istype(A, /mob/living/simple_animal) || istype(A, /mob/living/basic))

View File

@@ -41,8 +41,6 @@
#define ROLE_VOIDWALKER "Voidwalker"
#define ROLE_SUNWALKER "Sunwalker"
// Latejoin roles
#define ROLE_HERETIC_SMUGGLER "Heretic Smuggler"
#define ROLE_PROVOCATEUR "Provocateur"
#define ROLE_STOWAWAY_CHANGELING "Stowaway Changeling"
#define ROLE_SYNDICATE_INFILTRATOR "Syndicate Infiltrator"

View File

@@ -96,6 +96,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_EMOTEMUTE "emotemute"
#define TRAIT_DEAF "deaf"
#define TRAIT_FAT "fat"
/// If you are fat, you no longer get the slowdown from it
#define TRAIT_FAT_IGNORE_SLOWDOWN "fat_ignore_slowdown"
/// Always hungry. They can eat as much as they want without eating slowdown.
#define TRAIT_GLUTTON "glutton"
#define TRAIT_HUSK "husk"
@@ -180,6 +182,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NUKEIMMUNE "nuke_immunity"
/// Can't be given viruses
#define TRAIT_VIRUSIMMUNE "virus_immunity"
/// Stepping on ants wont cause damage
#define TRAIT_SPACE_ANT_IMMUNITY "space_ant_immunity"
/// Won't become a husk under any circumstances
#define TRAIT_UNHUSKABLE "trait_unhuskable"
/// Reduces the chance viruses will spread to this mob, and if the mob has a virus, slows its advancement
@@ -464,6 +468,14 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_HALLUCINATION_IMMUNE "hallucination_immune"
/// Increases chance of getting special traumas, makes them harder to cure
#define TRAIT_SPECIAL_TRAUMA_BOOST "special_trauma_boost"
//---- Brain trauma resists
/// Unable to gain any brain trauma whatsoever
#define TRAIT_BRAIN_TRAUMA_IMMUNITY "brain_trauma_immunity"
/// Prevents death from having too much brain damage
#define TRAIT_BRAIN_DAMAGE_NODEATH "brain_damage_nodeath"
#define TRAIT_SPACEWALK "spacewalk"
/// Mobs with this trait still breathe gas in and out but aren't harmed by lacking any particular gas mix. (You can still be hurt by TOO MUCH of a specific gas).
#define TRAIT_NO_BREATHLESS_DAMAGE "spacebreathing"
@@ -646,6 +658,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NO_GUN_AKIMBO "no_gun_akimbo"
/// Mobs with this trait cannot be hit by projectiles, meaning the projectiles will just go through.
#define TRAIT_UNHITTABLE_BY_PROJECTILES "unhittable_by_projectiles"
/// Mobs with this trait can never be hit by laser projectiles, meaning the projectiles will just go through.
#define TRAIT_UNHITTABLE_BY_LASERS "unhittable_by_lasers"
/// Mobs with this trait do care about a few grisly things, such as digging up graves. They also really do not like bringing people back to life or tending wounds, but love autopsies and amputations.
#define TRAIT_MORBID "morbid"
@@ -887,8 +901,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_ROD_ATTRACT_SHINY_LOVERS "rod_attract_shiny_lovers"
/// This rod can be used to fish on lava
#define TRAIT_ROD_LAVA_USABLE "rod_lava_usable"
/// This rod was infused by a heretic, making it awesome and improving influence gain
#define TRAIT_ROD_MANSUS_INFUSED "rod_infused"
/// Stuff that can go inside fish cases and aquariums
#define TRAIT_AQUARIUM_CONTENT "aquarium_content"
/// If the item can be used as a bit.
@@ -937,10 +949,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_NO_STRIP "no_strip"
/// Disallows this item from being pricetagged with a barcode
#define TRAIT_NO_BARCODES "no_barcode"
/// Allows heretics to cast their spells.
#define TRAIT_ALLOW_HERETIC_CASTING "allow_heretic_casting"
/// Designates a heart as a living heart for a heretic.
#define TRAIT_LIVING_HEART "living_heart"
/// Prevents the same person from being chosen multiple times for kidnapping objective
#define TRAIT_HAS_BEEN_KIDNAPPED "has_been_kidnapped"
/// An item still plays its hitsound even if it has 0 force, instead of the tap
@@ -962,6 +970,22 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// An item is ALWAYS considered baseline reachable and will pipe into CanBeReached().
#define TRAIT_SKIP_BASIC_REACH_CHECK "skip_basic_reach_check"
//---- Heretic Traits
/// Hides the heretic overlay that outs them as the heretic
#define TRAIT_HERETIC_AURA_HIDDEN "heretic_aura_hidden"
/// This rod was infused by a heretic, making it awesome and improving influence gain
#define TRAIT_ROD_MANSUS_INFUSED "rod_infused"
/// Allows heretics to cast their spells.
#define TRAIT_ALLOW_HERETIC_CASTING "allow_heretic_casting"
/// Designates a heart as a living heart for a heretic.
#define TRAIT_LIVING_HEART "living_heart"
/// Trait given to all participants in a heretic arena
#define TRAIT_ELDRITCH_ARENA_PARTICIPANT "eldritch_arena_participant"
/// Trait given to heretic summons, making them immune to heretic spells
#define TRAIT_HERETIC_SUMMON "heretic_summon"
/// Lock heretic grasp no longer goes on cooldown when opening things
#define TRAIT_LOCK_GRASP_UPGRADED "lock_grasp_upgraded"
//quirk traits
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_ANOSMIA "anosmia"
@@ -1393,9 +1417,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait given to anything linked to, not necessarily allied to, the mansus
#define TRAIT_MANSUS_TOUCHED "mansus_touched"
/// Trait given to all participants in a heretic arena
#define TRAIT_ELDRITCH_ARENA_PARTICIPANT "eldritch_arena_participant"
// These traits are used in IS_X() as an OR, and is utilized for pseudoantags (such as deathmatch or domains) so they don't need to actually get antag status.
// To specifically and only get the antag datum, GET_X() exists now.
#define TRAIT_ACT_AS_CULTIST "act_as_cultist"
@@ -1522,9 +1543,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
///A trait given to users as a mutex to prevent repeated unresolved attempts to christen a shuttle
#define TRAIT_ATTEMPTING_CHRISTENING "attempting_christening"
///Trait given to heretic summons, making them immune to heretic spells
#define TRAIT_HERETIC_SUMMON "heretic_summon"
///trait given to mobs that are difficult to tame through mounting
#define TRAIT_MOB_DIFFICULT_TO_MOUNT "difficult_to_mount"

View File

@@ -59,8 +59,6 @@
#define SHOES_TRAIT "shoes"
/// Trait inherited by implants
#define IMPLANT_TRAIT "implant"
/// Traits given by the heretic arena spell
#define HERETIC_ARENA_TRAIT "heretic_arena"
#define GLASSES_TRAIT "glasses"
/// inherited from riding vehicles
#define VEHICLE_TRAIT "vehicle"
@@ -104,6 +102,10 @@
/// Trait given by being recruited as a nuclear operative
#define NUKE_OP_MINION_TRAIT "nuke-op-minion"
//---- Heretic Traits Sources
/// Traits given by the heretic arena spell
#define HERETIC_ARENA_TRAIT "heretic_arena"
/// Trait given to you by shapeshifting
#define SHAPESHIFT_TRAIT "shapeshift_trait"

View File

@@ -89,6 +89,7 @@
#define RUST_RESISTANCE_REINFORCED 2
#define RUST_RESISTANCE_TITANIUM 3
#define RUST_RESISTANCE_ORGANIC 4
/// Should not be rustable. EVER. Includes thing like space, lava, chasms, admin walls
#define RUST_RESISTANCE_ABSOLUTE 5
/// Turf will be passable if density is 0

View File

@@ -34,6 +34,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SPINNING" = TRAIT_SPINNING,
"TRAIT_STICKERED" = TRAIT_STICKERED,
"TRAIT_UNHITTABLE_BY_PROJECTILES" = TRAIT_UNHITTABLE_BY_PROJECTILES,
"TRAIT_UNHITTABLE_BY_LASERS" = TRAIT_UNHITTABLE_BY_LASERS,
"TRAIT_UNLINKABLE_FISHING_SPOT" = TRAIT_UNLINKABLE_FISHING_SPOT,
"TRAIT_TETHER_ATTACHED" = TRAIT_TETHER_ATTACHED,
),
@@ -143,6 +144,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
/datum/wound = list(
"TRAIT_WOUND_SCANNED" = TRAIT_WOUND_SCANNED,
),
/datum/antagonist/heretic = list(
"TRAIT_LOCK_GRASP_UPGRADED" = TRAIT_LOCK_GRASP_UPGRADED,
),
/obj = list(
"TRAIT_CONTRABAND" = TRAIT_CONTRABAND,
"TRAIT_DUCT_TAPE_UNREPAIRABLE" = TRAIT_DUCT_TAPE_UNREPAIRABLE,
@@ -640,6 +644,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_PREVENT_BLINK_LOOPS" = TRAIT_PREVENT_BLINK_LOOPS,
"TRAIT_NO_EYELIDS" = TRAIT_NO_EYELIDS,
"TRAIT_CARPOTOXIN_IMMUNE" = TRAIT_CARPOTOXIN_IMMUNE,
"TRAIT_FAT_IGNORE_SLOWDOWN" = TRAIT_FAT_IGNORE_SLOWDOWN,
"TRAIT_SPACE_ANT_IMMUNITY" = TRAIT_SPACE_ANT_IMMUNITY,
"TRAIT_BRAIN_TRAUMA_IMMUNITY" = TRAIT_BRAIN_TRAUMA_IMMUNITY,
),
/mob/dead/observer = list(
"TRAIT_NO_OBSERVE" = TRAIT_NO_OBSERVE,
@@ -687,6 +694,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_UNCOMPOSTABLE" = TRAIT_UNCOMPOSTABLE,
"TRAIT_UNIQUE_AQUARIUM_CONTENT" = TRAIT_UNIQUE_AQUARIUM_CONTENT,
"TRAIT_WIELDED" = TRAIT_WIELDED,
"TRAIT_HERETIC_AURA_HIDDEN" = TRAIT_HERETIC_AURA_HIDDEN,
),
/obj/item/ammo_casing = list(
"TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT,
@@ -761,6 +769,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_LIVING_HEART" = TRAIT_LIVING_HEART,
"TRAIT_USED_ORGAN" = TRAIT_USED_ORGAN,
),
/obj/item/organ/brain = list(
"TRAIT_BRAIN_DAMAGE_NODEATH" = TRAIT_BRAIN_DAMAGE_NODEATH,
),
/obj/item/organ/liver = list(
"TRAIT_BALLMER_SCIENTIST" = TRAIT_BALLMER_SCIENTIST,
"TRAIT_COMEDY_METABOLISM" = TRAIT_COMEDY_METABOLISM,

View File

@@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list(
"TRAIT_CATCH_AND_RELEASE" = TRAIT_CATCH_AND_RELEASE,
"TRAIT_KEEP_TOGETHER" = TRAIT_KEEP_TOGETHER,
"TRAIT_UNHITTABLE_BY_PROJECTILES" = TRAIT_UNHITTABLE_BY_PROJECTILES,
"TRAIT_UNHITTABLE_BY_LASERS" = TRAIT_UNHITTABLE_BY_LASERS,
),
/atom/movable = list(
"TRAIT_ASHSTORM_IMMUNE" = TRAIT_ASHSTORM_IMMUNE,

View File

@@ -479,6 +479,11 @@
return clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
/mob/living/proc/send_item_attack_message(obj/item/weapon, mob/living/user, hit_area, def_zone)
if(SEND_SIGNAL(weapon, COMSIG_SEND_ITEM_ATTACK_MESSAGE_OBJECT, src, user) & SIGNAL_MESSAGE_MODIFIED)
return TRUE
if(SEND_SIGNAL(src, COMSIG_SEND_ITEM_ATTACK_MESSAGE_CARBON, weapon, user) & SIGNAL_MESSAGE_MODIFIED)
return TRUE
if(!weapon.force && !length(weapon.attack_verb_simple) && !length(weapon.attack_verb_continuous))
return

View File

@@ -793,3 +793,7 @@
/datum/config_entry/flag/generate_assets_in_init
default = FALSE
/datum/config_entry/number/minimum_ascension_time
default = 0 // 1 minute
min_val = 0

View File

@@ -35,19 +35,6 @@
/datum/dynamic_ruleset/latejoin/traitor/assign_role(datum/mind/candidate)
candidate.add_antag_datum(/datum/antagonist/traitor)
/datum/dynamic_ruleset/latejoin/heretic
name = "Heretic"
config_tag = "Latejoin Heretic"
preview_antag_datum = /datum/antagonist/heretic
pref_flag = ROLE_HERETIC_SMUGGLER
jobban_flag = ROLE_HERETIC
weight = 3
min_pop = 30 // Ensures good spread of sacrifice targets
ruleset_lazy_templates = list(LAZY_TEMPLATE_KEY_HERETIC_SACRIFICE)
blacklisted_roles = list(
JOB_HEAD_OF_PERSONNEL,
)
/datum/dynamic_ruleset/latejoin/heretic/assign_role(datum/mind/candidate)
candidate.add_antag_datum(/datum/antagonist/heretic)

View File

@@ -127,7 +127,7 @@ SUBSYSTEM_DEF(throwing)
qdel(src)
/// Returns the mob thrower, or null
/// Returns the thrower, or null
/datum/thrownthing/proc/get_thrower()
. = thrower?.resolve()
if(isnull(.))
@@ -144,11 +144,11 @@ SUBSYSTEM_DEF(throwing)
return
var/atom/movable/actual_target = initial_target?.resolve()
var/mob/mob_thrower = get_thrower()
var/atom/thrower = get_thrower()
if(dist_travelled) //to catch sneaky things moving on our tile while we slept
for(var/atom/movable/obstacle as anything in get_turf(thrownthing))
if (obstacle == thrownthing || (obstacle == mob_thrower && !ismob(thrownthing)))
if(obstacle == thrownthing || (obstacle == thrower && !ismob(thrownthing)))
continue
if(ismob(obstacle) && thrownthing.pass_flags & PASSMOB && (obstacle != actual_target))
continue

View File

@@ -8,14 +8,22 @@
abstract_type = /datum/brain_trauma
var/name = "Brain Trauma"
var/desc = "A trauma caused by brain damage, which causes issues to the patient."
var/scan_desc = "generic brain trauma" //description when detected by a health scanner
var/mob/living/carbon/owner //the poor bastard
var/obj/item/organ/brain/brain //the poor bastard's brain
/// Description when detected by a health scanner
var/scan_desc = "generic brain trauma"
/// The poor bastard
var/mob/living/carbon/owner
/// The poor bastard's brain
var/obj/item/organ/brain/brain
/// Message sent in chat when trauma is gained
var/gain_text = span_notice("You feel traumatized.")
/// Message sent in chat when trauma is lost
var/lose_text = span_notice("You no longer feel traumatized.")
/// If the trauma can be gained, checked in can_gain_trauma
var/can_gain = TRUE
var/random_gain = TRUE //can this be gained through random traumas?
var/resilience = TRAUMA_RESILIENCE_BASIC //how hard is this to cure?
/// If this trauma can be gained randomly
var/random_gain = TRUE
/// How hard is this to cure?
var/resilience = TRAUMA_RESILIENCE_BASIC
/datum/brain_trauma/Destroy()
// Handles our references with our brain

View File

@@ -74,8 +74,12 @@
scan_desc = "extra-sensory paranoia"
gain_text = span_warning("You feel like something wants to kill you...")
lose_text = span_notice("You no longer feel eyes on your back.")
/// Type of stalker that is chasing us
var/stalker_type = /obj/effect/client_image_holder/stalker_phantom
/// Reference to the stalker that is chasing us
var/obj/effect/client_image_holder/stalker_phantom/stalker
var/close_stalker = FALSE //For heartbeat
/// Plays a sound when the stalker is near their victim
var/close_stalker = FALSE
/datum/brain_trauma/magic/stalker/Destroy()
QDEL_NULL(stalker)
@@ -87,7 +91,7 @@
/datum/brain_trauma/magic/stalker/proc/create_stalker()
var/turf/stalker_source = locate(owner.x + pick(-12, 12), owner.y + pick(-12, 12), owner.z) //random corner
stalker = new(stalker_source, owner)
stalker = new stalker_type(stalker_source, owner)
/datum/brain_trauma/magic/stalker/on_lose()
QDEL_NULL(stalker)
@@ -125,3 +129,12 @@
desc = "It's coming closer..."
image_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
image_state = "curseblob"
// Heretic subtype that replaces the ghost guy with a stargazer
/datum/brain_trauma/magic/stalker/cosmic
stalker_type = /obj/effect/client_image_holder/stalker_phantom/cosmic
random_gain = FALSE
/obj/effect/client_image_holder/stalker_phantom/cosmic
image_icon = 'icons/mob/nonhuman-player/96x96eldritch_mobs.dmi'
image_state = "star_gazer"

View File

@@ -44,6 +44,9 @@
/// The color to give the healing visual
var/healing_color = COLOR_GREEN
/// If the aura also heals the owner of the component
var/self_heal = TRUE
/// A list of being healed to active alerts
var/list/mob/living/current_alerts = list()
@@ -64,6 +67,7 @@
simple_heal = 0,
limit_to_trait = null,
healing_color = COLOR_GREEN,
self_heal = TRUE,
)
if (!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -83,6 +87,7 @@
src.simple_heal = simple_heal
src.limit_to_trait = limit_to_trait
src.healing_color = healing_color
src.self_heal = self_heal
/datum/component/aura_healing/Destroy(force)
STOP_PROCESSING(SSaura, src)

View File

@@ -85,7 +85,7 @@
/datum/component/boomerang/proc/aerodynamic_swing(datum/thrownthing/throwingdatum)
var/mob/thrown_by = throwingdatum?.get_thrower()
var/obj/item/true_parent = parent
if(thrown_by)
if(istype(thrown_by))
addtimer(CALLBACK(true_parent, TYPE_PROC_REF(/atom/movable, throw_at), thrown_by, boomerang_throw_range, throwingdatum.speed, thrown_by, TRUE), 0.1 SECONDS)
COOLDOWN_START(src, last_boomerang_throw, BOOMERANG_REBOUND_INTERVAL)
true_parent.visible_message(

View File

@@ -104,6 +104,8 @@
if(HAS_TRAIT(digitigrade_fan, TRAIT_LIGHT_STEP))
damage *= 0.75
if(flags & CALTROP_ANTS && HAS_TRAIT(digitigrade_fan, TRAIT_SPACE_ANT_IMMUNITY))
damage = 0
if(!(flags & CALTROP_SILENT) && !digitigrade_fan.has_status_effect(/datum/status_effect/caltropped))
digitigrade_fan.apply_status_effect(/datum/status_effect/caltropped)

View File

@@ -495,6 +495,7 @@ Behavior that's still missing from this component that original food items had t
playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
if(!owner.reagents.total_volume)
return
SEND_SIGNAL(eater, COMSIG_LIVING_EAT_FOOD, owner)
var/sig_return = SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder, bitecount, bite_consumption)
if(sig_return & DESTROY_FOOD)
qdel(owner)

View File

@@ -73,10 +73,11 @@
return
var/mob/thrower = throwingdatum?.get_thrower()
if(thrower)
try_activate_command(thrower)
set_command_target(parent, thrown_thing)
parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, thrower)
if(!istype(thrower))
return
try_activate_command(thrower)
set_command_target(parent, thrown_thing)
parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, thrower)
// Don't try and fetch turfs or anchored objects if someone points at them
/datum/pet_command/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom)

View File

@@ -411,6 +411,13 @@
if(istype(potential_spine))
defense_mod += potential_spine.strength_bonus
if(istype(tackle_target.wear_suit, /obj/item/clothing/suit/hooded/cultrobes/eldritch/blade))
defense_mod += 8
if(istype(tackle_target.wear_suit, /obj/item/clothing/suit/hooded/cultrobes/eldritch/rust))
var/obj/item/clothing/suit/hooded/cultrobes/eldritch/rust/rust_robes = tackle_target.wear_suit
if(rust_robes.rusted)
defense_mod += 10
// OF-FENSE
var/mob/living/carbon/sacker = parent
var/sacker_drunkenness = sacker.get_drunk_amount()

View File

@@ -16,13 +16,55 @@
src.chosen_effect = chosen_effect
/datum/element/effect_trail/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
return ..()
/// Generates an effect
/datum/element/effect_trail/proc/generate_effect(atom/movable/target_object)
SIGNAL_HANDLER
var/turf/open/open_turf = get_turf(target_object)
if(istype(open_turf))
new chosen_effect(open_turf)
if(!istype(open_turf))
return
new chosen_effect(open_turf)
/// If we are a cosmic heretic, this will return the appropriate effect trail based on our passive level. returns the default trail otherwise
/proc/cosmic_trail_based_on_passive(mob/living/source)
if(isstargazer(source))
return /datum/element/effect_trail/cosmic_field/antiprojectile
var/datum/status_effect/heretic_passive/cosmic/cosmic_passive = source.has_status_effect(/datum/status_effect/heretic_passive/cosmic)
if(!cosmic_passive)
return /datum/element/effect_trail/cosmic_field
if(cosmic_passive.passive_level == 3)
return /datum/element/effect_trail/cosmic_field/antiprojectile
if(cosmic_passive.passive_level == 2)
return /datum/element/effect_trail/cosmic_field/antiexplosion
return /datum/element/effect_trail
/datum/element/effect_trail/cosmic_field // Cosmic field subtype which applies any upgrades
var/prevents_explosions = FALSE
var/slows_projectiles = FALSE
/datum/element/effect_trail/cosmic_field/Attach(datum/target, chosen_effect)
. = ..()
if(!ispath(chosen_effect, /obj/effect/forcefield/cosmic_field))
stack_trace("Tried to attach a cosmic_field effect trail with a non-cosmic field as the chosen effect")
/datum/element/effect_trail/cosmic_field/generate_effect(atom/movable/target_object)
var/turf/open/open_turf = get_turf(target_object)
if(!istype(open_turf))
return
var/obj/effect/forcefield/cosmic_field/new_field = new chosen_effect(open_turf)
if(prevents_explosions)
new_field.prevents_explosions()
if(slows_projectiles)
new_field.slows_projectiles()
/datum/element/effect_trail/cosmic_field/antiexplosion
prevents_explosions = TRUE
/datum/element/effect_trail/cosmic_field/antiprojectile
prevents_explosions = TRUE
slows_projectiles = TRUE

View File

@@ -1,5 +1,6 @@
/// Buffs and heals the target while standing on rust.
/datum/element/leeching_walk
var/healing_multiplier = 1.0 // How much healing to do
/datum/element/leeching_walk/Attach(datum/target)
. = ..()
@@ -43,13 +44,14 @@
// Heals all damage + Stamina
var/need_mob_update = FALSE
var/delta_time = DELTA_WORLD_TIME(SSmobs) * 0.5 // SSmobs.wait is 2 secs, so this should be halved.
need_mob_update += source.adjustBruteLoss(-3 * delta_time, updating_health = FALSE)
need_mob_update += source.adjustFireLoss(-3 * delta_time, updating_health = FALSE)
need_mob_update += source.adjustToxLoss(-3 * delta_time, updating_health = FALSE, forced = TRUE) // Slimes are people too
need_mob_update += source.adjustOxyLoss(-1.5 * delta_time, updating_health = FALSE)
need_mob_update += source.adjustStaminaLoss(-10 * delta_time, updating_stamina = FALSE)
need_mob_update += source.adjustBruteLoss(-3 * delta_time * healing_multiplier, updating_health = FALSE)
need_mob_update += source.adjustFireLoss(-3 * delta_time * healing_multiplier, updating_health = FALSE)
need_mob_update += source.adjustToxLoss(-3 * delta_time * healing_multiplier, updating_health = FALSE, forced = TRUE) // Slimes are people too
need_mob_update += source.adjustOxyLoss(-1.5 * delta_time * healing_multiplier, updating_health = FALSE)
need_mob_update += source.adjustStaminaLoss(-10 * delta_time * healing_multiplier, updating_stamina = FALSE)
if(need_mob_update)
source.updatehealth()
new /obj/effect/temp_visual/heal(get_turf(source), COLOR_BROWN)
// Reduces duration of stuns/etc
source.AdjustAllImmobility((-0.5 SECONDS) * delta_time)
// Heals blood loss
@@ -57,3 +59,10 @@
source.blood_volume += 2.5 * delta_time
// Slowly regulates your body temp
source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature) / 5)
/datum/element/leeching_walk/minor
healing_multiplier = 0.5
// Minor variant which heals slightly less and no baton resistance
/datum/element/leeching_walk/minor/on_move(mob/source, atom/old_loc, dir, forced, list/old_locs)
return

View File

@@ -74,8 +74,8 @@
var/obj/item/hit_item = hit_atom
if(!hit_item.throwforce)
return
var/mob/thrown_by = throwingdatum?.get_thrower()
if(!ismob(thrown_by))
var/atom/thrown_by = throwingdatum?.get_thrower()
if(!istype(thrown_by))
return
relay_attacker(target, thrown_by, hit_item.damtype == STAMINA ? ATTACKER_STAMINA_ATTACK : ATTACKER_DAMAGING_ATTACK)

View File

@@ -36,7 +36,7 @@
/datum/element/rust/proc/handle_examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
examine_text += span_notice("[source] is very rusty, you could probably <i>burn</i> or <i>scrape</i> it off.")
examine_text += span_notice("[source] is very rusty, you could probably <i>burn</i> or <i>scrape</i> it off, hell maybe even pour some <i>space cola</i> on it to remove the rust.")
/datum/element/rust/proc/apply_rust_overlay(atom/parent_atom, list/overlays)
SIGNAL_HANDLER
@@ -115,6 +115,10 @@
/datum/element/rust/heretic/proc/on_entered(turf/source, atom/movable/entered, ...)
SIGNAL_HANDLER
if(ismecha(entered))
var/obj/vehicle/sealed/mecha/victim = entered
victim.take_damage(20, armour_penetration = 100)
return
if(!isliving(entered))
return
var/mob/living/victim = entered

View File

@@ -68,7 +68,13 @@
//If we reserve a random sound channel, store the channel number here so we can clean it up later.
var/reserved_channel
/datum/looping_sound/New(_parent, start_immediately = FALSE, _direct = FALSE, _skip_starting_sounds = FALSE)
/datum/looping_sound/New(
_parent,
start_immediately = FALSE,
_direct = FALSE,
_skip_starting_sounds = FALSE,
sound_channel,
)
if(!mid_sounds)
WARNING("A looping sound datum was created without sounds to play.")
return
@@ -76,6 +82,7 @@
set_parent(_parent)
direct = _direct
skip_starting_sounds = _skip_starting_sounds
src.sound_channel = sound_channel
if(start_immediately)
start()
@@ -164,9 +171,9 @@
*/
/datum/looping_sound/proc/play(soundfile, volume_override)
var/sound/sound_to_play = sound(soundfile)
sound_to_play.channel = sound_channel || SSsounds.random_available_channel()
sound_to_play.volume = volume_override || volume //Use volume as fallback if theres no override
if(direct)
sound_to_play.channel = sound_channel || SSsounds.random_available_channel()
sound_to_play.volume = volume_override || volume //Use volume as fallback if theres no override
SEND_SOUND(parent, sound_to_play)
else
playsound(
@@ -176,6 +183,7 @@
vary,
extra_range,
falloff_exponent = falloff_exponent,
channel = sound_to_play.channel,
pressure_affected = pressure_affected,
ignore_walls = ignore_walls,
falloff_distance = falloff_distance,

View File

@@ -759,6 +759,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.25
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
mat_rust_resistance = RUST_RESISTANCE_BASIC
fish_weight_modifier = 1.2
fishing_difficulty_modifier = 30 //Sand fishing rods? What the hell are you doing?
fishing_cast_range = -2
@@ -790,6 +791,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.3
turf_sound_override = FOOTSTEP_WOOD
texture_layer_icon_state = "brick"
mat_rust_resistance = RUST_RESISTANCE_BASIC
fish_weight_modifier = 1.2
fishing_difficulty_modifier = 25 //Sand fishing rods? What the hell are you doing?
fishing_cast_range = -2
@@ -817,6 +819,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
beauty_modifier = 0.3
turf_sound_override = FOOTSTEP_SAND
texture_layer_icon_state = "sand"
mat_rust_resistance = RUST_RESISTANCE_ORGANIC
fish_weight_modifier = 0.8
fishing_difficulty_modifier = 25
fishing_cast_range = -2

View File

@@ -16,6 +16,7 @@
item_sound_override = 'sound/effects/meatslap.ogg'
turf_sound_override = FOOTSTEP_MEAT
texture_layer_icon_state = "pizza"
mat_rust_resistance = RUST_RESISTANCE_REINFORCED
fish_weight_modifier = 0.9
fishing_difficulty_modifier = 13
fishing_cast_range = -2

View File

@@ -260,7 +260,7 @@
/// Updates the mob's mood icon
/datum/mood/proc/update_mood_icon()
if (!(mob_parent.client || mob_parent.hud_used))
if (!(mob_parent.client || mob_parent.hud_used) || isnull(mood_screen_object))
return
mood_screen_object.cut_overlays()
@@ -324,6 +324,7 @@
if(hud?.infodisplay)
hud.infodisplay -= mood_screen_object
QDEL_NULL(mood_screen_object)
UnregisterSignal(hud, COMSIG_QDELETING)
/// Handles clicking on the mood HUD object
/datum/mood/proc/hud_click(datum/source, location, control, params, mob/user)

View File

@@ -102,6 +102,13 @@
to_chat(owner, span_warning("You plunge into your mind... Yep, it's your mind."))
return
if(cast_on.has_status_effect(/datum/status_effect/heretic_passive/moon))
to_chat(owner, span_hypnophrase(span_bolddanger("YOU SEEK THE TRUTH? I WILL SHOW YOU EVERYTHING.")))
if(isliving(owner))
var/mob/living/reader = owner
reader.apply_status_effect(/datum/status_effect/moon_converted)
return
if(HAS_TRAIT(cast_on, TRAIT_EVIL))
to_chat(owner, span_warning("As you reach into [cast_on]'s mind, \
you feel the overwhelming emptiness within. A truly evil being. \

View File

@@ -63,7 +63,8 @@ GLOBAL_LIST_EMPTY(heretic_arenas)
var/obj/item/melee/sickly_blade/training/new_blade = new(get_turf(human_in_range))
welfare_blades += new_blade
INVOKE_ASYNC(human_in_range, TYPE_PROC_REF(/mob, put_in_hands), new_blade)
human_in_range.mind?.add_antag_datum(/datum/antagonist/heretic_arena_participant)
to_chat(human_in_range, span_boldbig("Escape is impossible. The only way out is to defeat another participant in this battle to the death."))
human_in_range.balloon_alert(human_in_range, "start killing!")
human_in_range.apply_status_effect(/datum/status_effect/arena_tracker)
RegisterSignal(human_in_range, COMSIG_CAN_Z_MOVE, PROC_REF(on_try_z_move))
RegisterSignal(human_in_range, COMSIG_LADDER_TRAVEL, PROC_REF(on_try_ladder))
@@ -75,8 +76,8 @@ GLOBAL_LIST_EMPTY(heretic_arenas)
mob.remove_traits(given_immunities, HERETIC_ARENA_TRAIT)
mob.remove_status_effect(/datum/status_effect/arena_tracker)
UnregisterSignal(mob, list(COMSIG_CAN_Z_MOVE, COMSIG_LADDER_TRAVEL, COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_POST_TELEPORT))
if(mob.mind?.has_antag_datum(/datum/antagonist/heretic_arena_participant))
mob.mind.remove_antag_datum(/datum/antagonist/heretic_arena_participant)
to_chat(mob, span_boldbig("Your bloodlust is sated."))
mob.balloon_alert(mob, "escape the arena!")
for(var/turf/to_restore in border_walls)
to_restore.ChangeTurf(border_walls[to_restore])
for(var/obj/to_refund as anything in welfare_blades)

View File

@@ -0,0 +1,30 @@
/**
* Effectively grants a temporary form of x-ray with a cooldown period.
*/
/datum/status_effect/temporary_xray
id = "temp xray"
status_type = STATUS_EFFECT_UNIQUE
alert_type = null
duration = 10 SECONDS
show_duration = TRUE
/datum/status_effect/temporary_xray/on_apply()
ADD_TRAIT(owner, TRAIT_XRAY_VISION, TRAIT_STATUS_EFFECT(id))
owner.update_sight()
return TRUE
/datum/status_effect/temporary_xray/on_remove()
REMOVE_TRAIT(owner, TRAIT_XRAY_VISION, TRAIT_STATUS_EFFECT(id))
owner.update_sight()
/datum/status_effect/temporary_xray/eldritch // Heretic subtype that plays a sound and screen alert
alert_type = /atom/movable/screen/alert/status_effect/temporary_xray
/datum/status_effect/temporary_xray/eldritch/on_apply()
. = ..()
SEND_SOUND(owner, 'sound/effects/hallucinations/i_see_you1.ogg')
/atom/movable/screen/alert/status_effect/temporary_xray
name = "Eldritch Sight"
desc = "You get a glimpse of something new..."
icon_state = "influence"

View File

@@ -170,6 +170,7 @@
var/decay_multiplier = HAS_TRAIT(owner, TRAIT_HUSK) ? 2 : 1 // husks decay twice as fast
adjust_stacks(owner.fire_stack_decay_rate * decay_multiplier * seconds_between_ticks)
SEND_SIGNAL(owner, COMSIG_FIRE_STACKS_UPDATED, stacks)
if(stacks <= 0)
qdel(src)

View File

@@ -5,8 +5,14 @@
remove_on_fullheal = TRUE
/datum/status_effect/rust_corruption/tick(seconds_between_ticks)
if(issilicon(owner))
if(issilicon(owner) || isbot(owner))
owner.adjustBruteLoss(10 * seconds_between_ticks)
return
owner.adjust_disgust(5 * seconds_between_ticks)
owner.reagents?.remove_all(0.75 * seconds_between_ticks)
if(!iscarbon(owner))
return
var/mob/living/carbon/carbon_owner = owner
for(var/obj/item/bodypart/robotic_limb as anything in carbon_owner.bodyparts)
if(IS_ROBOTIC_LIMB(robotic_limb))
robotic_limb.receive_damage(10)

View File

@@ -228,7 +228,7 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances)
/datum/atom_hud/alternate_appearance/basic/heretic
/datum/atom_hud/alternate_appearance/basic/heretic/mobShouldSee(mob/M)
if(IS_HERETIC(M))
/datum/atom_hud/alternate_appearance/basic/heretic/mobShouldSee(mob/viewer)
if(IS_HERETIC_OR_MONSTER(viewer))
return TRUE
return FALSE

View File

@@ -230,8 +230,9 @@
*
* Override this if you want custom behaviour in whatever gets hit by the rust
* /turf/rust_turf should be used instead for overriding rust on turfs
* rust_strength (optional) - if you want to vary the effect based on the users' strength
*/
/atom/proc/rust_heretic_act()
/atom/proc/rust_heretic_act(rust_strength)
return
///wrapper proc that passes our mob's rust_strength to the target we are rusting

View File

@@ -1328,13 +1328,13 @@
return ..()
// Calls throw_at after checking that the move strength is greater than the thrown atom's move resist. Identical args.
/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
/atom/movable/proc/safe_throw_at(atom/target, range, speed, atom/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY))
return
return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force, gentle)
///If this returns FALSE then callback will not be called.
/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE, quickstart = TRUE, throw_datum_typepath = /datum/thrownthing)
/atom/movable/proc/throw_at(atom/target, range, speed, atom/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE, quickstart = TRUE, throw_datum_typepath = /datum/thrownthing)
. = FALSE
if(QDELETED(src))
@@ -1350,36 +1350,38 @@
pulledby.stop_pulling()
//They are moving! Wouldn't it be cool if we calculated their momentum and added it to the throw?
if (thrower && thrower.last_move && thrower.client && thrower.client.move_delay >= world.time + world.tick_lag*2)
var/user_momentum = thrower.cached_multiplicative_slowdown
if (!user_momentum) //no movement_delay, this means they move once per byond tick, lets calculate from that instead.
user_momentum = world.tick_lag
if(ismob(thrower))
var/mob/thrower_mob = thrower
if(thrower_mob.last_move && thrower_mob.client && thrower_mob.client.move_delay >= world.time + world.tick_lag*2)
var/user_momentum = thrower_mob.cached_multiplicative_slowdown
if (!user_momentum) //no movement_delay, this means they move once per byond tick, lets calculate from that instead.
user_momentum = world.tick_lag
user_momentum = 1 / user_momentum // convert from ds to the tiles per ds that throw_at uses.
user_momentum = 1 / user_momentum // convert from ds to the tiles per ds that throw_at uses.
if (get_dir(thrower, target) & last_move)
user_momentum = user_momentum //basically a noop, but needed
else if (get_dir(target, thrower) & last_move)
user_momentum = -user_momentum //we are moving away from the target, lets slowdown the throw accordingly
else
user_momentum = 0
if (get_dir(thrower_mob, target) & last_move)
user_momentum = user_momentum //basically a noop, but needed
else if (get_dir(target, thrower_mob) & last_move)
user_momentum = -user_momentum //we are moving away from the target, lets slowdown the throw accordingly
else
user_momentum = 0
if (user_momentum)
//first lets add that momentum to range.
range *= (user_momentum / speed) + 1
//then lets add it to speed
speed += user_momentum
if (speed <= 0)
return//no throw speed, the user was moving too fast.
if (user_momentum)
//first lets add that momentum to range.
range *= (user_momentum / speed) + 1
//then lets add it to speed
speed += user_momentum
if (speed <= 0)
return//no throw speed, the user was moving too fast.
. = TRUE // No failure conditions past this point.
var/target_zone
if(QDELETED(thrower))
thrower = null //Let's not pass a qdeleting reference if any.
else
target_zone = thrower.zone_selected
else if(ismob(thrower))
var/mob/thrower_mob = thrower
target_zone = thrower_mob.zone_selected
var/datum/thrownthing/thrown_thing = new throw_datum_typepath(src, target, get_dir(src, target), range, speed, thrower, diagonals_first, force, gentle, callback, target_zone)

View File

@@ -1237,8 +1237,9 @@
dropped_atom.pixel_x = -8 + ((.%3)*8)
dropped_atom.pixel_y = -8 + (round( . / 3)*8)
/obj/machinery/rust_heretic_act()
take_damage(500, BRUTE, MELEE, 1)
/obj/machinery/rust_heretic_act(rust_strength)
var/damage = 500 + rust_strength * 200
take_damage(damage, BRUTE, BOMB, 1)
/obj/machinery/vv_edit_var(vname, vval)
if(vname == NAMEOF(src, occupant))

View File

@@ -69,6 +69,12 @@
if(!active)
return PROCESS_KILL
for(var/obj/effect/forcefield/cosmic_field/potential_field as anything in GLOB.active_cosmic_fields)
if(get_dist(potential_field, src) < 3)
new /obj/effect/temp_visual/revenant(get_turf(src))
defuse()
return
if(!isnull(next_beep) && (next_beep <= world.time))
var/volume
switch(seconds_remaining())

View File

@@ -95,12 +95,15 @@
receive_ricochet_chance_mod = INFINITY //we do ricochet a lot!
initial_duration = 10 SECONDS
GLOBAL_LIST_EMPTY_TYPED(active_cosmic_fields, /obj/effect/forcefield/cosmic_field)
/// The cosmic heretics forcefield
/obj/effect/forcefield/cosmic_field
name = "Cosmic Field"
desc = "A field that cannot be passed by people marked with a cosmic star."
icon = 'icons/effects/eldritch.dmi'
icon_state = "cosmic_carpet"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
layer = GIB_LAYER
density = FALSE
@@ -108,10 +111,27 @@
initial_duration = 30 SECONDS
/// Flags for what antimagic can just ignore our forcefields
var/antimagic_flags = MAGIC_RESISTANCE
/// If we are able to slow down projectiles
var/slows_projectiles = FALSE
/obj/effect/forcefield/cosmic_field/Initialize(mapload, flags = MAGIC_RESISTANCE)
. = ..()
antimagic_flags = flags
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
COMSIG_ATOM_EXITED = PROC_REF(on_loc_exited),
)
AddElement(/datum/element/connect_loc, loc_connections)
// Make sure that if we create a field, we apply whatever effects
for(var/atom/movable/thing in get_turf(src))
on_entered(src, thing)
/obj/effect/forcefield/cosmic_field/Destroy(force)
// Make sure when the field goes away that the effects don't persist
for(var/atom/movable/thing in get_turf(src))
on_loc_exited(src, thing)
GLOB.active_cosmic_fields -= src
return ..()
/obj/effect/forcefield/cosmic_field/CanAllowThrough(atom/movable/mover, border_dir)
if(!isliving(mover))
@@ -119,10 +139,68 @@
var/mob/living/living_mover = mover
if(living_mover.can_block_magic(antimagic_flags, charge_cost = 0))
return ..()
// Being buckled/pulled by a cosmic heretic will allow you through cosmic fields EVEN IF you have a star mark
if(ismob(living_mover.buckled))
var/mob/living/fireman = living_mover.buckled
if(fireman.has_status_effect(/datum/status_effect/heretic_passive/cosmic))
return ..()
if(living_mover.pulledby?.has_status_effect(/datum/status_effect/heretic_passive/cosmic))
return ..()
if(living_mover.has_status_effect(/datum/status_effect/star_mark))
return FALSE
return ..()
/obj/effect/forcefield/cosmic_field/proc/on_entered(datum/source, atom/movable/thing)
SIGNAL_HANDLER
if(isprojectile(thing) && slows_projectiles)
var/obj/projectile/bullet = thing
if(istype(bullet, /obj/projectile/magic/star_ball)) // Don't slow down star balls
return
bullet.speed *= 0.2 // 80% Slowdown
return
if(!isliving(thing))
return
var/mob/living/living_mover = thing
var/datum/status_effect/heretic_passive/cosmic/cosmic_passive = living_mover.has_status_effect(/datum/status_effect/heretic_passive/cosmic)
if(!cosmic_passive)
return
living_mover.add_movespeed_modifier(/datum/movespeed_modifier/cosmic_field)
/obj/effect/forcefield/cosmic_field/proc/on_loc_exited(datum/source, atom/movable/thing)
SIGNAL_HANDLER
if(isprojectile(thing) && slows_projectiles)
var/obj/projectile/bullet = thing
if(istype(bullet, /obj/projectile/magic/star_ball)) // Don't speed up star balls
return
bullet.speed /= 0.2 // 80% Slowdown
return
if(!isliving(thing))
return
var/mob/living/living_mover = thing
var/datum/status_effect/heretic_passive/cosmic/cosmic_passive = living_mover.has_status_effect(/datum/status_effect/heretic_passive/cosmic)
if(!cosmic_passive)
return
living_mover.remove_movespeed_modifier(/datum/movespeed_modifier/cosmic_field)
/// Adds the ability to slow down any projectiles that enters any turf we occupy
/obj/effect/forcefield/cosmic_field/proc/slows_projectiles()
slows_projectiles = TRUE
/// Adds our cosmic field to the global list which bombs check to see if they have to stop exploding
/obj/effect/forcefield/cosmic_field/proc/prevents_explosions()
GLOB.active_cosmic_fields += src
/datum/movespeed_modifier/cosmic_field
multiplicative_slowdown = -0.25
/obj/effect/forcefield/cosmic_field/star_blast
initial_duration = 5 SECONDS
/obj/effect/forcefield/cosmic_field/star_touch
initial_duration = 30 SECONDS
/obj/effect/forcefield/cosmic_field/fast
initial_duration = 5 SECONDS

View File

@@ -804,3 +804,6 @@
color = COLOR_FULL_TONER_BLACK
duration = 12 SECONDS
amount_to_scale = 12
/obj/effect/temp_visual/circle_wave/star_blast
color = COLOR_VOID_PURPLE

View File

@@ -743,7 +743,8 @@
item_flags &= ~IN_INVENTORY
UnregisterSignal(src, list(SIGNAL_ADDTRAIT(TRAIT_NO_WORN_ICON), SIGNAL_REMOVETRAIT(TRAIT_NO_WORN_ICON)))
SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user)
if(!silent)
SEND_SIGNAL(user, COMSIG_MOB_DROPPED_ITEM, src)
if(!silent && drop_sound)
play_drop_sound(DROP_SOUND_VOLUME)
/// called just as an item is picked up (loc is not yet changed)

View File

@@ -235,6 +235,11 @@
if(!istype(target) || (target != tank_one && target != tank_two))
return FALSE
for(var/obj/effect/forcefield/cosmic_field/potential_field as anything in GLOB.active_cosmic_fields)
if(get_dist(potential_field, src) < 3)
new /obj/effect/temp_visual/revenant(get_turf(src))
return FALSE
// Throw both tanks into processing queue
var/datum/gas_mixture/target_mix = target.return_air()
var/datum/gas_mixture/other_mix

View File

@@ -70,7 +70,7 @@
/obj/item/dice/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
var/mob/thrown_by = throwingdatum?.get_thrower()
if(thrown_by)
if(istype(thrown_by))
diceroll(thrown_by)
return ..()

View File

@@ -180,6 +180,13 @@
update_appearance()
return FALSE
for(var/obj/effect/forcefield/cosmic_field/potential_field as anything in GLOB.active_cosmic_fields)
if(get_dist(potential_field, src) < 3)
new /obj/effect/temp_visual/revenant(get_turf(src))
active = FALSE
update_appearance()
return FALSE
dud_flags |= GRENADE_USED // Don't detonate if we have already detonated.
if(shrapnel_type && shrapnel_radius && !shrapnel_initialized) // add a second check for adding the component in case whatever triggered the grenade went straight to prime (badminnery for example)
shrapnel_initialized = TRUE

View File

@@ -776,7 +776,7 @@
/obj/item/melee/baton/security/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
if(!. && active && prob(throw_stun_chance) && isliving(hit_atom))
if(!. && active && prob(throw_stun_chance) && hit_atom)
finalize_baton_attack(hit_atom, throwingdatum?.get_thrower())
/obj/item/melee/baton/security/emp_act(severity)

View File

@@ -204,7 +204,7 @@
if(victim.incorporeal_move || HAS_TRAIT(victim, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return ..()
var/mob/thrower = throwingdatum?.get_thrower()
if(thrower)
if(istype(thrower))
log_combat(thrower, hit_atom, "consumed", src)
message_admins("[src] has consumed [key_name_admin(victim)] [ADMIN_JMP(src)], thrown by [key_name_admin(thrower)].")
investigate_log("has consumed [key_name(victim)], thrown by [key_name(thrower)]", INVESTIGATE_ENGINE)

View File

@@ -618,14 +618,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/spawner, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/unanchored/spawner, 0)
// You can't rust glass! So only reinforced glass can be impacted.
/obj/structure/window/reinforced/rust_heretic_act()
add_atom_colour(COLOR_RUSTED_GLASS, FIXED_COLOUR_PRIORITY)
AddElement(/datum/element/rust)
set_armor(/datum/armor/none)
take_damage(get_integrity() * 0.5)
modify_max_integrity(initial(max_integrity) * 0.2)
/obj/structure/window/plasma
name = "plasma window"
desc = "A window made out of a plasma-silicate alloy. It looks insanely tough to break and burn through."

View File

@@ -9,12 +9,13 @@
damaged_dmi = 'icons/turf/floors.dmi'
icon_state = "asteroid"
base_icon_state = "asteroid"
turf_flags = IS_SOLID
footstep = FOOTSTEP_SAND
barefootstep = FOOTSTEP_SAND
clawfootstep = FOOTSTEP_SAND
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
rust_resistance = RUST_RESISTANCE_ORGANIC
rust_resistance = RUST_RESISTANCE_BASIC
/// Base turf type to be created by the tunnel
var/turf_type = /turf/open/misc/asteroid
/// Whether this turf has different icon states

View File

@@ -7,6 +7,7 @@
base_icon_state = "bcircuit"
light_color = LIGHT_COLOR_BABY_BLUE
floor_tile = /obj/item/stack/tile/circuit
rust_resistance = RUST_RESISTANCE_REINFORCED
/// If we want to ignore our area's power status and just be always off
/// Mostly for mappers doing asthetic things, or cases where the floor should be broken
var/always_off = FALSE
@@ -237,6 +238,7 @@
desc = "This one takes you back."
icon_state = "eighties"
floor_tile = /obj/item/stack/tile/eighties
rust_resistance = RUST_RESISTANCE_BASIC
/turf/open/floor/eighties/broken_states()
return list("eighties_damaged")

View File

@@ -8,7 +8,7 @@
barefootstep = FOOTSTEP_SAND
clawfootstep = FOOTSTEP_SAND
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
rust_resistance = RUST_RESISTANCE_ORGANIC
rust_resistance = RUST_RESISTANCE_REINFORCED
/turf/open/misc/beach/Initialize(mapload)
. = ..()

View File

@@ -91,7 +91,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
var/force_no_gravity = FALSE
///This turf's resistance to getting rusted
var/rust_resistance = RUST_RESISTANCE_ORGANIC
var/rust_resistance = RUST_RESISTANCE_BASIC
/// How pathing algorithm will check if this turf is passable by itself (not including content checks). By default it's just density check.
/// WARNING: Currently to use a density shortcircuiting this does not support dense turfs with special allow through function

View File

@@ -222,7 +222,7 @@ Striking a noncultist, however, will tear their flesh."}
// Moon
PATH_MOON = list(
WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/projectile/moon_parade),
SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/moon_smile),
SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/mind_gate),
SWORD_PREFIX = "shimmering",
),
// Starter
@@ -412,7 +412,7 @@ Striking a noncultist, however, will tear their flesh."}
fling_act.Grant(trapped_entity)
// Set the sword's path for spell selection.
heretic_path = heretic_holder.heretic_path
heretic_path = heretic_holder.heretic_path.route || PATH_START
// Copy the objectives to keep for roundend, remove the datum as neither us nor the heretic need it anymore
var/list/copied_objectives = heretic_holder.objectives.Copy()

View File

@@ -31,47 +31,63 @@
stinger_sound = 'sound/music/antag/heretic/heretic_gain.ogg'
antag_flags = parent_type::antag_flags | ANTAG_OBSERVER_VISIBLE_PANEL
/// Whether we give this antagonist objectives on gain.
var/give_objectives = TRUE
/// Whether we've ascended! (Completed one of the final rituals)
var/ascended = FALSE
/// The path our heretic has chosen. Mostly used for flavor.
var/heretic_path = PATH_START
/// A sum of how many knowledge points this heretic CURRENTLY has. Used to research.
var/knowledge_points = 1
/// The time between gaining influence passively. The heretic gain +1 knowledge points every this duration of time.
var/passive_gain_timer = 20 MINUTES
/// Assoc list of [typepath] = [knowledge instance]. A list of all knowledge this heretic's reserached.
var/list/researched_knowledge = list()
/// The organ slot we place our Living Heart in.
var/living_heart_organ_slot = ORGAN_SLOT_HEART
/// A list of TOTAL how many sacrifices completed. (Includes high value sacrifices)
var/total_sacrifices = 0
/// A list of TOTAL how many high value sacrifices completed. (Heads of staff)
var/high_value_sacrifices = 0
/// 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()
/// Whether we're drawing a rune or not
var/drawing_rune = FALSE
/// Contains multiple separate heretic shops so you can choose between multiple when buying.
var/list/heretic_shops = list(
HERETIC_KNOWLEDGE_START = list(),
HERETIC_KNOWLEDGE_TREE = list(),
HERETIC_KNOWLEDGE_SHOP = list(),
HERETIC_KNOWLEDGE_DRAFT = list()
)
/// A static typecache of all tools we can scribe with.
var/static/list/scribing_tools = typecacheof(list(/obj/item/pen, /obj/item/toy/crayon))
/// A blacklist of turfs we cannot scribe on.
var/static/list/blacklisted_rune_turfs = typecacheof(list(/turf/open/space, /turf/open/openspace, /turf/open/lava, /turf/open/chasm))
/// Controls what types of turf we can spread rust to, increases as we unlock more powerful rust abilites
var/rust_strength = 0
/// Wether we are allowed to ascend
var/feast_of_owls = FALSE
/// A static list of all paths we can take and related info for the UI
var/static/list/path_info = list()
/// Assoc list of [typepath] = [knowledge instance]. A list of all knowledge this heretic's reserached.
var/list/researched_knowledge = list()
/// 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()
/// List that keeps track of which items have been gifted to the heretic after a cultist was sacrificed. Used to alter drop chances to reduce dupes.
var/list/unlocked_heretic_items = list(
/obj/item/melee/sickly_blade/cursed = 0,
/obj/item/clothing/neck/heretic_focus/crimson_medallion = 0,
/mob/living/basic/construct/harvester/heretic = 0,
)
/// Whether or not the heretic can make unlimited blades, but unable to blade break to teleport
var/unlimited_blades = FALSE
/// Whether we are allowed to ascend
var/feast_of_owls = FALSE
/// Whether we give this antagonist objectives on gain.
var/give_objectives = TRUE
/// Whether we've ascended! (Completed one of the final rituals)
var/ascended = FALSE
/// Whether we're drawing a rune or not
var/drawing_rune = FALSE
/// The path our heretic has chosen.
var/datum/heretic_knowledge_tree_column/heretic_path
/// Reference to the overlay heretics get when they get strong enough
var/static/mutable_appearance/eldritch_overlay = mutable_appearance('icons/mob/effects/heretic_aura.dmi', "heretic_aura")
/// A sum of how many knowledge points this heretic CURRENTLY has. Used to research.
var/knowledge_points = 1
/// The time between gaining influence passively. The heretic gain +1 knowledge points every this duration of time.
var/passive_gain_timer = 20 MINUTES
/// Tracks how many knowledge points the heretic has aqcuired. Once you get enough points you lose the ability to blade break
var/knowledge_gained = 0
/// The organ slot we place our Living Heart in.
var/living_heart_organ_slot = ORGAN_SLOT_HEART
/// A list of TOTAL how many sacrifices completed. (Includes high value sacrifices)
var/total_sacrifices = 0
/// A list of TOTAL how many high value sacrifices completed. (Heads of staff)
var/high_value_sacrifices = 0
/// Controls what types of turf we can spread rust to
var/rust_strength = 1
/// Simpler version of above used to limit amount of loot that can be hoarded
var/rewards_given = 0
/// Our heretic passive level. Tracked here in case of body moving shenanigans
var/passive_level = 1
/datum/antagonist/heretic/Destroy()
LAZYNULL(sac_targets)
@@ -107,13 +123,6 @@
icon_path = result_mob.icon
icon_state = result_mob.icon_state
//if the knowledge is an eldritch mark, use the mark sprite
else if(ispath(knowledge,/datum/heretic_knowledge/mark))
var/datum/heretic_knowledge/mark/mark_knowledge = knowledge
var/datum/status_effect/eldritch/mark_effect = mark_knowledge.mark_type
icon_path = mark_effect.effect_icon
icon_state = mark_effect.effect_icon_state
//if the knowledge is an ascension, use the achievement sprite
else if(ispath(knowledge,/datum/heretic_knowledge/ultimate))
var/datum/heretic_knowledge/ultimate/ascension_knowledge = knowledge
@@ -130,70 +139,126 @@
result_parameters["moving"] = icon_moving
return result_parameters
/datum/antagonist/heretic/proc/get_knowledge_data(datum/heretic_knowledge/knowledge, done)
/datum/antagonist/heretic/proc/get_knowledge_data(datum/heretic_knowledge/knowledge, list/source_list, done = FALSE, category = HERETIC_KNOWLEDGE_TREE)
if(!length(source_list))
CRASH("get_knowledge_data called without source_list! (Got: [source_list || "empty list"])")
var/list/knowledge_data = list()
knowledge_data["path"] = knowledge
knowledge_data["icon_params"] = get_icon_of_knowledge(knowledge)
knowledge_data["name"] = initial(knowledge.name)
knowledge_data["gainFlavor"] = initial(knowledge.gain_text)
knowledge_data["cost"] = initial(knowledge.cost)
knowledge_data["disabled"] = (!done) && (initial(knowledge.cost) > knowledge_points)
knowledge_data["bgr"] = GLOB.heretic_research_tree[knowledge][HKT_UI_BGR]
knowledge_data["finished"] = done
knowledge_data["ascension"] = ispath(knowledge,/datum/heretic_knowledge/ultimate)
knowledge_data["cost"] = source_list[knowledge][HKT_COST]
knowledge_data["depth"] = source_list[knowledge][HKT_DEPTH]
knowledge_data["bgr"] = source_list[knowledge][HKT_UI_BGR]
knowledge_data[HKT_CATEGORY] = category
knowledge_data["ascension"] = ispath(knowledge, /datum/heretic_knowledge/ultimate)
knowledge_data["done"] = done
//description of a knowledge might change, make sure we are not shown the initial() value in that case
if(done)
var/datum/heretic_knowledge/knowledge_instance = researched_knowledge[knowledge]
var/list/knowledge_info = researched_knowledge[knowledge]
if(islist(knowledge_info))
var/datum/heretic_knowledge/knowledge_instance = knowledge_info[HKT_INSTANCE]
knowledge_data["desc"] = knowledge_instance.desc
else
knowledge_data["desc"] = initial(knowledge.desc)
return knowledge_data
/datum/antagonist/heretic/ui_data(mob/user)
var/list/data = list()
data["charges"] = knowledge_points
/datum/antagonist/heretic/ui_interact(mob/user, datum/tgui/ui)
. = ..()
ui?.set_autoupdate(FALSE)
/datum/antagonist/heretic/ui_data(mob/user)
var/list/data = list("charges" = knowledge_points)
data["objectives"] = get_objectives()
data["can_change_objective"] = can_assign_self_objectives
data["paths"] = path_info
data["passive_level"] = passive_level
data["total_sacrifices"] = total_sacrifices
data["ascended"] = ascended
var/list/tiers = list()
var/list/tree_data = list()
var/list/shop_knowledge = list()
// This should be cached in some way, but the fact that final knowledge
// has to update its disabled state based on whether all objectives are complete,
// makes this very difficult. I'll figure it out one day maybe
for(var/datum/heretic_knowledge/knowledge as anything in researched_knowledge)
var/list/knowledge_data = get_knowledge_data(knowledge,TRUE)
for(var/knowledge_path in researched_knowledge)
var/list/knowledge_info = researched_knowledge[knowledge_path]
/// draft knowledges are only shown post-research
var/list/knowledge_data = get_knowledge_data(knowledge_path, researched_knowledge, TRUE, knowledge_info[HKT_CATEGORY])
var/category = knowledge_info[HKT_CATEGORY]
while(GLOB.heretic_research_tree[knowledge][HKT_DEPTH] > tiers.len)
tiers += list(list("nodes"=list()))
var/depth = knowledge_info[HKT_DEPTH]
while(depth > length(tree_data))
tree_data += list(list("nodes" = list()))
tiers[GLOB.heretic_research_tree[knowledge][HKT_DEPTH]]["nodes"] += list(knowledge_data)
if(category == HERETIC_KNOWLEDGE_SHOP || category == HERETIC_KNOWLEDGE_DRAFT)
shop_knowledge += list(knowledge_data)
continue
for(var/datum/heretic_knowledge/knowledge as anything in get_researchable_knowledge())
var/list/knowledge_data = get_knowledge_data(knowledge,FALSE)
tree_data[depth]["nodes"] += list(knowledge_data)
// TODO: sanity for purchasing categories as bypasses are likely rn
var/list/heretic_tree = heretic_shops[HERETIC_KNOWLEDGE_TREE]
var/list/researchable_knowledges = get_researchable_knowledge()
for(var/datum/heretic_knowledge/knowledge_path as anything in heretic_tree)
if(ispath(knowledge_path, /datum/heretic_knowledge/limited_amount/starting))
continue
var/list/knowledge_info = heretic_tree[knowledge_path]
if(!(knowledge_info[HKT_ID] in researchable_knowledges))
continue
var/list/knowledge_data = get_knowledge_data(knowledge_path, heretic_tree, FALSE)
// Final knowledge can't be learned until all objectives are complete.
if(ispath(knowledge, /datum/heretic_knowledge/ultimate))
knowledge_data["disabled"] ||= !can_ascend()
if(ispath(knowledge_path, /datum/heretic_knowledge/ultimate))
var/ascension_check = can_ascend()
if(ascension_check != HERETIC_CAN_ASCEND)
knowledge_data["disabled"] = TRUE
knowledge_data["tooltip"] = ascension_check
while(GLOB.heretic_research_tree[knowledge][HKT_DEPTH] > tiers.len)
tiers += list(list("nodes"=list()))
tiers[GLOB.heretic_research_tree[knowledge][HKT_DEPTH]]["nodes"] += list(knowledge_data)
var/depth = knowledge_data[HKT_DEPTH]
data["knowledge_tiers"] = tiers
while(depth > length(tree_data))
tree_data += list(list("nodes" = list()))
return data
tree_data[depth]["nodes"] += list(knowledge_data)
/datum/antagonist/heretic/ui_static_data(mob/user)
var/list/data = list()
data["objectives"] = get_objectives()
data["can_change_objective"] = can_assign_self_objectives
if(!heretic_path)
data["knowledge_tiers"] = tree_data
return data
var/list/heretic_drafts = heretic_shops[HERETIC_KNOWLEDGE_DRAFT]
for(var/datum/heretic_knowledge/knowledge_path as anything in heretic_drafts)
var/list/knowledge_info = heretic_drafts[knowledge_path]
if(!(knowledge_info[HKT_ID] in researchable_knowledges))
continue
var/list/knowledge_data = get_knowledge_data(knowledge_path, heretic_drafts, FALSE, HERETIC_KNOWLEDGE_DRAFT)
var/depth = knowledge_data[HKT_DEPTH]
while(depth > length(tree_data))
tree_data += list(list("nodes" = list()))
tree_data[depth]["nodes"] += list(knowledge_data)
data["knowledge_tiers"] = tree_data
var/list/shop = heretic_shops[HERETIC_KNOWLEDGE_SHOP]
for(var/knowledge_path in shop)
var/list/knowledge_info = shop[knowledge_path]
if(!(knowledge_info[HKT_ID] in researchable_knowledges))
continue
var/list/knowledge_data = get_knowledge_data(knowledge_path, shop, FALSE, HERETIC_KNOWLEDGE_SHOP)
shop_knowledge += list(knowledge_data)
data["knowledge_shop"] = shop_knowledge
return data
@@ -207,21 +272,27 @@
var/datum/heretic_knowledge/researched_path = text2path(params["path"])
if(!ispath(researched_path, /datum/heretic_knowledge))
CRASH("Heretic attempted to learn non-heretic_knowledge path! (Got: [researched_path || "invalid path"])")
if(!(researched_path in get_researchable_knowledge()))
var/shop_category = params["category"]
if(!researchable_knowledge(researched_path, shop_category))
message_admins("Heretic [key_name(owner)] potentially attempted to href exploit to learn knowledge they can't learn!")
CRASH("Heretic attempted to learn knowledge they can't learn! (Got: [researched_path])")
if(ispath(researched_path, /datum/heretic_knowledge/ultimate) && !can_ascend())
if(ispath(researched_path, /datum/heretic_knowledge/ultimate) & can_ascend() != HERETIC_CAN_ASCEND)
message_admins("Heretic [key_name(owner)] potentially attempted to href exploit to learn ascension knowledge without completing objectives!")
CRASH("Heretic attempted to learn a final knowledge despite not being able to ascend!")
if(initial(researched_path.cost) > knowledge_points)
return TRUE
if(!gain_knowledge(researched_path))
return TRUE
if(!purchase_knowledge(researched_path, shop_category))
return FALSE
update_data_for_all_viewers()
log_heretic_knowledge("[key_name(owner)] gained knowledge: [initial(researched_path.name)]")
knowledge_points -= initial(researched_path.cost)
return TRUE
/datum/antagonist/heretic/proc/researchable_knowledge(datum/heretic_knowledge/knowledge_path, shop_category = HERETIC_KNOWLEDGE_TREE)
var/list/knowledge_info = heretic_shops[shop_category][knowledge_path]
if(knowledge_info[HKT_ID] in get_researchable_knowledge())
return TRUE
return FALSE
/datum/antagonist/heretic/submit_player_objective(retain_existing = FALSE, retain_escape = TRUE, force = FALSE)
if (isnull(owner) || isnull(owner.current))
return
@@ -243,7 +314,7 @@
/datum/antagonist/heretic/get_preview_icon()
var/icon/icon = render_preview_outfit(preview_outfit)
// MOTHBLOCKS TOOD: Copied and pasted from cult, make this its own proc
// MOTHBLOCKS TODO: Copied and pasted from cult, make this its own proc
// The sickly blade is 64x64, but getFlatIcon crunches to 32x32.
// So I'm just going to add it in post, screw it.
@@ -267,15 +338,20 @@
return ..()
/datum/antagonist/heretic/on_gain()
if(!GLOB.heretic_research_tree)
GLOB.heretic_research_tree = generate_heretic_research_tree()
generate_heretic_starting_knowledge(heretic_shops[HERETIC_KNOWLEDGE_START])
if(!length(path_info))
for(var/datum/heretic_knowledge_tree_column/path as anything in subtypesof(/datum/heretic_knowledge_tree_column))
path = new path()
path_info += list(path.get_ui_data(src, HERETIC_KNOWLEDGE_START))
qdel(path)
if(give_objectives)
forge_primary_objectives()
forge_primary_objectives(heretic_shops[HERETIC_KNOWLEDGE_TREE])
for(var/starting_knowledge in GLOB.heretic_start_knowledge)
gain_knowledge(starting_knowledge)
gain_knowledge(starting_knowledge, HERETIC_KNOWLEDGE_START, update = FALSE)
owner.current.AddElement(/datum/element/leeching_walk/minor)
ADD_TRAIT(owner, TRAIT_SEE_BLESSED_TILES, REF(src))
addtimer(CALLBACK(src, PROC_REF(passive_influence_gain)), passive_gain_timer) // Gain +1 knowledge every 20 minutes.
@@ -283,12 +359,15 @@
/datum/antagonist/heretic/on_removal()
if(owner.current)
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
for(var/knowledge_path in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_path][HKT_INSTANCE]
knowledge.on_lose(owner.current, src)
QDEL_NULL(researched_knowledge[knowledge_path][HKT_INSTANCE])
REMOVE_TRAIT(owner, TRAIT_SEE_BLESSED_TILES, REF(src))
QDEL_LIST_ASSOC_VAL(researched_knowledge)
owner.current.RemoveElement(/datum/element/leeching_walk/minor)
QDEL_NULL(heretic_path)
owner.current.cut_overlay(eldritch_overlay)
return ..()
/datum/antagonist/heretic/apply_innate_effects(mob/living/mob_override)
@@ -296,7 +375,7 @@
handle_clown_mutation(our_mob, "Ancient knowledge described to you has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
our_mob.faction |= FACTION_HERETIC
if (!issilicon(our_mob))
if(!issilicon(our_mob))
GLOB.reality_smash_track.add_tracked_mind(owner)
ADD_TRAIT(our_mob, TRAIT_MANSUS_TOUCHED, REF(src))
@@ -304,31 +383,89 @@
RegisterSignals(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED), PROC_REF(on_spell_cast))
RegisterSignal(our_mob, COMSIG_USER_ITEM_INTERACTION, PROC_REF(on_item_use))
RegisterSignal(our_mob, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(after_fully_healed))
RegisterSignal(our_mob, COMSIG_ATOM_EXAMINE, PROC_REF(on_heretic_examine))
RegisterSignals(
our_mob,
list(SIGNAL_ADDTRAIT(TRAIT_HERETIC_AURA_HIDDEN), SIGNAL_REMOVETRAIT(TRAIT_HERETIC_AURA_HIDDEN)),
PROC_REF(update_heretic_aura)
)
/datum/antagonist/heretic/remove_innate_effects(mob/living/mob_override)
var/mob/living/our_mob = mob_override || owner.current
handle_clown_mutation(our_mob, removing = FALSE)
our_mob.faction -= FACTION_HERETIC
if (owner in GLOB.reality_smash_track.tracked_heretics)
if(owner in GLOB.reality_smash_track.tracked_heretics)
GLOB.reality_smash_track.remove_tracked_mind(owner)
REMOVE_TRAIT(our_mob, TRAIT_MANSUS_TOUCHED, REF(src))
UnregisterSignal(our_mob, list(
COMSIG_MOB_BEFORE_SPELL_CAST,
COMSIG_MOB_SPELL_ACTIVATED,
COMSIG_USER_ITEM_INTERACTION,
COMSIG_LIVING_POST_FULLY_HEAL,
COMSIG_LIVING_CULT_SACRIFICED,
))
UnregisterSignal(
our_mob,
list(
COMSIG_MOB_BEFORE_SPELL_CAST,
COMSIG_MOB_SPELL_ACTIVATED,
COMSIG_USER_ITEM_INTERACTION,
COMSIG_LIVING_POST_FULLY_HEAL,
COMSIG_LIVING_CULT_SACRIFICED,
COMSIG_ATOM_EXAMINE,
SIGNAL_ADDTRAIT(TRAIT_HERETIC_AURA_HIDDEN),
SIGNAL_REMOVETRAIT(TRAIT_HERETIC_AURA_HIDDEN)
)
)
/// Removes the ability to blade break, removes cloak of shadows and removes the cap on how many blades you can craft
/datum/antagonist/heretic/proc/disable_blade_breaking()
if(unlimited_blades)
return
var/mob/heretic_mob = owner.current
unlimited_blades = TRUE
to_chat(heretic_mob, span_boldwarning("You have gained a lot of power, the mansus will no longer allow you to break your blades, but you can now make as many as you wish."))
heretic_mob.balloon_alert(heretic_mob, "blade breaking disabled!")
update_heretic_aura()
var/datum/action/cooldown/spell/shadow_cloak/cloak_spell = locate() in heretic_mob.actions
cloak_spell.Remove(heretic_mob)
/// Adds an overlay to the heretic
/datum/antagonist/heretic/proc/update_heretic_aura()
SIGNAL_HANDLER
var/mob/heretic_mob = owner.current
heretic_mob.cut_overlay(eldritch_overlay)
if(!should_show_aura())
return FALSE
heretic_mob.add_overlay(eldritch_overlay)
return TRUE
/datum/antagonist/heretic/proc/should_show_aura()
if(!can_assign_self_objectives)
return FALSE // We spurned the offer of the Mansus :(
if(!unlimited_blades || HAS_TRAIT(owner.current, TRAIT_HERETIC_AURA_HIDDEN))
return FALSE // No aura if we have the trait or is too early still
if(feast_of_owls)
return FALSE // No use in giving the aura to a heretic that can't ascend
if(heretic_path?.route == PATH_LOCK)
return FALSE // Lock heretics never get this aura
return TRUE
/datum/antagonist/heretic/proc/on_heretic_examine(datum/source, mob/user, text)
SIGNAL_HANDLER
if(!should_show_aura())
return
var/mob/heretic_mob = owner.current
var/potential_string = "[heretic_mob.p_They()] [heretic_mob.p_are()] crackling with a swirling green vortex of energy."
if(can_ascend() == HERETIC_CAN_ASCEND)
potential_string += " [heretic_mob.p_They()] [heretic_mob.p_are()] shedding [heretic_mob.p_their()] mortal shell!"
text += span_green(potential_string)
/datum/antagonist/heretic/on_body_transfer(mob/living/old_body, mob/living/new_body)
. = ..()
if(old_body == new_body) // if they were using a temporary body
return
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
for(var/knowledge_path in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_path][HKT_INSTANCE]
knowledge.on_lose(old_body, src)
knowledge.on_gain(new_body, src)
@@ -415,7 +552,7 @@
/datum/antagonist/heretic/proc/draw_rune(mob/living/user, turf/target_turf, drawing_time = 20 SECONDS, additional_checks)
drawing_rune = TRUE
var/rune_colour = GLOB.heretic_path_to_color[heretic_path]
var/rune_colour = GLOB.heretic_path_to_color[heretic_path?.route || PATH_START]
target_turf.balloon_alert(user, "drawing rune...")
var/obj/effect/temp_visual/drawing_heretic_rune/drawing_effect
if (drawing_time < (10 SECONDS))
@@ -569,8 +706,8 @@
/**
* Create our objectives for our heretic.
*/
/datum/antagonist/heretic/proc/forge_primary_objectives()
var/datum/objective/heretic_research/research_objective = new()
/datum/antagonist/heretic/proc/forge_primary_objectives(heretic_research_tree)
var/datum/objective/heretic_research/research_objective = new(heretic_research_tree = heretic_research_tree)
research_objective.owner = owner
objectives += research_objective
@@ -582,7 +719,7 @@
var/datum/objective/minor_sacrifice/sac_objective = new()
sac_objective.owner = owner
if(num_heads < 2) // They won't get major sacrifice, so bump up minor sacrifice a bit
sac_objective.target_amount += 2
sac_objective.target_amount = 5
sac_objective.update_explanation_text()
objectives += sac_objective
@@ -630,11 +767,19 @@
* Used in callbacks for passive gain over time.
*/
/datum/antagonist/heretic/proc/passive_influence_gain()
knowledge_points++
if(owner.current.stat <= SOFT_CRIT)
adjust_knowledge_points(1)
if(owner?.current?.stat <= SOFT_CRIT)
to_chat(owner.current, "[span_hear("You hear a whisper...")] [span_hypnophrase(pick_list(HERETIC_INFLUENCE_FILE, "drain_message"))]")
addtimer(CALLBACK(src, PROC_REF(passive_influence_gain)), passive_gain_timer)
/datum/antagonist/heretic/proc/adjust_knowledge_points(amount, update = TRUE)
knowledge_points = max(0, knowledge_points + amount) // Don't allow negative knowledge points
knowledge_gained += max(0, amount)
if(knowledge_gained > 8 && !unlimited_blades)
disable_blade_breaking()
if(update)
update_data_for_all_viewers()
/datum/antagonist/heretic/roundend_report()
var/list/parts = list()
@@ -665,8 +810,9 @@
var/list/string_of_knowledge = list()
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
for(var/knowledge_path in researched_knowledge)
var/list/knowledge_info = researched_knowledge[knowledge_path]
var/datum/heretic_knowledge/knowledge = knowledge_info[HKT_INSTANCE]
string_of_knowledge += knowledge.name
parts += english_list(string_of_knowledge)
@@ -758,7 +904,7 @@
if(!change_num || QDELETED(src))
return
knowledge_points += change_num
adjust_knowledge_points(change_num)
/**
* Admin proc for giving a heretic a focus.
@@ -775,8 +921,8 @@
/datum/antagonist/heretic/antag_panel_data()
var/list/string_of_knowledge = list()
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
for(var/knowledge_path in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_path][HKT_INSTANCE]
if(istype(knowledge, /datum/heretic_knowledge/ultimate))
string_of_knowledge += span_bold(knowledge.name)
else
@@ -797,35 +943,72 @@
. += "<i>None!</i><br>"
. += "<br>"
/datum/antagonist/heretic/proc/purchase_knowledge(datum/heretic_knowledge/knowledge_type, category = HERETIC_KNOWLEDGE_TREE, update = TRUE)
var/list/shop_list = heretic_shops[category]
if(!shop_list)
stack_trace("Heretic attempted to learn knowledge from a non-existent category! (Got: [category])")
return FALSE
var/list/knowledge_data = shop_list[knowledge_type]
if(!knowledge_data)
stack_trace("[type] purchase_knowledge was given a path that doesn't exist in the heretic [category] knowledge list! (Got: [knowledge_type])")
return FALSE
var/cost = knowledge_data[HKT_COST]
if(cost > knowledge_points)
return FALSE
if(!gain_knowledge(knowledge_type, category, update))
return FALSE
adjust_knowledge_points(-cost, FALSE)
return TRUE
/**
* Learns the passed [typepath] of knowledge, creating a knowledge datum
* and adding it to our researched knowledge list.
*
* Returns TRUE if the knowledge was added successfully. FALSE otherwise.
*/
/datum/antagonist/heretic/proc/gain_knowledge(datum/heretic_knowledge/knowledge_type)
/datum/antagonist/heretic/proc/gain_knowledge(datum/heretic_knowledge/knowledge_type, category = HERETIC_KNOWLEDGE_TREE, update = TRUE)
var/list/knowledge_list = heretic_shops[category]
if(!ispath(knowledge_type))
stack_trace("[type] gain_knowledge was given an invalid path! (Got: [knowledge_type])")
return FALSE
var/list/knowledge_data = knowledge_list[knowledge_type]
if(!islist(knowledge_data))
knowledge_data = make_knowledge_entry(knowledge_type, category)
heretic_shops[category][knowledge_type] = knowledge_data
if(get_knowledge(knowledge_type))
return FALSE
var/datum/heretic_knowledge/initialized_knowledge = new knowledge_type()
researched_knowledge[knowledge_type] = initialized_knowledge
if(!initialized_knowledge.pre_research(owner.current, src))
return FALSE
researched_knowledge[knowledge_type] = knowledge_data.Copy()
researched_knowledge[knowledge_type][HKT_INSTANCE] = initialized_knowledge
researched_knowledge[knowledge_type][HKT_CATEGORY] = category
// case for letting you modify depth post-purchase
var/purchased_depth = knowledge_data[HKT_PURCHASED_DEPTH]
if(purchased_depth != 0 && isnum(purchased_depth))
researched_knowledge[knowledge_type][HKT_DEPTH] = purchased_depth
knowledge_list -= knowledge_type
initialized_knowledge.on_research(owner.current, src)
update_static_data(owner.current)
if(update)
update_data_for_all_viewers()
return TRUE
/**
* Get a list of all knowledge TYPEPATHS that we can currently research.
* Get a list of all knowledge IDs that we can currently research.
*/
/datum/antagonist/heretic/proc/get_researchable_knowledge()
var/list/researchable_knowledge = list()
var/list/banned_knowledge = list()
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
researchable_knowledge |= GLOB.heretic_research_tree[knowledge_index][HKT_NEXT]
banned_knowledge |= GLOB.heretic_research_tree[knowledge_index][HKT_BAN]
banned_knowledge |= knowledge.type
for(var/knowledge_type in researched_knowledge)
var/list/knowledge_info = researched_knowledge[knowledge_type]
researchable_knowledge |= knowledge_info[HKT_NEXT]
banned_knowledge |= knowledge_info[HKT_BAN]
banned_knowledge |= knowledge_type
researchable_knowledge -= banned_knowledge
return researchable_knowledge
@@ -833,7 +1016,10 @@
* Check if the wanted type-path is in the list of research knowledge.
*/
/datum/antagonist/heretic/proc/get_knowledge(wanted)
return researched_knowledge[wanted]
var/list/knowledge_data = researched_knowledge[wanted]
if(knowledge_data)
return knowledge_data[HKT_INSTANCE]
return null
/// Makes our heretic more able to rust things.
/// if side_path_only is set to TRUE, this function does nothing for rust heretics.
@@ -852,8 +1038,8 @@
/datum/antagonist/heretic/proc/get_rituals()
var/list/rituals = list()
for(var/knowledge_index in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_index]
for(var/knowledge_path in researched_knowledge)
var/datum/heretic_knowledge/knowledge = researched_knowledge[knowledge_path][HKT_INSTANCE]
if(!knowledge.can_be_invoked(src))
continue
rituals[knowledge.name] = knowledge
@@ -866,14 +1052,19 @@
* Returns FALSE if not all of our objectives are complete, or TRUE otherwise.
*/
/datum/antagonist/heretic/proc/can_ascend()
if(!can_assign_self_objectives)
return FALSE // We spurned the offer of the Mansus :(
if(feast_of_owls)
return FALSE // We sold our ambition for immediate power :/
return "The owls have taken your right of ascension (denied ascension)." // We sold our ambition for immediate power :/
if(!can_assign_self_objectives)
return "The mansus has spurned you (denied ascension)."
for(var/datum/objective/must_be_done as anything in objectives)
if(!must_be_done.check_completion())
return FALSE
return TRUE
return "Must complete all objectives before ascending."
var/config_time = CONFIG_GET(number/minimum_ascension_time) MINUTES
var/time_passed = STATION_TIME_PASSED()
if(config_time >= time_passed)
return "Too early, must wait [DisplayTimeText(config_time - time_passed)] before ascending."
return HERETIC_CAN_ASCEND
/**
* Helper to determine if a Heretic
@@ -901,7 +1092,7 @@
/datum/objective/minor_sacrifice/New(text)
. = ..()
target_amount = rand(3, 4)
target_amount = 4
update_explanation_text()
/datum/objective/minor_sacrifice/update_explanation_text()
@@ -932,7 +1123,7 @@
/// The length of a main path. Calculated once in New().
var/static/main_path_length = 0
/datum/objective/heretic_research/New(text)
/datum/objective/heretic_research/New(text, heretic_research_tree)
. = ..()
if(!main_path_length)
@@ -940,7 +1131,8 @@
// (All the main paths are (should be) the same length, so it doesn't matter.)
var/rust_paths_found = 0
for(var/datum/heretic_knowledge/knowledge as anything in subtypesof(/datum/heretic_knowledge))
if(GLOB.heretic_research_tree[knowledge][HKT_ROUTE] == PATH_RUST)
var/list/knowledge_data = heretic_research_tree[knowledge]
if(knowledge_data && knowledge_data[HKT_ROUTE] == PATH_RUST)
rust_paths_found++
main_path_length = rust_paths_found

View File

@@ -32,6 +32,8 @@
var/priority = 0
///If this is considered starting knowledge, TRUE if yes
var/is_starting_knowledge = FALSE
/// If the spell is final knowledge, disables blade breaking and removes the cap on how many blades we can make
var/is_final_knowledge = FALSE
/// In case we want to override the default UI icon getter and plug in our own icon instead.
/// if research_tree_icon_path is not null, research_tree_icon_state must also be specified or things may break
var/research_tree_icon_path
@@ -40,6 +42,23 @@
var/research_tree_icon_dir = SOUTH
///Determines what kind of monster ghosts will ignore from here on out. Defaults to POLL_IGNORE_HERETIC_MONSTER, but we define other types of monsters for more granularity.
var/poll_ignore_define = POLL_IGNORE_HERETIC_MONSTER
/// This is used for the drafting system. By default is 0 (Meaning it won't show up in the draft), also makes it show up in the shop according to this tier
var/drafting_tier = 0
/// decides if it's added to the shop, only, and not drafts
var/is_shop_only = FALSE
/**
* Called before the knowledge is researched,
* use this for any checks that should happen before the knowledge is researched.
* Returns TRUE if the knowledge can be researched, FALSE otherwise.
*/
/datum/heretic_knowledge/proc/pre_research(mob/user, datum/antagonist/heretic/our_heretic)
// consider moving this check to a type instead
if(is_final_knowledge && !our_heretic.unlimited_blades)
var/choice = tgui_alert(user, "THIS WILL DISABLE BLADE BREAKING, Are you ready to research this? The blade cap will also be removed.", "Get Final Spell?", list("Yes", "No"))
if(choice != "Yes")
return FALSE
return TRUE
/** Called when the knowledge is first researched.
* This is only ever called once per heretic.
@@ -54,6 +73,8 @@
if(gain_text)
to_chat(user, span_warning("[gain_text]"))
on_gain(user, our_heretic)
if(is_final_knowledge && !our_heretic.unlimited_blades)
our_heretic.disable_blade_breaking()
/**
* Called when the knowledge is applied to a mob.
@@ -210,6 +231,11 @@
return ..()
/datum/heretic_knowledge/limited_amount/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/our_heretic = IS_HERETIC(user)
if(our_heretic && our_heretic.unlimited_blades)
if(length(result_atoms & typesof(/obj/item/melee/sickly_blade)))
return TRUE
for(var/datum/weakref/ref as anything in created_items)
var/atom/real_thing = ref.resolve()
if(QDELETED(real_thing))
@@ -230,6 +256,7 @@
/**
* A knowledge subtype for limited_amount knowledge
* used for base knowledge (the ones that make blades)
* Grants your path-relevant grasp upgrade, passive and grasp mark
*
* A heretic can only learn one /starting type knowledge,
* and their ascension depends on whichever they chose.
@@ -239,38 +266,55 @@
limit = 2
cost = 1
priority = MAX_KNOWLEDGE_PRIORITY - 5
/// The status effect typepath we apply on people on mansus grasp.
var/datum/status_effect/eldritch/mark_type
/// The status effect of our passive
var/datum/status_effect/heretic_passive/eldritch_passive = /datum/status_effect/heretic_passive
/datum/heretic_knowledge/limited_amount/starting/on_research(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
our_heretic.heretic_path = GLOB.heretic_research_tree[type][HKT_ROUTE]
SSblackbox.record_feedback("tally", "heretic_path_taken", 1, our_heretic.heretic_path)
for(var/datum/heretic_knowledge_tree_column/column_path as anything in subtypesof(/datum/heretic_knowledge_tree_column))
if(column_path::route != our_heretic.researched_knowledge[type][HKT_ROUTE])
continue
our_heretic.heretic_path = new column_path()
if(!our_heretic.heretic_path)
// If we don't have a path, we can't continue.
to_chat(user, span_warning("Oh shit, something broke, no path found!"))
stack_trace("failed to find valid path [our_heretic.heretic_shops[HERETIC_KNOWLEDGE_TREE][type][HKT_ROUTE]] from researching [src]")
return
SSblackbox.record_feedback("tally", "heretic_path_taken", 1, our_heretic.heretic_path.route)
our_heretic.update_heretic_aura()
our_heretic.generate_heretic_research_tree()
determine_drafted_knowledge(
our_heretic.heretic_path.route,
our_heretic.heretic_shops[HERETIC_KNOWLEDGE_TREE],
our_heretic.heretic_shops[HERETIC_KNOWLEDGE_SHOP],
our_heretic.heretic_shops[HERETIC_KNOWLEDGE_DRAFT],
)
SEND_SIGNAL(src, COMSIG_HERETIC_SHOP_SETUP)
/**
* A knowledge subtype for heretic knowledge
* that applies a mark on use.
*
* A heretic can only learn one /mark type knowledge.
*/
/datum/heretic_knowledge/mark
abstract_parent_type = /datum/heretic_knowledge/mark
cost = 2
/// The status effect typepath we apply on people on mansus grasp.
var/datum/status_effect/eldritch/mark_type
/datum/heretic_knowledge/mark/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
/datum/heretic_knowledge/limited_amount/starting/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignals(user, list(COMSIG_HERETIC_MANSUS_GRASP_ATTACK, COMSIG_LIONHUNTER_ON_HIT), PROC_REF(on_mansus_grasp))
RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(on_eldritch_blade))
if(isliving(user))
var/mob/living/living_user = user
living_user.apply_status_effect(eldritch_passive)
/datum/heretic_knowledge/mark/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
/datum/heretic_knowledge/limited_amount/starting/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, list(COMSIG_HERETIC_MANSUS_GRASP_ATTACK, COMSIG_HERETIC_BLADE_ATTACK))
if(isliving(user))
var/mob/living/living_user = user
living_user.remove_status_effect(eldritch_passive)
/**
* Signal proc for [COMSIG_HERETIC_MANSUS_GRASP_ATTACK].
*
* Whenever we cast mansus grasp on someone, apply our mark.
*/
/datum/heretic_knowledge/mark/proc/on_mansus_grasp(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
SHOULD_CALL_PARENT(TRUE)
create_mark(source, target)
@@ -279,7 +323,7 @@
*
* Whenever we attack someone with our blade, attempt to trigger any marks on them.
*/
/datum/heretic_knowledge/mark/proc/on_eldritch_blade(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
/datum/heretic_knowledge/limited_amount/starting/proc/on_eldritch_blade(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
SIGNAL_HANDLER
if(!isliving(target))
@@ -293,7 +337,7 @@
*
* Can be overriden to set or pass in additional vars of the status effect.
*/
/datum/heretic_knowledge/mark/proc/create_mark(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/proc/create_mark(mob/living/source, mob/living/target)
if(target.stat == DEAD)
return
return target.apply_status_effect(mark_type)
@@ -303,7 +347,7 @@
*
* If there is no mark, returns FALSE. Returns TRUE if a mark was triggered.
*/
/datum/heretic_knowledge/mark/proc/trigger_mark(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/proc/trigger_mark(mob/living/source, mob/living/target)
var/datum/status_effect/eldritch/mark = target.has_status_effect(/datum/status_effect/eldritch)
if(!istype(mark))
return FALSE
@@ -319,7 +363,7 @@
*/
/datum/heretic_knowledge/blade_upgrade
abstract_parent_type = /datum/heretic_knowledge/blade_upgrade
cost = 2
cost = 1
/datum/heretic_knowledge/blade_upgrade/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(on_eldritch_blade))
@@ -416,7 +460,6 @@
var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
heretic_monster.set_owner(user.mind)
ADD_TRAIT(heretic_monster, TRAIT_HERETIC_SUMMON, INNATE_TRAIT)
var/datum/objective/heretic_summon/summon_objective = locate() in user.mind.get_all_objectives()
summon_objective?.num_summoned++
@@ -467,22 +510,18 @@
)
var/static/list/potential_uncommoner_items = list(
/obj/item/restraints/legcuffs/beartrap,
/obj/item/restraints/handcuffs/cable/zipties,
/obj/item/melee/baton,
/obj/item/circular_saw,
/obj/item/scalpel,
/obj/item/clothing/gloves/color/yellow,
/obj/item/melee/baton/security,
/obj/item/clothing/glasses/sunglasses,
)
required_atoms = list()
// 2 organs. Can be the same.
// 1 Organ, 1 Easy, 1 Hard
required_atoms[pick(potential_organs)] += 1
required_atoms[pick(potential_organs)] += 1
// 2-3 random easy items.
required_atoms[pick(potential_easy_items)] += rand(2, 3)
// 1 uncommon item.
required_atoms[pick(potential_easy_items)] += 1
required_atoms[pick(potential_uncommoner_items)] += 1
/datum/heretic_knowledge/knowledge_ritual/on_research(mob/user, datum/antagonist/heretic/our_heretic)
@@ -508,7 +547,7 @@
/datum/heretic_knowledge/knowledge_ritual/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/our_heretic = GET_HERETIC(user)
our_heretic.knowledge_points += KNOWLEDGE_RITUAL_POINTS
our_heretic.adjust_knowledge_points(KNOWLEDGE_RITUAL_POINTS)
was_completed = TRUE
to_chat(user, span_boldnotice("[name] completed!"))
@@ -516,6 +555,7 @@
desc += " (Completed!)"
log_heretic_knowledge("[key_name(user)] completed a [name] at [gameTimestamp()].")
user.add_mob_memory(/datum/memory/heretic_knowledge_ritual)
SEND_SIGNAL(our_heretic, COMSIG_HERETIC_PASSIVE_UPGRADE_FINAL)
return TRUE
#undef KNOWLEDGE_RITUAL_POINTS
@@ -540,8 +580,9 @@
/datum/heretic_knowledge/ultimate/on_research(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
var/total_points = 0
for(var/datum/heretic_knowledge/knowledge as anything in assoc_to_values(our_heretic.researched_knowledge))
total_points += knowledge.cost
for(var/datum/heretic_knowledge/knowledge as anything in our_heretic.researched_knowledge)
var/list/cost = our_heretic.researched_knowledge[knowledge][HKT_COST]
total_points += cost
log_heretic_knowledge("[key_name(user)] gained knowledge of their final ritual at [gameTimestamp()]. \
They have [length(our_heretic.researched_knowledge)] knowledge nodes researched, totalling [total_points] points \
@@ -551,7 +592,7 @@
if(invoker.ascended)
return FALSE
if(!invoker.can_ascend())
if(invoker.can_ascend() != HERETIC_CAN_ASCEND)
return FALSE
return TRUE
@@ -578,8 +619,11 @@
return (sacrifice.stat == DEAD) && !ismonkey(sacrifice)
/datum/heretic_knowledge/ultimate/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = GET_HERETIC(user)
heretic_datum.ascended = TRUE
// In case we skipped ritual of knowledge
SEND_SIGNAL(heretic_datum, COMSIG_HERETIC_PASSIVE_UPGRADE_FINAL)
// Show the cool red gradiant in our UI
heretic_datum.update_static_data(user)
@@ -589,7 +633,7 @@
human_user.physiology.brute_mod *= 0.5
human_user.physiology.burn_mod *= 0.5
SSblackbox.record_feedback("tally", "heretic_ascended", 1, GLOB.heretic_research_tree[type][HKT_ROUTE])
SSblackbox.record_feedback("tally", "heretic_ascended", 1, heretic_datum.heretic_path.route)
log_heretic_knowledge("[key_name(user)] completed their final ritual at [gameTimestamp()].")
notify_ghosts(
"[user.real_name] has completed an ascension ritual!",
@@ -603,9 +647,13 @@
color_override = "pink",
)
if(EMERGENCY_IDLE_OR_RECALLED)
SSshuttle.call_evac_shuttle("Critical reality rupture detected on supranatural casuality long-range scanners. Mass crew casualty and possible station destruction determined to be beyond acceptable probability. Priority evacuation shuttle dispatched.")
SSshuttle.emergency_no_recall = TRUE
if(!isnull(ascension_achievement))
user.client?.give_award(ascension_achievement, user)
heretic_datum.increase_rust_strength()
heretic_datum.rust_strength = 4 // Ascended heretics can rust whatever they want (below RUST_RESISTANCE_ABSOLUTE)
ADD_TRAIT(user, TRAIT_DESENSITIZED, type)
return TRUE

View File

@@ -23,6 +23,16 @@
master = null
return ..()
/datum/antagonist/heretic_monster/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/target = mob_override || owner.current
ADD_TRAIT(target, TRAIT_HERETIC_SUMMON, REF(src))
/datum/antagonist/heretic_monster/remove_innate_effects(mob/living/mob_override)
var/mob/living/target = mob_override || owner.current
REMOVE_TRAIT(target, TRAIT_HERETIC_SUMMON, REF(src))
return ..()
/*
* Set our [master] var to a new mind.
*/

View File

@@ -170,6 +170,8 @@
var/being_drained = FALSE
/// The icon state applied to the image created for this influence.
var/real_icon_state = "reality_smash"
/// Proximity monitor that gives any nearby heretics x-ray vision
var/datum/proximity_monitor/influence_monitor/monitor
/obj/effect/heretic_influence/Initialize(mapload)
. = ..()
@@ -182,12 +184,14 @@
AddElement(/datum/element/block_turf_fingerprints)
AddComponent(/datum/component/redirect_attack_hand_from_turf, interact_check = CALLBACK(src, PROC_REF(verify_user_can_see)))
AddComponent(/datum/component/fishing_spot, GLOB.preset_fish_sources[/datum/fish_source/dimensional_rift])
monitor = new(src, 7)
/obj/effect/heretic_influence/proc/verify_user_can_see(mob/user)
return (user.mind in GLOB.reality_smash_track.tracked_heretics)
/obj/effect/heretic_influence/Destroy()
GLOB.reality_smash_track.smashes -= src
QDEL_NULL(monitor)
return ..()
/obj/effect/heretic_influence/attack_hand_secondary(mob/user, list/modifiers)
@@ -224,21 +228,29 @@
*
* If successful, the influence is drained and deleted.
*/
/obj/effect/heretic_influence/proc/drain_influence(mob/living/user, knowledge_to_gain, drain_speed = 10 SECONDS)
/obj/effect/heretic_influence/proc/drain_influence(mob/living/user, knowledge_to_gain, drain_speed = HERETIC_RIFT_DEFAULT_DRAIN_SPEED)
being_drained = TRUE
loc.balloon_alert(user, "draining influence...")
// Only gives you the dripping eye effect if you have faster drain speed than default
var/mutable_appearance/draining_overlay = mutable_appearance('icons/mob/effects/heretic_aura.dmi', "heretic_eye_dripping")
if(drain_speed < HERETIC_RIFT_DEFAULT_DRAIN_SPEED)
draining_overlay.pixel_y = 16
user.add_overlay(draining_overlay)
if(!do_after(user, drain_speed, src, hidden = TRUE))
being_drained = FALSE
loc.balloon_alert(user, "interrupted!")
user.cut_overlay(draining_overlay)
return
// We don't need to set being_drained back since we delete after anyways
loc.balloon_alert(user, "influence drained")
user.cut_overlay(draining_overlay)
var/datum/antagonist/heretic/heretic_datum = GET_HERETIC(user)
heretic_datum.knowledge_points += knowledge_to_gain
heretic_datum.adjust_knowledge_points(knowledge_to_gain)
// Aaand now we delete it
after_drain(user)
@@ -269,3 +281,19 @@
/datum/atom_hud/alternate_appearance/basic/has_antagonist/heretic
antag_datum_type = /datum/antagonist/heretic
add_ghost_version = TRUE
/datum/proximity_monitor/influence_monitor
/// Cooldown before we can give another heretic xray
COOLDOWN_DECLARE(xray_cooldown)
/datum/proximity_monitor/influence_monitor/on_entered(atom/source, atom/movable/arrived, turf/old_loc)
. = ..()
if(!isliving(arrived))
return
if(!COOLDOWN_FINISHED(src, xray_cooldown))
return
var/mob/living/arrived_living = arrived
if(!IS_HERETIC(arrived_living))
return
arrived_living.apply_status_effect(/datum/status_effect/temporary_xray/eldritch)
COOLDOWN_START(src, xray_cooldown, 3 MINUTES)

View File

@@ -44,7 +44,7 @@
return
if(IS_HERETIC(viewer))
return
if(viewer.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_MIND))
if(viewer.can_block_magic(MAGIC_RESISTANCE_MOON))
return
if(viewer.reagents.has_reagent(/datum/reagent/water/holywater))
return
@@ -54,7 +54,7 @@
to_chat(viewer, span_hypnophrase("Your mind is overcome! The painting leaves a mark on your psyche."))
/obj/structure/sign/painting/eldritch/wirecutter_act(mob/living/user, obj/item/I)
if(!user.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_MIND))
if(!user.can_block_magic(MAGIC_RESISTANCE_MOON))
user.add_mood_event("ripped_eldritch_painting", /datum/mood_event/eldritch_painting)
to_chat(user, span_hypnophrase("There's an itch in your brain. It's laughing at you..."))
qdel(src)

View File

@@ -11,7 +11,7 @@
/// Helps determine the icon state of this item when it's used on self.
var/book_open = FALSE
/// How fast we can drain influences
var/drain_speed = 10 SECONDS
var/drain_speed = 5 SECONDS
/// How fast we can draw runes
var/draw_speed = 8 SECONDS
@@ -79,7 +79,7 @@
desc = "A hideous, ragged book covered in separately-blinking eyes, all of them staring at you. You have no idea how to hold this thing, and to be honest you're not sure if you want to."
base_icon_state = "book_morbus"
icon_state = "book_morbus"
drain_speed = 7 SECONDS
drain_speed = 2.5 SECONDS
draw_speed = 5 SECONDS
/// List of mobs we've cursed with transmutation. When the codex is destroyed all those curses become undone
var/list/transmuted_victims = list()

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,9 @@
return .
/obj/item/melee/sickly_blade/attack_self(mob/user)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
if(heretic_datum?.unlimited_blades)
return
if(HAS_TRAIT(user, TRAIT_ELDRITCH_ARENA_PARTICIPANT))
user.balloon_alert(user, "can't escape!")
if(escape_attempts > 2)
@@ -170,16 +173,13 @@
if(!heretic_datum)
return
//Apply our heretic mark
var/datum/heretic_knowledge/mark/blade_mark/mark_to_apply = heretic_datum.get_knowledge(/datum/heretic_knowledge/mark/blade_mark)
// Apply our heretic mark
var/datum/heretic_knowledge/limited_amount/starting/base_blade/mark_to_apply = heretic_datum.get_knowledge(/datum/heretic_knowledge/limited_amount/starting/base_blade)
if(!mark_to_apply)
return
mark_to_apply.create_mark(user, living_target)
//Remove the infusion from any blades we own (and update their sprite)
for(var/obj/item/melee/sickly_blade/dark/to_infuse in user.get_all_contents_type(/obj/item/melee/sickly_blade/dark))
to_infuse.infused = FALSE
to_infuse.update_appearance(UPDATE_ICON)
infused = FALSE
update_appearance(UPDATE_ICON)
user.update_held_items()
if(!check_behind(user, living_target))

View File

@@ -146,7 +146,6 @@
icon_state = "eye_medalion"
w_class = WEIGHT_CLASS_SMALL
// The amulet conversion tool used by moon heretics
/obj/item/clothing/neck/heretic_focus/moon_amulet
name = "moonlight amulet"
@@ -154,31 +153,158 @@
icon = 'icons/obj/antags/eldritch.dmi'
icon_state = "moon_amulette"
w_class = WEIGHT_CLASS_SMALL
// How much damage does this item do to the targets sanity?
/// How much damage does this item do to the targets sanity?
var/sanity_damage = 20
var/list/possible_sounds = list(
'sound/items/sitcom_laugh/SitcomLaugh1.ogg',
'sound/items/sitcom_laugh/SitcomLaugh2.ogg',
'sound/items/sitcom_laugh/SitcomLaugh3.ogg',
)
var/valid_weapon_type = /obj/item/melee/sickly_blade
var/sanity_threshold = SANITY_LEVEL_INSANE
/obj/item/clothing/neck/heretic_focus/moon_amulet/examine(mob/user)
. = ..()
if(IS_HERETIC(user))
. += span_notice("Wearing this amulet increases your healing speed by 50%")
/obj/item/clothing/neck/heretic_focus/moon_amulet/equipped(mob/living/user, slot)
. = ..()
if(!IS_HERETIC(user) && (slot_flags & slot))
channel_amulet(user)
return // Equipping the amulet as a non-heretic will give you a fat mood debuff and nothing else
if(!(slot_flags & slot))
on_amulet_deactivate(user)
return
on_amulet_activate(user)
/// Modifies any blades you hold/pickup/drop when the amulet is enabled
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/on_amulet_activate(mob/living/user)
RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(blade_channel))
RegisterSignal(user, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equip_item))
RegisterSignal(user, COMSIG_MOB_DROPPED_ITEM, PROC_REF(on_dropped_item))
// Just make sure we pacify blades potentially in our hands when we put on the amulet
on_equip_item(user, user.get_active_held_item(), ITEM_SLOT_HANDS)
on_equip_item(user, user.get_inactive_held_item(), ITEM_SLOT_HANDS)
ADD_TRAIT(user, TRAIT_THERMAL_VISION, REF(src))
user.update_sight()
// If the equipper is a moon heretic, we buff their passive
var/datum/status_effect/heretic_passive/moon/moon_passive = user.has_status_effect(/datum/status_effect/heretic_passive/moon)
moon_passive?.amulet_equipped = TRUE
/// Modifies any blades you hold/pickup/drop when the amulet is disabled
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/on_amulet_deactivate(mob/living/user)
// Make sure to restore the values of any blades we might be holding when our amulet is deactivated
on_dropped_item(user, user.get_active_held_item())
on_dropped_item(user, user.get_inactive_held_item())
UnregisterSignal(user, list(COMSIG_HERETIC_BLADE_ATTACK, COMSIG_MOB_EQUIPPED_ITEM, COMSIG_MOB_DROPPED_ITEM))
REMOVE_TRAIT(user, TRAIT_THERMAL_VISION, REF(src))
user.update_sight()
var/datum/status_effect/heretic_passive/moon/moon_passive = user.has_status_effect(/datum/status_effect/heretic_passive/moon)
moon_passive?.amulet_equipped = FALSE
/obj/item/clothing/neck/heretic_focus/moon_amulet/dropped(mob/living/user)
on_amulet_deactivate(user)
return ..()
/obj/item/clothing/neck/heretic_focus/moon_amulet/attack(mob/living/target, mob/living/user, list/modifiers, list/attack_modifiers)
var/mob/living/carbon/human/hit = target
if(!IS_HERETIC_OR_MONSTER(user))
user.balloon_alert(user, "you feel a presence watching you")
user.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity)
user.mob_mood.adjust_sanity(-50)
if(channel_amulet(user, target))
return
return ..()
if(hit.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_MIND))
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/blade_channel(mob/living/attacker, mob/living/victim)
SIGNAL_HANDLER
channel_amulet(attacker, victim)
/// Makes whoever the target is a bit more insane. If they are insane enough, they will be zombified into a moon zombie
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/channel_amulet(mob/user, atom/target)
if(!isliving(user))
return FALSE
var/mob/living/living_user = user
if(!IS_HERETIC_OR_MONSTER(living_user))
living_user.balloon_alert(living_user, "you feel a presence watching you")
living_user.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity)
living_user.mob_mood.adjust_sanity(-50)
return FALSE
if(!isliving(target))
return FALSE
var/mob/living/living_target = target
if(!ishuman(target))
living_target.adjustFireLoss(30)
return TRUE
var/mob/living/carbon/human/human_target = target
if(IS_HERETIC_OR_MONSTER(human_target))
living_user.balloon_alert(living_user, "resists effects!")
return FALSE
if(human_target.has_status_effect(/datum/status_effect/moon_slept) || human_target.has_status_effect(/datum/status_effect/moon_converted))
human_target.balloon_alert(living_user, "causing damage!")
human_target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 25)
return FALSE
if(human_target.can_block_magic(MAGIC_RESISTANCE_MOON))
return FALSE
if(!human_target.mob_mood)
return FALSE
if(human_target.mob_mood.sanity_level < sanity_threshold)
human_target.balloon_alert(living_user, "their mind is too strong!")
human_target.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity)
human_target.mob_mood.adjust_sanity(-sanity_damage)
else
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
human_target.balloon_alert(living_user, "their mind almost bends but something protects it!")
human_target.apply_status_effect(/datum/status_effect/moon_slept)
return TRUE
human_target.balloon_alert(living_user, "their mind bends to see the truth!")
human_target.apply_status_effect(/datum/status_effect/moon_converted)
living_user.log_message("made [human_target] insane.", LOG_GAME)
human_target.log_message("was driven insane by [living_user]", LOG_GAME)
return TRUE
/// Modifies any blades that we equip while wearing the amulet
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/on_equip_item(mob/user, obj/item/blade, slot)
SIGNAL_HANDLER
if(!istype(blade, valid_weapon_type))
return // We only care about modifying blades
if(slot & ITEM_SLOT_HANDS)
blade.force = 0
blade.wound_bonus = 0
blade.exposed_wound_bonus = 0
blade.armour_penetration = 200
RegisterSignal(blade, COMSIG_SEND_ITEM_ATTACK_MESSAGE_OBJECT, PROC_REF(modify_attack_message))
return
blade.force = initial(blade.force)
blade.wound_bonus = initial(blade.wound_bonus)
blade.exposed_wound_bonus = initial(blade.exposed_wound_bonus)
blade.armour_penetration = initial(blade.armour_penetration)
UnregisterSignal(blade, COMSIG_SEND_ITEM_ATTACK_MESSAGE_OBJECT)
if(!hit.mob_mood)
return
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/modify_attack_message(obj/item/weapon, mob/living/victim, mob/living/attacker)
SIGNAL_HANDLER
if(hit.mob_mood.sanity_level > SANITY_LEVEL_UNSTABLE)
user.balloon_alert(user, "their mind is too strong!")
hit.add_mood_event("Moon Amulet Insanity", /datum/mood_event/amulet_insanity)
hit.mob_mood.adjust_sanity(-sanity_damage)
return ..()
var/list/attack_list = list(
"You sweep [weapon] towards [victim], splitting [victim.p_Their()] image in two.",
"You strike [victim] with [weapon], spilling forth a cascade from within. Immaculate.",
"As it bite deep, your [weapon] unburdens [victim] of unneeded thought.",
)
to_chat(attacker, span_danger(pick(attack_list)))
user.balloon_alert(user, "their mind bends to see the truth!")
hit.apply_status_effect(/datum/status_effect/moon_converted)
user.log_message("made [target] insane.", LOG_GAME)
hit.log_message("was driven insane by [user]")
. = ..()
var/list/victim_list = list(
"You are struck by [attacker], but the [weapon] tears away something more than parts of your body.",
"You see an arch of light as [attacker]'s [weapon] twists towards you, and you see the world briefly in tetrachrome.",
"As [attacker] carves into you with [weapon], you lose something deep within. The agony is worse than any wound.",
)
to_chat(victim, span_userdanger(pick(victim_list)))
playsound(attacker, pick(possible_sounds), 40, TRUE)
return SIGNAL_MESSAGE_MODIFIED
/// Modifies any blades that we drop while wearing the amulet
/obj/item/clothing/neck/heretic_focus/moon_amulet/proc/on_dropped_item(mob/user, obj/item/dropped_item)
SIGNAL_HANDLER
if(!istype(dropped_item, valid_weapon_type))
return // We only care about modifying blades
dropped_item.force = initial(dropped_item.force)
dropped_item.wound_bonus = initial(dropped_item.wound_bonus)
dropped_item.exposed_wound_bonus = initial(dropped_item.exposed_wound_bonus)
dropped_item.armour_penetration = initial(dropped_item.armour_penetration)
UnregisterSignal(dropped_item, COMSIG_SEND_ITEM_ATTACK_MESSAGE_OBJECT)

View File

@@ -2,14 +2,19 @@
name = "labyrinth pages"
desc = "A field of papers flying in the air, repulsing heathens with impossible force."
icon_state = "lintel"
initial_duration = 8 SECONDS
initial_duration = 15 SECONDS
/obj/effect/forcefield/wizard/heretic/CanAllowThrough(atom/movable/mover, border_dir)
if(istype(mover.throwing?.get_thrower(), /obj/effect/forcefield/wizard/heretic))
return TRUE
return ..()
/obj/effect/forcefield/wizard/heretic/Bumped(mob/living/bumpee)
. = ..()
if(!istype(bumpee) || IS_HERETIC_OR_MONSTER(bumpee))
return
var/throwtarget = get_edge_target_turf(loc, get_dir(loc, get_step_away(bumpee, loc)))
bumpee.safe_throw_at(throwtarget, 10, 1, force = MOVE_FORCE_EXTREMELY_STRONG)
bumpee.safe_throw_at(throwtarget, 10, 10, src, force = MOVE_FORCE_EXTREMELY_STRONG)
visible_message(span_danger("[src] repulses [bumpee] in a storm of paper!"))
///A heretic item that spawns a barrier at the clicked turf, 3 uses
@@ -31,15 +36,21 @@
pickup_sound = 'sound/items/handling/book_pickup.ogg'
///what type of barrier do we spawn when used
var/barrier_type = /obj/effect/forcefield/wizard/heretic
///how many uses do we have left
var/uses = 3
/// Current charges remaining
var/charges = 5
/// Max possible amount of charges
var/max_charges = 5
/// List that contains each timer for the charge
var/list/charge_timers = list()
/// How long before a charge is restored
var/charge_time = 15 SECONDS
/obj/item/heretic_labyrinth_handbook/examine(mob/user)
. = ..()
if(!IS_HERETIC_OR_MONSTER(user))
return
. += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.")
. += span_hypnophrase("It has <b>[uses]</b> uses left.")
. += span_notice("It has <b>[charges]</b> charge\s remaining.")
/obj/item/heretic_labyrinth_handbook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION))
@@ -56,6 +67,10 @@
human_user.dropItemToGround(src)
return ITEM_INTERACT_BLOCKING
if(charges <= 0)
balloon_alert(user, "no charges!")
return ITEM_INTERACT_BLOCKING
var/turf/turf_target = get_turf(interacting_with)
if(locate(barrier_type) in turf_target)
user.balloon_alert(user, "already occupied!")
@@ -64,8 +79,9 @@
new /obj/effect/temp_visual/paper_scatter(turf_target)
playsound(turf_target, 'sound/effects/magic/smoke.ogg', 30)
new barrier_type(turf_target, user)
uses--
if(uses <= 0)
to_chat(user, span_warning("[src] falls apart, turning into ash and dust!"))
qdel(src)
charges--
charge_timers.Add(addtimer(CALLBACK(src, PROC_REF(recharge)), charge_time, TIMER_STOPPABLE))
return ITEM_INTERACT_SUCCESS
/obj/item/heretic_labyrinth_handbook/proc/recharge()
charges = min(charges+1, max_charges)

View File

@@ -4,9 +4,10 @@
desc = "A mask created from suffering. When you look into its eyes, it looks back."
icon_state = "mad_mask"
inhand_icon_state = null
clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH | PEPPERPROOF
resistance_flags = LAVA_PROOF | FIRE_PROOF
w_class = WEIGHT_CLASS_SMALL
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
///Who is wearing this
var/mob/living/carbon/human/local_user

View File

@@ -67,7 +67,7 @@
to_chat(wearer, span_warning("Laughter echoes in your mind...."))
wearer.adjustOrganLoss(ORGAN_SLOT_BRAIN, 40)
wearer.dropItemToGround(src, TRUE)
wearer.gain_trauma(pick(brain_traumas) ,TRAUMA_RESILIENCE_ABSOLUTE)
wearer.gain_trauma(pick(brain_traumas), TRAUMA_RESILIENCE_MAGIC)
/obj/item/storage/belt/unfathomable_curio/examine(mob/living/carbon/user)
. = ..()

View File

@@ -1,199 +1,387 @@
//Global typecache of all heretic knowledges -> instantiate the tree columns -> make them link themselves -> replace the old heretic stuff
//heretic research tree is a directional graph so we can use some basic graph stuff to make internally handling it easier
GLOBAL_LIST(heretic_research_tree)
//HKT = Heretic Knowledge Tree (Heretic Research Tree :3) these objects really only exist for a short period of time at startup and then get deleted
/datum/heretic_knowledge_tree_column
///Route that symbolizes what path this is
var/route
///Used to determine if this is a side path or a main path
var/abstract_parent_type = /datum/heretic_knowledge_tree_column
///IDs od neighbours (to left and right)
var/neighbour_type_left
var/neighbour_type_right
///Tier1 knowledge (or knowledges)
var/tier1
///Tier2 knowledge (or knowledges)
var/tier2
///Tier3 knowledge (or knowledges)
var/tier3
///UI background
var/ui_bgr = "node_side"
/datum/heretic_knowledge_tree_column/main
abstract_parent_type = /datum/heretic_knowledge_tree_column/main
///Starting knowledge - first thing you pick
var/start
///Grasp upgrade
var/grasp
///Mark upgrade
var/mark
///Unique ritual of knoweldge
var/ritual_of_knowledge
///Path specific unique ability
var/unique_ability
///Blade upgrade
var/blade
///Ascension
var/ascension
/proc/generate_heretic_research_tree()
var/list/heretic_research_tree = list()
//Initialize the data structure
for(var/type in subtypesof(/datum/heretic_knowledge))
heretic_research_tree[type] = list()
heretic_research_tree[type][HKT_NEXT] = list()
heretic_research_tree[type][HKT_BAN] = list()
heretic_research_tree[type][HKT_DEPTH] = 1
heretic_research_tree[type][HKT_UI_BGR] = "node_side"
var/datum/heretic_knowledge/knowledge = type
if(initial(knowledge.is_starting_knowledge))
heretic_research_tree[type][HKT_ROUTE] = PATH_START
continue
heretic_research_tree[type][HKT_ROUTE] = null
/// Assoc list of heretic_route.path string -> list of knowledges in that path, see generate_heretic_path() in code/modules/antagonists/heretic/knowledge/_heretic_paths.dm
GLOBAL_LIST(heretic_path_knowledges)
GLOBAL_LIST_INIT(heretic_path_datums, init_heretic_path_datums())
/proc/init_heretic_path_datums()
var/list/paths = list()
for(var/type in subtypesof(/datum/heretic_knowledge_tree_column))
var/datum/heretic_knowledge_tree_column/column_path = type
for(var/datum/heretic_knowledge_tree_column/column_path as anything in subtypesof(/datum/heretic_knowledge_tree_column))
if(initial(column_path.abstract_parent_type) == column_path)
continue
var/datum/heretic_knowledge_tree_column/heretic_route = new column_path()
paths[heretic_route.route] += heretic_route
return paths
var/datum/heretic_knowledge_tree_column/column = new type()
paths[column.type] = column
/datum/heretic_knowledge_tree_column
///Route that symbolizes what path this is, MUST be unique between paths
var/route = PATH_START
var/icon_state = "dark_blade"
/*
* Complexity grades:
* Easy = COLOR_GREEN
* Medium = COLOR_YELLOW
* Hard = COLOR_RED
*/
var/complexity = "Insane"
var/complexity_color = COLOR_WHITE
var/list/icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "dark_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
var/list/description = list("A heretic knowledge tree column, used to define a path of knowledge.")
var/list/pros = list("Is bad", "Is very bad", "Is extremely bad")
var/list/cons = list("Smells bad", "Looks bad", "Tastes bad")
var/list/tips = list("Don't use it", "Don't touch it", "Don't look at it")
///Used to determine if this is a side path or a main path
var/abstract_parent_type = /datum/heretic_knowledge_tree_column
///UI background
var/ui_bgr = BGR_SIDE
var/list/start_blacklist = list()
var/list/grasp_blacklist = list()
var/list/mark_blacklist = list()
var/list/blade_blacklist = list()
var/list/asc_blacklist = list()
//-- Knowledge in order of unlocking
///Starting knowledge - first thing you pick. Gives you access to blades, grasp, mark and passive
var/datum/heretic_knowledge/limited_amount/starting/start
///Tier1 knowledge
var/knowledge_tier1
///Tier2 knowledge
var/knowledge_tier2
///Path-Specific Heretic robes
var/robes
///Tier3 knowledge
var/knowledge_tier3
///Blade upgrade
var/blade
///Tier4 knowledge
var/knowledge_tier4
///Ascension
var/ascension
// Drafting system, if a path has any side-knowledge that is guaranteed to be one of the options
/// Knowledge guaranteed to show up in the first draft
var/guaranteed_side_tier1
/// Knowledge guaranteed to show up in the second draft
var/guaranteed_side_tier2
/// Knowledge guaranteed to show up in the third draft
var/guaranteed_side_tier3
for(var/id in paths)
if(!istype(paths[id],/datum/heretic_knowledge_tree_column/main))
continue
var/datum/heretic_knowledge_tree_column/main/column = paths[id]
start_blacklist += column.start
grasp_blacklist += column.grasp
mark_blacklist += column.mark
blade_blacklist += column.blade
asc_blacklist += column.ascension
/datum/heretic_knowledge_tree_column/proc/get_ui_data(datum/antagonist/heretic/our_heretic, category)
var/list/power_info = our_heretic.heretic_shops[category]
var/list/data = list(
"route" = route,
"icon" = icon.Copy(),
"complexity" = complexity,
"complexity_color" = complexity_color,
"description" = description.Copy(),
"pros" = pros.Copy(),
"cons" = cons.Copy(),
"tips" = tips.Copy(),
"starting_knowledge" = our_heretic.get_knowledge_data(start, power_info),
)
heretic_research_tree[/datum/heretic_knowledge/spell/basic][HKT_NEXT] += start_blacklist
data["preview_abilities"] = list(
our_heretic.get_knowledge_data(knowledge_tier1, power_info, category = category),
our_heretic.get_knowledge_data(knowledge_tier2, power_info, category = category),
our_heretic.get_knowledge_data(knowledge_tier3, power_info, category = category),
our_heretic.get_knowledge_data(knowledge_tier4, power_info, category = category),
)
for(var/id in paths)
var/datum/heretic_knowledge_tree_column/this_column = paths[id]
var/datum/heretic_knowledge_tree_column/neighbour_0 = paths[this_column.neighbour_type_left]
var/datum/heretic_knowledge_tree_column/neighbour_1 = paths[this_column.neighbour_type_right]
//horizontal (two way)
var/list/tier1 = this_column.tier1
var/list/tier2 = this_column.tier2
var/list/tier3 = this_column.tier3
var/datum/status_effect/heretic_passive/passive = new start.eldritch_passive()
data["passive"] = list(
"name" = initial(passive.name),
"description" = passive.passive_descriptions.Copy(),
)
qdel(passive)
//Tier1, 2 and 3 can technically be lists so we handle them here
if(!islist(this_column.tier1))
tier1 = list(this_column.tier1)
return data
if(!islist(this_column.tier2))
tier2 = list(this_column.tier2)
if(!islist(this_column.tier3))
tier3 = list(this_column.tier3)
/**
* Modifies the 2 lists provided in the arguments and sets it up so the heretic can actually start researching stuff.
* Specifically generates the tier 1-4 knowledges + start ones for each path as well for the preview (should probably be moved to use the actual list of per-path researches)
* Importantly, this adds HKT_NEXT's for the starting knowledges so the heretic's next researches are considered valid
**/
/proc/generate_heretic_starting_knowledge(list/starting_knowledges = list())
for(var/knowledge in GLOB.heretic_start_knowledge)
starting_knowledges[knowledge] = make_knowledge_entry(knowledge, null, HERETIC_KNOWLEDGE_START)
for(var/t1_knowledge in tier1)
heretic_research_tree[t1_knowledge][HKT_NEXT] += neighbour_0.tier1
heretic_research_tree[t1_knowledge][HKT_NEXT] += neighbour_1.tier1
heretic_research_tree[t1_knowledge][HKT_ROUTE] = this_column.route
heretic_research_tree[t1_knowledge][HKT_UI_BGR] = this_column.ui_bgr
heretic_research_tree[t1_knowledge][HKT_DEPTH] = 4
var/list/start_knowledges = list()
var/list/start_knowledge_ids = list()
for(var/route in GLOB.heretic_path_datums)
var/datum/heretic_knowledge_tree_column/column_path = GLOB.heretic_path_datums[route]
var/start_knowledge = column_path::start
// why aren't the tiered knowledges in a list?!?!? (initial() probably)
var/t1_knowledge = column_path::knowledge_tier1
var/t2_knowledge = column_path::knowledge_tier2
var/t3_knowledge = column_path::knowledge_tier3
var/t4_knowledge = column_path::knowledge_tier4
starting_knowledges[start_knowledge] = make_knowledge_entry(start_knowledge, column_path, HERETIC_KNOWLEDGE_START, HKT_DEPTH_START)
starting_knowledges[t1_knowledge] = make_knowledge_entry(t1_knowledge, column_path, HERETIC_KNOWLEDGE_START, HKT_DEPTH_TIER_1)
starting_knowledges[t2_knowledge] = make_knowledge_entry(t2_knowledge, column_path, HERETIC_KNOWLEDGE_START, HKT_DEPTH_TIER_2)
starting_knowledges[t3_knowledge] = make_knowledge_entry(t3_knowledge, column_path, HERETIC_KNOWLEDGE_START, HKT_DEPTH_TIER_3)
starting_knowledges[t4_knowledge] = make_knowledge_entry(t4_knowledge, column_path, HERETIC_KNOWLEDGE_START, HKT_DEPTH_TIER_4)
// start the HKT_NEXT chain here
starting_knowledges[/datum/heretic_knowledge/spell/basic][HKT_NEXT] += starting_knowledges[start_knowledge][HKT_ID]
// notably, the heretic's tree isn't yet generated so we have to generate the ID here instead of fetching it, hopefully this doesn't break
starting_knowledges[start_knowledge][HKT_NEXT] += make_knowledge_id(t1_knowledge, HERETIC_KNOWLEDGE_TREE)
start_knowledges += start_knowledge
start_knowledge_ids += starting_knowledges[start_knowledge][HKT_ID]
for(var/t2_knowledge in tier2)
heretic_research_tree[t2_knowledge][HKT_NEXT] += neighbour_0.tier2
heretic_research_tree[t2_knowledge][HKT_NEXT] += neighbour_1.tier2
heretic_research_tree[t2_knowledge][HKT_ROUTE] = this_column.route
heretic_research_tree[t2_knowledge][HKT_UI_BGR] = this_column.ui_bgr
heretic_research_tree[t2_knowledge][HKT_DEPTH] = 8
// make sure to prevent starting on other paths
for(var/knowledge_path in start_knowledges)
var/list/target_knowledge = starting_knowledges[knowledge_path]
target_knowledge[HKT_BAN] += start_knowledge_ids - target_knowledge[HKT_ID]
for(var/t3_knowledge in tier3)
heretic_research_tree[t3_knowledge][HKT_NEXT] += neighbour_0.tier3
heretic_research_tree[t3_knowledge][HKT_NEXT] += neighbour_1.tier3
heretic_research_tree[t3_knowledge][HKT_ROUTE] = this_column.route
heretic_research_tree[t3_knowledge][HKT_UI_BGR] = this_column.ui_bgr
heretic_research_tree[t3_knowledge][HKT_DEPTH] = 10
//TODO: use this to generate the globallist
/datum/antagonist/heretic/proc/generate_heretic_research_tree()
if(!heretic_path)
stack_trace("somehow called generate_heretic_research_tree with a falsey heretic_path")
return
if(!length(GLOB.heretic_path_knowledges))
GLOB.heretic_path_knowledges = generate_global_heretic_tree()
var/list/selected_route = GLOB.heretic_path_knowledges[heretic_path.route]
if(!selected_route)
stack_trace("called generate_heretic_research_tree with a invalid heretic_path.route")
return
heretic_shops[HERETIC_KNOWLEDGE_TREE] = deep_copy_list_alt(selected_route)
//Everything below this line is considered to be a "main path" and not a side path
//Since we are handling the heretic research tree column by column this is required
if(this_column.abstract_parent_type != /datum/heretic_knowledge_tree_column/main)
continue
var/datum/heretic_knowledge_tree_column/main/main_column = this_column
//vertical (one way)
heretic_research_tree[/datum/heretic_knowledge/spell/basic] += main_column.start
heretic_research_tree[main_column.start][HKT_NEXT] += main_column.grasp
heretic_research_tree[main_column.grasp][HKT_NEXT] += main_column.tier1
//t1 handling
for(var/t1_knowledge in tier1)
heretic_research_tree[t1_knowledge][HKT_NEXT] += main_column.mark
heretic_research_tree[main_column.mark][HKT_NEXT] += main_column.ritual_of_knowledge
heretic_research_tree[main_column.ritual_of_knowledge][HKT_NEXT] += main_column.unique_ability
heretic_research_tree[main_column.unique_ability][HKT_NEXT] += main_column.tier2
//t2 handling
for(var/t2_knowledge in tier2)
heretic_research_tree[t2_knowledge][HKT_NEXT] += main_column.blade
heretic_research_tree[main_column.blade][HKT_NEXT] += main_column.tier3
//t3 handling
for(var/t3_knowledge in tier3)
heretic_research_tree[t3_knowledge][HKT_NEXT] += main_column.ascension
//blacklist
heretic_research_tree[main_column.start][HKT_BAN] += (start_blacklist - main_column.start) + (asc_blacklist - main_column.ascension)
heretic_research_tree[main_column.grasp][HKT_BAN] += (grasp_blacklist - main_column.grasp)
heretic_research_tree[main_column.mark][HKT_BAN] += (mark_blacklist - main_column.mark)
heretic_research_tree[main_column.blade][HKT_BAN] += (blade_blacklist - main_column.blade)
//route stuff
heretic_research_tree[main_column.start][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.grasp][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.mark][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.ritual_of_knowledge][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.unique_ability][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.blade][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.ascension][HKT_ROUTE] = main_column.route
heretic_research_tree[main_column.start][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.grasp][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.mark][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.ritual_of_knowledge][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.unique_ability][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.blade][HKT_UI_BGR] = main_column.ui_bgr
heretic_research_tree[main_column.ascension][HKT_UI_BGR] = main_column.ui_bgr
//depth stuff
heretic_research_tree[main_column.start][HKT_DEPTH] = 2
heretic_research_tree[main_column.grasp][HKT_DEPTH] = 3
heretic_research_tree[main_column.mark][HKT_DEPTH] = 5
heretic_research_tree[main_column.ritual_of_knowledge][HKT_DEPTH] = 6
heretic_research_tree[main_column.unique_ability][HKT_DEPTH] = 7
heretic_research_tree[main_column.blade][HKT_DEPTH] = 9
heretic_research_tree[main_column.ascension][HKT_DEPTH] = 11
//Per path bullshit goes here \/\/\/
for(var/t2_knowledge in tier2)
heretic_research_tree[t2_knowledge][HKT_NEXT] += /datum/heretic_knowledge/reroll_targets
// If you want to do any custom bullshit put it here \/\/\/
heretic_research_tree[/datum/heretic_knowledge/reroll_targets][HKT_ROUTE] = PATH_SIDE
heretic_research_tree[/datum/heretic_knowledge/reroll_targets][HKT_DEPTH] = 8
heretic_research_tree[/datum/heretic_knowledge/rifle][HKT_NEXT] += /datum/heretic_knowledge/rifle_ammo
heretic_research_tree[/datum/heretic_knowledge/rifle_ammo][HKT_ROUTE] = PATH_SIDE
heretic_research_tree[/datum/heretic_knowledge/rifle_ammo][HKT_DEPTH] = heretic_research_tree[/datum/heretic_knowledge/rifle][HKT_DEPTH]
//and we're done
QDEL_LIST_ASSOC_VAL(paths)
/proc/generate_global_heretic_tree()
var/heretic_research_tree = list()
for(var/path in GLOB.heretic_path_datums)
var/datum/heretic_knowledge_tree_column/heretic_route = GLOB.heretic_path_datums[path]
heretic_research_tree[path] = generate_heretic_path(heretic_route)
if(!length(heretic_research_tree))
CRASH("Somehow generated an empty heretic research tree, this should never happen.")
return heretic_research_tree
/proc/make_knowledge_entry(datum/heretic_knowledge/knowledge, datum/heretic_knowledge_tree_column/path, category = HERETIC_KNOWLEDGE_TREE, depth = 1, cost = -1)
return list(
HKT_NEXT = list(),
HKT_BAN = list(),
HKT_DEPTH = depth,
HKT_PURCHASED_DEPTH = 0,
HKT_UI_BGR = path ? path::ui_bgr : BGR_SIDE,
HKT_COST = cost != -1 ? cost : knowledge::cost,
HKT_ROUTE = path ? path::route : null,
HKT_CATEGORY = category,
HKT_ID = make_knowledge_id(knowledge, category),
)
/// ID's are not unique, the same knowledge with the same type in the same shop will always have the same ID.
/proc/make_knowledge_id(datum/heretic_knowledge/knowledge, shop_category = HERETIC_KNOWLEDGE_TREE)
var/type_string = replacetext("[knowledge::type]", "/", "", 1, 2)
var/our_type = replacetext(type_string, "/", "_")
return "[shop_category]/[our_type]"
/proc/generate_heretic_path(datum/heretic_knowledge_tree_column/heretic_path)
var/list/heretic_research_tree = list()
//Initialize the data structure
var/list/tree_paths = list()
tree_paths += list(
heretic_path.knowledge_tier1,
heretic_path.knowledge_tier2,
heretic_path.knowledge_tier3,
heretic_path.knowledge_tier4,
heretic_path.robes,
heretic_path.blade,
heretic_path.ascension,
)
for(var/datum/heretic_knowledge/type as anything in tree_paths)
heretic_research_tree[type] = make_knowledge_entry(type, heretic_path, depth = 1)
var/knowledge_tier1 = heretic_path.knowledge_tier1
var/knowledge_tier2 = heretic_path.knowledge_tier2
var/knowledge_tier3 = heretic_path.knowledge_tier3
var/knowledge_tier4 = heretic_path.knowledge_tier4
//horizontal (two way)
heretic_research_tree[knowledge_tier1][HKT_DEPTH] = HKT_DEPTH_TIER_1
heretic_research_tree[knowledge_tier1][HKT_NEXT] += heretic_research_tree[knowledge_tier2][HKT_ID]
heretic_research_tree[knowledge_tier2][HKT_DEPTH] = HKT_DEPTH_TIER_2
heretic_research_tree[knowledge_tier2][HKT_NEXT] += heretic_research_tree[heretic_path.robes][HKT_ID]
heretic_research_tree[knowledge_tier3][HKT_DEPTH] = HKT_DEPTH_TIER_3
heretic_research_tree[knowledge_tier3][HKT_NEXT] += heretic_research_tree[heretic_path.blade][HKT_ID]
heretic_research_tree[heretic_path.robes][HKT_NEXT] += heretic_research_tree[knowledge_tier3][HKT_ID]
heretic_research_tree[knowledge_tier4][HKT_DEPTH] = HKT_DEPTH_TIER_4
heretic_research_tree[heretic_path.blade][HKT_NEXT] += heretic_research_tree[knowledge_tier4][HKT_ID]
heretic_research_tree[knowledge_tier4][HKT_NEXT] += heretic_research_tree[heretic_path.ascension][HKT_ID]
//depth stuff
heretic_research_tree[heretic_path.robes][HKT_DEPTH] = HKT_DEPTH_ROBES
heretic_research_tree[heretic_path.blade][HKT_DEPTH] = HKT_DEPTH_ARMOR
heretic_research_tree[heretic_path.ascension][HKT_DEPTH] = HKT_DEPTH_ASCENSION
//and we're done
return heretic_research_tree
/**
* Each heretic has a few drafted knowledges within their heretic knowledge tree.
* This is not during the knowledge tree creation because we want to know what path our heretic picks so we filter out dupe knowledges.
* Also generates shop knowledges as their validation is shared.
* Modifies shop_list and final_draft that are provided in the arguments.
*/
/proc/determine_drafted_knowledge(route, list/tree = list(), list/shop = list(), list/final_draft = list())
if(!route)
stack_trace("somehow called determine_drafted_knowledge with a falsey current_path")
return
var/list/heretic_research_tree = tree
var/datum/heretic_knowledge_tree_column/heretic_path = GLOB.heretic_path_datums[route]
/// costs by index mapped to depth
var/list/shop_costs = list(1, 2, 2, 2, 3)
// Relevant variables that we pull from the path
var/knowledge_tier1 = heretic_path.knowledge_tier1
var/knowledge_tier2 = heretic_path.knowledge_tier2
var/knowledge_tier3 = heretic_path.knowledge_tier3
var/knowledge_tier4 = heretic_path.knowledge_tier4
var/list/path_knowledges = list(
knowledge_tier1,
knowledge_tier2,
knowledge_tier3,
knowledge_tier4,
)
// Every path can have a guaranteed option that will show up in the first 3 drafts (Otherwise we just run as normal)
var/datum/heretic_knowledge/guaranteed_draft_t1 = heretic_path.guaranteed_side_tier1
var/datum/heretic_knowledge/guaranteed_draft_t2 = heretic_path.guaranteed_side_tier2
var/datum/heretic_knowledge/guaranteed_draft_t3 = heretic_path.guaranteed_side_tier3
var/list/guaranteed_drafts = list(
guaranteed_draft_t1,
guaranteed_draft_t2,
guaranteed_draft_t3,
)
var/list/shop_unlock_order = list(
knowledge_tier1,
knowledge_tier2,
heretic_path.robes,
knowledge_tier3,
knowledge_tier4,
)
var/list/draft_ineligible = path_knowledges.Copy()
draft_ineligible += guaranteed_drafts
var/list/elligible_knowledge = list()
var/list/shop_knowledge = list()
for(var/tier in 1 to HERETIC_DRAFT_TIER_MAX)
elligible_knowledge += list(list())
shop_knowledge += list(list())
for(var/datum/heretic_knowledge/potential_type as anything in subtypesof(/datum/heretic_knowledge))
if(potential_type::drafting_tier == 0)
continue
// Don't add the knowledge if it's obtainable later in the path
if(is_path_in_list(potential_type, draft_ineligible))
continue
if(!potential_type::is_shop_only)
elligible_knowledge[potential_type::drafting_tier] += potential_type
shop_knowledge[potential_type::drafting_tier] += potential_type
var/list/drafts = list(
list(
"parent_knowledge" = knowledge_tier1,
"guaranteed_knowledge" = guaranteed_draft_t1,
"probabilities" = list("1" = 50, "2" = 50, "3" = 0, "4" = 0, "5" = 0),
HKT_DEPTH = HKT_DEPTH_DRAFT_1,
),
list(
"parent_knowledge" = knowledge_tier2,
"guaranteed_knowledge" = guaranteed_draft_t2,
"probabilities" = list("1" = 50, "2" = 25, "3" = 25, "4" = 0, "5" = 0),
HKT_DEPTH = HKT_DEPTH_DRAFT_2,
),
list(
"parent_knowledge" = knowledge_tier3,
"guaranteed_knowledge" = guaranteed_draft_t3,
"probabilities" = list("1" = 20, "2" = 20, "3" = 20, "4" = 20, "5" = 20),
HKT_DEPTH = HKT_DEPTH_DRAFT_3,
),
list(
"parent_knowledge" = knowledge_tier4,
"probabilities" = list("1" = 0, "2" = 0, "3" = 0, "4" = 0, "5" = 100),
HKT_DEPTH = HKT_DEPTH_DRAFT_4,
)
)
/// generate 3 drafts for each draft tier, while banning you from picking multiple drafts
for(var/draft in drafts)
var/parent_knowledge_path = draft["parent_knowledge"]
var/datum/heretic_knowledge/guaranteed_draft = draft["guaranteed_knowledge"]
var/list/probabilities = draft["probabilities"]
var/depth = draft[HKT_DEPTH]
var/list/draft_blacklist = list()
for(var/cycle in 1 to 3)
var/datum/heretic_knowledge/selected_knowledge
if(guaranteed_draft && cycle == 1)
selected_knowledge = guaranteed_draft
var/shop_tier = shop_knowledge[guaranteed_draft::drafting_tier]
if(shop_tier && !(guaranteed_draft in shop_tier))
shop_tier += guaranteed_draft
else
// rng kinda not correct but like, whatever
var/chosen_tier = min(text2num(pick_weight(probabilities)), length(elligible_knowledge))
var/list/picked_tier = elligible_knowledge[chosen_tier]
selected_knowledge = pick_n_take(picked_tier)
if(!length(picked_tier))
elligible_knowledge.Cut(chosen_tier, chosen_tier + 1)
if(isnull(selected_knowledge))
stack_trace("Failed to select a knowledge for heretic path [heretic_path] at depth [depth]. This should never happen.")
continue
final_draft[selected_knowledge] = make_knowledge_entry(
selected_knowledge,
null,
HERETIC_KNOWLEDGE_DRAFT,
depth,
0,
)
final_draft[selected_knowledge][HKT_PURCHASED_DEPTH] = selected_knowledge::drafting_tier
var/draft_id = final_draft[selected_knowledge][HKT_ID]
draft_blacklist[selected_knowledge] = draft_id
heretic_research_tree[parent_knowledge_path][HKT_NEXT] |= draft_id
var/list/blacklist_ids = assoc_to_values(draft_blacklist)
for(var/blacklist_path in draft_blacklist)
var/id = draft_blacklist[blacklist_path]
final_draft[blacklist_path][HKT_BAN] += (blacklist_ids - id)
// all possible drafts are added to the shop, this time with costs
for(var/drafting_tier in 1 to length(shop_knowledge))
var/unlocked_by = shop_unlock_order[drafting_tier]
var/list/eligible_tier = shop_knowledge[drafting_tier]
for(var/knowledge_type in eligible_tier)
shop[knowledge_type] = make_knowledge_entry(
knowledge_type,
null,
HERETIC_KNOWLEDGE_SHOP,
drafting_tier,
shop_costs[drafting_tier],
)
var/shop_id = shop[knowledge_type][HKT_ID]
heretic_research_tree[unlocked_by][HKT_NEXT] |= shop_id
// ban the corresponding same knowledge from the final draft to prevent duplicates
var/found = final_draft[knowledge_type]
if(!found)
continue
found[HKT_BAN] |= shop_id
var/gun_path = /datum/heretic_knowledge/rifle
var/ammo_path = /datum/heretic_knowledge/rifle_ammo
shop[ammo_path] = make_knowledge_entry(ammo_path, null, HERETIC_KNOWLEDGE_SHOP, 2)
var/ammo_id = shop[ammo_path][HKT_ID]
shop[gun_path][HKT_NEXT] |= ammo_id
var/already_in = final_draft[gun_path]
if(already_in)
already_in[HKT_NEXT] |= ammo_id

View File

@@ -1,19 +1,50 @@
/datum/heretic_knowledge_tree_column/main/ash
neighbour_type_left = /datum/heretic_knowledge_tree_column/cosmic_to_ash
neighbour_type_right = /datum/heretic_knowledge_tree_column/ash_to_moon
/datum/heretic_knowledge_tree_column/ash
route = PATH_ASH
ui_bgr = "node_ash"
complexity = "Easy"
complexity_color = COLOR_GREEN
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "ash_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Ash revolves around fire, mobility and brutal crowd control against single opponents.",
"Play this path if you are new to Heretic, or really enjoy hit and run playstyles.",
)
pros = list(
"Very potent even from the beginning of the path.",
"Easy access to a mobility spells and expanded vision.",
"Very powerful mark effect.",
)
cons = list(
"Has less power than most heretics beyond their starting abilities.",
"Lacks durability in long conflicts.",
"Reliant on hitting fast and hard before their opponents can mount proper countermeasures.",
)
tips = list(
"Your Mansus Grasp applies a short blind and a mark that puts your opponent into stamina crit when triggered by your blade. The mark can spread to nearby opponents.",
"Selecting this path makes you immune to high temperature damage. Remember, however, that your clothes can still burn! If you want to protect yourself from your own fire, wear a Scorched Mantle.",
"Your Scorched Mantle will cause you to generate firestacks on your own body (Make sure you toggle the effect!). Upon reaching 5 fire stacks, your ashen spells will be empowered (indicated by your spells being highlighted in green).",
"Your Ashen passage is a short cooldown jaunt capable of removing restraints. If empowered, it gains a longer jaunt time, and also will remove stuns and stamina crit.",
"Volcano blast can make short work of your enemies, should they be foolish enough to stick close to each other. If empowered, it will have no cast time and generate twice the amount of firestacks. Burn the heathens to ashes!",
"Do not neglect the Mask of Madness. It will slowly sap the stamina of your enemies and make them hallucinate.",
"Make sure to set as many enemies on fire as you possibly can! Nightwatcher's Rebirth will heal you and have its cooldown reduced based on how many mobs you siphon.",
"Your ascension grants you complete immunity to environmental hazards, including bombs! But you are still vulnerable to more conventional weaponry. Do not become overconfident.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_ash
grasp = /datum/heretic_knowledge/ashen_grasp
tier1 = /datum/heretic_knowledge/spell/ash_passage
mark = /datum/heretic_knowledge/mark/ash_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/ash
unique_ability = /datum/heretic_knowledge/spell/fire_blast
tier2 = /datum/heretic_knowledge/mad_mask
knowledge_tier1 = /datum/heretic_knowledge/spell/ash_passage
guaranteed_side_tier1 = /datum/heretic_knowledge/medallion
knowledge_tier2 = /datum/heretic_knowledge/spell/fire_blast
guaranteed_side_tier2 = /datum/heretic_knowledge/rifle
robes = /datum/heretic_knowledge/armor/ash
knowledge_tier3 = /datum/heretic_knowledge/mad_mask
guaranteed_side_tier3 = /datum/heretic_knowledge/summon/ashy
blade = /datum/heretic_knowledge/blade_upgrade/ash
tier3 = /datum/heretic_knowledge/spell/flame_birth
knowledge_tier4 = /datum/heretic_knowledge/spell/flame_birth
ascension = /datum/heretic_knowledge/ultimate/ash_final
/datum/heretic_knowledge/limited_amount/starting/base_ash
@@ -29,24 +60,11 @@
result_atoms = list(/obj/item/melee/sickly_blade/ash)
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "ash_blade"
mark_type = /datum/status_effect/eldritch/ash
eldritch_passive = /datum/status_effect/heretic_passive/ash
/datum/heretic_knowledge/ashen_grasp
name = "Grasp of Ash"
desc = "Your Mansus Grasp will burn the eyes of the victim, damaging them and blurring their vision."
gain_text = "The Nightwatcher was the first of them, his treason started it all. \
Their lantern, expired to ash - their watch, absent."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_ash"
/datum/heretic_knowledge/ashen_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/ashen_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/ashen_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_ash/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
if(target.is_blind())
return
@@ -58,27 +76,7 @@
target.adjustOrganLoss(ORGAN_SLOT_EYES, 15)
target.set_eye_blur_if_lower(20 SECONDS)
/datum/heretic_knowledge/spell/ash_passage
name = "Ashen Passage"
desc = "Grants you Ashen Passage, a spell that lets you phase out of reality and traverse a short distance, passing though any walls."
gain_text = "He knew how to walk between the planes."
action_to_add = /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash
cost = 1
/datum/heretic_knowledge/mark/ash_mark
name = "Mark of Ash"
desc = "Your Mansus Grasp now applies the Mark of Ash. The mark is triggered from an attack with your Ashen Blade. \
When triggered, the victim takes additional stamina and burn damage, and the mark is transferred to a nearby heathen. \
Damage dealt is decreased with each transfer. \
Triggering the mark will also greatly reduce the cooldown of your Mansus Grasp."
gain_text = "He was a very particular man, always watching in the dead of night. \
But in spite of his duty, he regularly tranced through the Manse with his blazing lantern held high. \
He shone brightly in the darkness, until the blaze begin to die."
mark_type = /datum/status_effect/eldritch/ash
/datum/heretic_knowledge/mark/ash_mark/trigger_mark(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/base_ash/trigger_mark(mob/living/source, mob/living/target)
. = ..()
if(!.)
return
@@ -89,20 +87,41 @@
grasp.next_use_time -= round(grasp.cooldown_time*0.75)
grasp.build_all_button_icons()
/datum/heretic_knowledge/knowledge_ritual/ash
/datum/heretic_knowledge/spell/ash_passage
name = "Ashen Passage"
desc = "Grants you Ashen Passage, a spell that lets you phase out of reality, allowing you to traverse a short distance, passing though any walls. \
When empowered, it will break you out of any stuns and restraints, and will have a longer range."
gain_text = "He knew how to walk between the planes."
action_to_add = /datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/spell/fire_blast
name = "Volcano Blast"
desc = "Grants you Volcano Blast, a spell that - after a short charge - fires off a beam of energy \
at a nearby enemy, setting them on fire and burning them. If they do not extinguish themselves, \
the beam will continue to another target."
the beam will continue to another target. \
When empowered, has instant cast time and blasts enemies with more flames."
gain_text = "No fire was hot enough to rekindle them. No fire was bright enough to save them. No fire is eternal."
action_to_add = /datum/action/cooldown/spell/charged/beam/fire_blast
cost = 1
cost = 2
research_tree_icon_frame = 7
/datum/heretic_knowledge/armor/ash
desc = "Allows you to transmute a table (or a suit), a mask and a match to create a scorched mantle. \
It provides completes protection from fire, and is able to produce more flames passively. \
When you have enough fire, you may cast empowered versions of your ashen spells. \
Acts as a focus while hooded."
gain_text = "The Watch remain as they fell, crumbling away from sight. \
Yet the winds blowing through the city call them back to service, dust kicked into the air, a drifting silhouette of the fallen."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/ash)
research_tree_icon_state = "ash_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/item/match = 1,
)
/datum/heretic_knowledge/mad_mask
name = "Mask of Madness"
@@ -117,7 +136,7 @@
/obj/item/flashlight/flare/candle = 4,
)
result_atoms = list(/obj/item/clothing/mask/madness_mask)
cost = 1
cost = 2
research_tree_icon_path = 'icons/obj/clothing/masks.dmi'
research_tree_icon_state = "mad_mask"
@@ -146,8 +165,9 @@
gain_text = "The fire was inescapable, and yet, life remained in his charred body. \
The Nightwatcher was a particular man, always watching."
action_to_add = /datum/action/cooldown/spell/aoe/fiery_rebirth
cost = 1
cost = 2
research_tree_icon_frame = 5
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/ash_final
name = "Ashlord's Rite"

View File

@@ -1,20 +1,53 @@
/datum/heretic_knowledge_tree_column/main/blade
neighbour_type_left = /datum/heretic_knowledge_tree_column/void_to_blade
neighbour_type_right = /datum/heretic_knowledge_tree_column/blade_to_rust
/datum/heretic_knowledge_tree_column/blade
route = PATH_BLADE
ui_bgr = "node_blade"
complexity = "Hard"
complexity_color = COLOR_RED
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "dark_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Blade is as the name suggests.",
"You are highly competent at cutting your opponents to ribbons.",
"Pick this path if you want to fight, and you want to be the best at fighting.",
)
pros = list(
"Capable of blocking incoming attacks, retaliating with a riposte.",
"Rapidly deals damage through dual-wielded blades and channeled strikes.",
"High defense against stuns and knockdowns.",
"Highly lethal combatant in a direct combat with a single opponent.",
)
cons = list(
"Requires a high degree of skill input.",
"Without blades, the path loses most of its fighting power.",
"Lacks mobility options.",
"Lacks environmental protections.",
)
tips = list(
"Your Mansus Grasp will stun your opponent if they are attacked from behind or while they are prone. This also locks them in the room they are in until the mark is detonated. Triggering the mark will grant you a orbiting knife that will protect you from one melee or ranged attack.",
"You have the highest blade cap out of all paths (A total of 4). But since they require silver or titanium to craft, you might be strapped for ingredients if the miners aren't doing their job. If you need materials, shuttle walls and seats are a source of titanium metal, and surgery tables a source of silver.",
"You are highly reliant on approaching opponents in melee. Slips, bolas and beartraps are your worst enemy. You can counteract slips by crafting a pair of Greaves Of The Prophet, or remove restraints with Ashen Passage.",
"Realignment will pull you out of stuns and knockdowns, but also pacifies you for the duration.",
"With Empowered Blades, your offensive power grows considerably. You are able to fight with dual-wielded blades, and can empower them by activating your Mansus Grasp while wielding your blades. Your blades also deal additional damage to objects, silicons and mechs.",
"Maintaining a good offense also creates a good defense. With orbiting blades, you are able to block additional incoming attacks.",
"With Furious Steel, you can not only produce several knives for defensive purposes, but throw them by clicking with an empty hand. This gives you additional ranged power in a pinch.",
"Use Wolves Among Sheep with caution. Not only does it have a significant cooldown, but it also arms anyone trapped in the effect with you with blades of their own. Use it either as a last ditch defense, or when you know you have the upper hand and need an extra edge. Just don't try to flee the area before taking someone out first.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_blade
grasp = /datum/heretic_knowledge/blade_grasp
tier1 = /datum/heretic_knowledge/blade_dance
mark = /datum/heretic_knowledge/mark/blade_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/blade
unique_ability = /datum/heretic_knowledge/spell/realignment
tier2 = /datum/heretic_knowledge/spell/furious_steel
knowledge_tier1 = /datum/heretic_knowledge/spell/realignment
guaranteed_side_tier1 = /datum/heretic_knowledge/greaves_of_the_prophet
knowledge_tier2 = /datum/heretic_knowledge/duel_stance
guaranteed_side_tier2 = /datum/heretic_knowledge/essence
robes = /datum/heretic_knowledge/armor/blade
knowledge_tier3 = /datum/heretic_knowledge/spell/furious_steel
guaranteed_side_tier3 = /datum/heretic_knowledge/rune_carver
blade = /datum/heretic_knowledge/blade_upgrade/blade
tier3 = /datum/heretic_knowledge/spell/wolves_among_sheep
knowledge_tier4 = /datum/heretic_knowledge/spell/wolves_among_sheep
ascension = /datum/heretic_knowledge/ultimate/blade_final
/datum/heretic_knowledge/limited_amount/starting/base_blade
@@ -31,24 +64,11 @@
limit = 4 // It's the blade path, it's a given
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "dark_blade"
mark_type = /datum/status_effect/eldritch/blade
eldritch_passive = /datum/status_effect/heretic_passive/blade
/datum/heretic_knowledge/blade_grasp
name = "Grasp of the Blade"
desc = "Your Mansus Grasp will cause a short stun when used on someone lying down or facing away from you."
gain_text = "The story of the footsoldier has been told since antiquity. It is one of blood and valor, \
and is championed by sword, steel and silver."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_blade"
/datum/heretic_knowledge/blade_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/blade_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/blade_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_blade/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
if(!check_behind(source, target))
return
@@ -59,109 +79,7 @@
target.balloon_alert(source, "backstab!")
playsound(target, 'sound/items/weapons/guillotine.ogg', 100, TRUE)
/// The cooldown duration between triggers of blade dance
#define BLADE_DANCE_COOLDOWN (20 SECONDS)
/datum/heretic_knowledge/blade_dance
name = "Dance of the Brand"
desc = "Being attacked while wielding a Heretic Blade in either hand will deliver a riposte \
towards your attacker. This effect can only trigger once every 20 seconds."
gain_text = "The footsoldier was known to be a fearsome duelist. \
Their general quickly appointed them as their personal Champion."
cost = 1
research_tree_icon_path = 'icons/mob/actions/actions_ecult.dmi'
research_tree_icon_state = "shatter"
/// Whether the counter-attack is ready or not.
/// Used instead of cooldowns, so we can give feedback when it's ready again
var/riposte_ready = TRUE
/datum/heretic_knowledge/blade_dance/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_LIVING_CHECK_BLOCK, PROC_REF(on_shield_reaction))
/datum/heretic_knowledge/blade_dance/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_LIVING_CHECK_BLOCK)
/datum/heretic_knowledge/blade_dance/proc/on_shield_reaction(
mob/living/carbon/human/source,
atom/movable/hitby,
damage = 0,
attack_text = "the attack",
attack_type = MELEE_ATTACK,
armour_penetration = 0,
damage_type = BRUTE,
)
SIGNAL_HANDLER
if(attack_type != MELEE_ATTACK)
return
if(!riposte_ready)
return
if(INCAPACITATED_IGNORING(source, INCAPABLE_GRAB))
return
var/mob/living/attacker = hitby.loc
if(!istype(attacker))
return
if(!source.Adjacent(attacker))
return
// Let's check their held items to see if we can do a riposte
var/obj/item/main_hand = source.get_active_held_item()
var/obj/item/off_hand = source.get_inactive_held_item()
// This is the item that ends up doing the "blocking" (flavor)
var/obj/item/striking_with
// First we'll check if the offhand is valid
if(!QDELETED(off_hand) && istype(off_hand, /obj/item/melee/sickly_blade))
striking_with = off_hand
// Then we'll check the mainhand
// We do mainhand second, because we want to prioritize it over the offhand
if(!QDELETED(main_hand) && istype(main_hand, /obj/item/melee/sickly_blade))
striking_with = main_hand
// No valid item in either slot? No riposte
if(!striking_with)
return
// If we made it here, deliver the strike
INVOKE_ASYNC(src, PROC_REF(counter_attack), source, attacker, striking_with, attack_text)
// And reset after a bit
riposte_ready = FALSE
addtimer(CALLBACK(src, PROC_REF(reset_riposte), source), BLADE_DANCE_COOLDOWN)
/datum/heretic_knowledge/blade_dance/proc/counter_attack(mob/living/carbon/human/source, mob/living/target, obj/item/melee/sickly_blade/weapon, attack_text)
playsound(get_turf(source), 'sound/items/weapons/parry.ogg', 100, TRUE)
source.balloon_alert(source, "riposte used")
source.visible_message(
span_warning("[source] leans into [attack_text] and delivers a sudden riposte back at [target]!"),
span_warning("You lean into [attack_text] and deliver a sudden riposte back at [target]!"),
span_hear("You hear a clink, followed by a stab."),
)
weapon.melee_attack_chain(source, target)
/datum/heretic_knowledge/blade_dance/proc/reset_riposte(mob/living/carbon/human/source)
riposte_ready = TRUE
source.balloon_alert(source, "riposte ready")
#undef BLADE_DANCE_COOLDOWN
/datum/heretic_knowledge/mark/blade_mark
name = "Mark of the Blade"
desc = "Your Mansus Grasp now applies the Mark of the Blade. While marked, \
the victim will be unable to leave their current room until it expires or is triggered. \
Triggering the mark will summon a knife that will orbit you for a short time. \
The knife will block any attack directed towards you, but is consumed on use."
gain_text = "His general wished to end the war, but the Champion knew there could be no life without death. \
He would slay the coward himself, and anyone who tried to run."
mark_type = /datum/status_effect/eldritch/blade
/datum/heretic_knowledge/mark/blade_mark/create_mark(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/base_blade/create_mark(mob/living/source, mob/living/target)
var/datum/status_effect/eldritch/blade/blade_mark = ..()
if(istype(blade_mark))
var/area/to_lock_to = get_area(target)
@@ -169,16 +87,12 @@
to_chat(target, span_hypnophrase("An otherworldly force is compelling you to stay in [get_area_name(to_lock_to)]!"))
return blade_mark
/datum/heretic_knowledge/mark/blade_mark/trigger_mark(mob/living/source, mob/living/target)
/datum/heretic_knowledge/limited_amount/starting/base_blade/trigger_mark(mob/living/source, mob/living/target)
. = ..()
if(!.)
return
source.apply_status_effect(/datum/status_effect/protective_blades, 60 SECONDS, 1, 20, 0 SECONDS)
/datum/heretic_knowledge/knowledge_ritual/blade
/datum/heretic_knowledge/spell/realignment
name = "Realignment"
desc = "Grants you Realignment a spell that wil realign your body rapidly for a short period. \
@@ -186,7 +100,91 @@
This spell can be cast in rapid succession, but doing so will increase the cooldown."
gain_text = "In the flurry of death, he found peace within himself. Despite insurmountable odds, he forged on."
action_to_add = /datum/action/cooldown/spell/realignment
cost = 1
cost = 2
/// The amount of blood flow reduced per level of severity of gained bleeding wounds for Stance of the Torn Champion.
#define BLOOD_FLOW_PER_SEVEIRTY -1
/datum/heretic_knowledge/duel_stance
name = "Stance of the Torn Champion"
desc = "Grants resilience to blood loss from wounds and immunity to having your limbs dismembered. \
Additionally, when damaged below 50% of your maximum health, \
you gain increased resistance to gaining wounds and resistance to slowdown."
gain_text = "In time, it was he who stood alone among the bodies of his former comrades, awash in blood, none of it his own. \
He was without rival, equal, or purpose."
cost = 2
research_tree_icon_path = 'icons/effects/blood.dmi'
research_tree_icon_state = "suitblood"
research_tree_icon_dir = SOUTH
drafting_tier = 5
/// Whether we're currently in duelist stance, gaining certain buffs (low health)
var/in_duelist_stance = FALSE
/datum/heretic_knowledge/duel_stance/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
ADD_TRAIT(user, TRAIT_NODISMEMBER, type)
RegisterSignal(user, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(user, COMSIG_CARBON_GAIN_WOUND, PROC_REF(on_wound_gain))
RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(on_health_update))
on_health_update(user) // Run this once, so if the knowledge is learned while hurt it activates properly
/datum/heretic_knowledge/duel_stance/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
REMOVE_TRAIT(user, TRAIT_NODISMEMBER, type)
if(in_duelist_stance)
user.remove_traits(list(TRAIT_HARDLY_WOUNDED), type)
if(isliving(user))
var/mob/living/living_mob = user
living_mob.remove_movespeed_mod_immunities(type, /datum/movespeed_modifier/damage_slowdown, TRUE)
UnregisterSignal(user, list(COMSIG_ATOM_EXAMINE, COMSIG_CARBON_GAIN_WOUND, COMSIG_LIVING_HEALTH_UPDATE))
/datum/heretic_knowledge/duel_stance/proc/on_examine(mob/living/source, mob/user, list/examine_list)
SIGNAL_HANDLER
var/obj/item/held_item = source.get_active_held_item()
if(in_duelist_stance)
examine_list += span_warning("[source] looks unnaturally poised[held_item?.force >= 15 ? " and ready to strike out":""].")
/datum/heretic_knowledge/duel_stance/proc/on_wound_gain(mob/living/source, datum/wound/gained_wound, obj/item/bodypart/limb)
SIGNAL_HANDLER
if(gained_wound.blood_flow <= 0)
return
gained_wound.adjust_blood_flow(gained_wound.severity * BLOOD_FLOW_PER_SEVEIRTY)
/datum/heretic_knowledge/duel_stance/proc/on_health_update(mob/living/source)
SIGNAL_HANDLER
if(in_duelist_stance && source.health > source.maxHealth * 0.5)
source.balloon_alert(source, "exited duelist stance")
in_duelist_stance = FALSE
source.remove_traits(list(TRAIT_HARDLY_WOUNDED), type)
source.remove_movespeed_mod_immunities(type, /datum/movespeed_modifier/damage_slowdown, TRUE)
return
if(!in_duelist_stance && source.health <= source.maxHealth * 0.5)
source.balloon_alert(source, "entered duelist stance")
in_duelist_stance = TRUE
ADD_TRAIT(source, TRAIT_HARDLY_WOUNDED, type)
source.add_movespeed_mod_immunities(type, /datum/movespeed_modifier/damage_slowdown, TRUE)
return
#undef BLOOD_FLOW_PER_SEVEIRTY
/datum/heretic_knowledge/armor/blade
desc = "Allows you to transmute a table (or a suit), a mask and a sheet of titanium or silver to create a Shattered Panoply. \
Provides baton resistance and shock insulation while worn. \
Acts as a focus while hooded."
gain_text = "The echoing, directionless cacophony of violence reverberates about me. \
Even as the Champion's steel panoply was torn from their form, each piece craves purpose still, seeking to intercept unseen or imagined attackers."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/blade)
research_tree_icon_state = "blade_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
list(/obj/item/stack/sheet/mineral/silver, /obj/item/stack/sheet/mineral/titanium) = 1,
)
/datum/heretic_knowledge/spell/wolves_among_sheep
name = "Wolves Among Sheep"
@@ -199,8 +197,9 @@
I have made an enemy of all, and peace will never be known to me \
again. I have shattered bonds and severed all alliances. In this truth, \
I know now the fragility of comradery. My enemies will be all, divided."
cost = 1
cost = 2
action_to_add = /datum/action/cooldown/spell/wolves_among_sheep
is_final_knowledge = TRUE
/datum/heretic_knowledge/blade_upgrade/blade
name = "Empowered Blades"
@@ -221,11 +220,10 @@
. = ..()
RegisterSignal(user, COMSIG_TOUCH_HANDLESS_CAST, PROC_REF(on_grasp_cast))
RegisterSignal(user, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_blade_equipped))
RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(do_melee_effects))
/datum/heretic_knowledge/blade_upgrade/blade/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
UnregisterSignal(user, list(COMSIG_TOUCH_HANDLESS_CAST, COMSIG_MOB_EQUIPPED_ITEM, COMSIG_HERETIC_BLADE_ATTACK))
UnregisterSignal(user, list(COMSIG_TOUCH_HANDLESS_CAST, COMSIG_MOB_EQUIPPED_ITEM))
///Tries to infuse our held blade with our mansus grasp
/datum/heretic_knowledge/blade_upgrade/blade/proc/on_grasp_cast(mob/living/carbon/cast_on)
@@ -296,7 +294,7 @@
/datum/heretic_knowledge/blade_upgrade/blade/proc/on_blade_equipped(mob/user, obj/item/equipped, slot)
SIGNAL_HANDLER
if(istype(equipped, /obj/item/melee/sickly_blade/dark))
equipped.demolition_mod = 1.5
equipped.demolition_mod = 2.5
/datum/heretic_knowledge/spell/furious_steel
name = "Furious Steel"
@@ -307,7 +305,7 @@
gain_text = "Without thinking, I took the knife of a fallen soldier and threw with all my might. My aim was true! \
The Torn Champion smiled at their first taste of agony, and with a nod, their blades became my own."
action_to_add = /datum/action/cooldown/spell/pointed/projectile/furious_steel
cost = 1
cost = 2
/datum/heretic_knowledge/ultimate/blade_final
name = "Maelstrom of Silver"
@@ -336,7 +334,7 @@
. = ..()
ADD_TRAIT(user, TRAIT_NEVER_WOUNDED, type)
RegisterSignal(user, COMSIG_HERETIC_BLADE_ATTACK, PROC_REF(on_eldritch_blade))
user.apply_status_effect(/datum/status_effect/protective_blades/recharging, null, 8, 30, 0.25 SECONDS, /obj/effect/floating_blade, 1 MINUTES)
user.apply_status_effect(/datum/status_effect/protective_blades/recharging, STATUS_EFFECT_PERMANENT, 8, 30, 0.25 SECONDS, /obj/effect/floating_blade, 60 SECONDS)
user.add_stun_absorption(
source = name,
message = span_warning("%EFFECT_OWNER throws off the stun!"),

View File

@@ -1,20 +1,50 @@
/datum/heretic_knowledge_tree_column/main/cosmic
neighbour_type_left = /datum/heretic_knowledge_tree_column/rust_to_cosmic
neighbour_type_right = /datum/heretic_knowledge_tree_column/cosmic_to_ash
/datum/heretic_knowledge_tree_column/cosmic
route = PATH_COSMIC
ui_bgr = "node_cosmos"
complexity = "Hard"
complexity_color = COLOR_RED
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "cosmic_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Cosmos revolves around area denial, teleporation, and mastery over space.",
"Pick this path if you enjoy adapting to your environment and thinking outside (or inside) the box.",
)
pros = list(
"Control the movement of foes with cosmic fields",
"Move in and around space with ease.",
"Teleport rapidly across the station.",
"Confound opponents with barriers upon barriers.",
)
cons = list(
"Requires you spread your star mark to affect opponents with your cosmic fields.",
"Relatively low damage.",
"Relatively low direct defense, highly reliant on proper use of abilities.",
)
tips = list(
"Your Mansus Grasp will mark your opponent with a star mark, as well as leave a mark that, when detonated, will teleport your opponent back to the place where the mark was applied and briefly paralyze them.",
"Your cosmic runes can quickly teleport you from two different locations instantly. Beware, however; non-heretics are also able to travel through them. Be creative and have your opponents teleport right into a trap. They come out star marked!",
"When standing on top of a cosmic rune, you can click on yourself with a empty hand to activate it.",
"Star marked opponents cannot cross your cosmic fields willingly. But they can be dragged through!",
"Star Blast is both a jaunt ability as well as a disabling tool. Use it to catch several people in your cosmic fields at once.",
"Star Touch will prevent your target from teleporting away. Should they fail to break the tether, they will be put to sleep and then teleport to your feet.",
"It's Always a good idea to leave one cosmic rune near your ritual rune, it will allow you to quickly kidnap your targets to sacrifice them.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_cosmic
grasp = /datum/heretic_knowledge/cosmic_grasp
tier1 = /datum/heretic_knowledge/spell/cosmic_runes
mark = /datum/heretic_knowledge/mark/cosmic_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/cosmic
unique_ability = /datum/heretic_knowledge/spell/star_touch
tier2 = /datum/heretic_knowledge/spell/star_blast
knowledge_tier1 = /datum/heretic_knowledge/spell/cosmic_runes
guaranteed_side_tier1 = /datum/heretic_knowledge/eldritch_coin
knowledge_tier2 = /datum/heretic_knowledge/spell/star_blast
guaranteed_side_tier2 = /datum/heretic_knowledge/spell/space_phase
robes = /datum/heretic_knowledge/armor/cosmic
knowledge_tier3 = /datum/heretic_knowledge/spell/star_touch
guaranteed_side_tier3 = /datum/heretic_knowledge/essence
blade = /datum/heretic_knowledge/blade_upgrade/cosmic
tier3 = /datum/heretic_knowledge/spell/cosmic_expansion
knowledge_tier4 = /datum/heretic_knowledge/spell/cosmic_expansion
ascension = /datum/heretic_knowledge/ultimate/cosmic_final
/datum/heretic_knowledge/limited_amount/starting/base_cosmic
@@ -30,30 +60,16 @@
result_atoms = list(/obj/item/melee/sickly_blade/cosmic)
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "cosmic_blade"
/datum/heretic_knowledge/cosmic_grasp
name = "Grasp of Cosmos"
desc = "Your Mansus Grasp will give people a star mark (cosmic ring) and create a cosmic field where you stand. \
People with a star mark can not pass cosmic fields."
gain_text = "Some stars dimmed, others' magnitude increased. \
With newfound strength I could channel the nebula's power into myself."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_cosmos"
/datum/heretic_knowledge/cosmic_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/cosmic_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
mark_type = /datum/status_effect/eldritch/cosmic
eldritch_passive = /datum/status_effect/heretic_passive/cosmic
/// Aplies the effect of the mansus grasp when it hits a target.
/datum/heretic_knowledge/cosmic_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_cosmic/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
to_chat(target, span_danger("A cosmic ring appeared above your head!"))
target.apply_status_effect(/datum/status_effect/star_mark, source)
new /obj/effect/forcefield/cosmic_field(get_turf(source))
create_cosmic_field(get_turf(source), source)
/datum/heretic_knowledge/spell/cosmic_runes
name = "Cosmic Runes"
@@ -63,20 +79,30 @@
gain_text = "The distant stars crept into my dreams, roaring and screaming without reason. \
I spoke, and heard my own words echoed back."
action_to_add = /datum/action/cooldown/spell/cosmic_rune
cost = 1
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/spell/star_blast
name = "Star Blast"
desc = "Fires a projectile that moves very slowly, raising a short-lived wall of cosmic fields where it goes. \
Anyone hit by the projectile will receive burn damage, a knockdown, and give people in a three tile range a star mark."
gain_text = "The Beast was behind me now at all times, with each sacrifice words of affirmation coursed through me."
action_to_add = /datum/action/cooldown/spell/pointed/projectile/star_blast
cost = 2
/datum/heretic_knowledge/mark/cosmic_mark
name = "Mark of Cosmos"
desc = "Your Mansus Grasp now applies the Mark of Cosmos. The mark is triggered from an attack with your Cosmic Blade. \
When triggered, the victim is returned to the location where the mark was originally applied to them, \
leaving a cosmic field in their place. \
They will then be paralyzed for 2 seconds."
gain_text = "The Beast now whispered to me occasionally, only small tidbits of their circumstances. \
I can help them, I have to help them."
mark_type = /datum/status_effect/eldritch/cosmic
/datum/heretic_knowledge/armor/cosmic
/datum/heretic_knowledge/knowledge_ritual/cosmic
desc = "Allows you to transmute a table (or a suit), a mask and a sheet of plasma to create a Starwoven Cloak, grants protection from the hazards of space while granting to the user the ability to levitate at will. \
Acts as a focus while hooded."
gain_text = "Like radiant cords, the stars shone in union across the silken shape of a billowing cloak, that at once does and does not drape my shoulders. \
The eyes of the Beast rested upon me, and through me."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/cosmic)
research_tree_icon_state = "cosmic_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/item/stack/sheet/mineral/plasma = 1,
)
/datum/heretic_knowledge/spell/star_touch
name = "Star Touch"
@@ -87,23 +113,14 @@
gain_text = "After waking in a cold sweat I felt a palm on my scalp, a sigil burned onto me. \
My veins now emitted a strange purple glow, the Beast knows I will surpass its expectations."
action_to_add = /datum/action/cooldown/spell/touch/star_touch
cost = 1
/datum/heretic_knowledge/spell/star_blast
name = "Star Blast"
desc = "Fires a projectile that moves very slowly, raising a short-lived wall of cosmic fields where it goes. \
Anyone hit by the projectile will receive burn damage, a knockdown, and give people in a three tile range a star mark."
gain_text = "The Beast was behind me now at all times, with each sacrifice words of affirmation coursed through me."
action_to_add = /datum/action/cooldown/spell/pointed/projectile/star_blast
cost = 1
cost = 2
/datum/heretic_knowledge/blade_upgrade/cosmic
name = "Cosmic Blade"
desc = "Your blade now deals damage to people's organs through cosmic radiation. \
desc = "Your blade now star marks your victims, and allows you to attack star marked heathens from further away. \
Your attacks will chain bonus damage to up to two previous victims. \
The combo is reset after two seconds without making an attack, \
or if you attack someone already marked. If you combo more than four attacks you will receive, \
a cosmic trail and increase your combo timer up to ten seconds."
The combo is reset after two seconds without making an attack, or if you attack someone already marked. \
If you combo three attacks you will receive a cosmic trail and increase your combo timer up to ten seconds."
gain_text = "The Beast took my blades in their hand, I kneeled and felt a sharp pain. \
The blades now glistened with fragmented power. I fell to the ground and wept at the beast's feet."
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
@@ -124,19 +141,20 @@
var/increase_amount = 0.5 SECONDS
/// The hits we have on a mob with a mind.
var/combo_counter = 0
/// How much further we can hit people, modified by ascension
var/max_attack_range = 2
/datum/heretic_knowledge/blade_upgrade/cosmic/on_ranged_eldritch_blade(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
. = ..()
if(!isliving(target) || get_dist(source, target) > max_attack_range || !target.has_status_effect(/datum/status_effect/star_mark))
return
source.changeNext_move(blade.attack_speed)
return blade.attack(target, source)
/datum/heretic_knowledge/blade_upgrade/cosmic/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
var/static/list/valid_organ_slots = list(
ORGAN_SLOT_HEART,
ORGAN_SLOT_LUNGS,
ORGAN_SLOT_STOMACH,
ORGAN_SLOT_EYES,
ORGAN_SLOT_EARS,
ORGAN_SLOT_LIVER,
ORGAN_SLOT_BRAIN
)
if(source == target || !isliving(target))
return
target.apply_status_effect(/datum/status_effect/star_mark, source)
if(combo_timer)
deltimer(combo_timer)
combo_timer = addtimer(CALLBACK(src, PROC_REF(reset_combo), source), combo_duration, TIMER_STOPPABLE)
@@ -144,7 +162,6 @@
var/mob/living/third_target_resolved = third_target?.resolve()
var/need_mob_update = FALSE
need_mob_update += target.adjustFireLoss(5, updating_health = FALSE)
need_mob_update += target.adjustOrganLoss(pick(valid_organ_slots), 8)
if(need_mob_update)
target.updatehealth()
if(target == second_target_resolved || target == third_target_resolved)
@@ -157,7 +174,6 @@
playsound(get_turf(second_target_resolved), 'sound/effects/magic/cosmic_energy.ogg', 25, FALSE)
need_mob_update = FALSE
need_mob_update += second_target_resolved.adjustFireLoss(14, updating_health = FALSE)
need_mob_update += second_target_resolved.adjustOrganLoss(pick(valid_organ_slots), 12)
if(need_mob_update)
second_target_resolved.updatehealth()
if(third_target_resolved)
@@ -165,15 +181,12 @@
playsound(get_turf(third_target_resolved), 'sound/effects/magic/cosmic_energy.ogg', 50, FALSE)
need_mob_update = FALSE
need_mob_update += third_target_resolved.adjustFireLoss(28, updating_health = FALSE)
need_mob_update += third_target_resolved.adjustOrganLoss(pick(valid_organ_slots), 14)
if(need_mob_update)
third_target_resolved.updatehealth()
if(combo_counter > 3)
target.apply_status_effect(/datum/status_effect/star_mark, source)
if(combo_counter == 3)
if(target.mind && target.stat != DEAD)
increase_combo_duration()
if(combo_counter == 4)
source.AddElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast)
source.AddElement(cosmic_trail_based_on_passive(source), /obj/effect/forcefield/cosmic_field/fast)
third_target = second_target
second_target = WEAKREF(target)
@@ -181,8 +194,7 @@
/datum/heretic_knowledge/blade_upgrade/cosmic/proc/reset_combo(mob/living/source)
second_target = null
third_target = null
if(combo_counter > 3)
source.RemoveElement(/datum/element/effect_trail, /obj/effect/forcefield/cosmic_field/fast)
source.RemoveElement(cosmic_trail_based_on_passive(source), /obj/effect/forcefield/cosmic_field/fast)
combo_duration = combo_duration_amount
combo_counter = 0
new /obj/effect/temp_visual/cosmic_cloud(get_turf(source))
@@ -196,16 +208,17 @@
/datum/heretic_knowledge/spell/cosmic_expansion
name = "Cosmic Expansion"
desc = "Grants you Cosmic Expansion, a spell that creates a 3x3 area of cosmic fields around you. \
desc = "Grants you Cosmic Expansion, a spell that creates a 5x5 area of cosmic fields around you. \
Nearby beings will also receive a star mark."
gain_text = "The ground now shook beneath me. The Beast inhabited me, and their voice was intoxicating."
action_to_add = /datum/action/cooldown/spell/conjure/cosmic_expansion
cost = 1
cost = 2
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/cosmic_final
name = "Creators's Gift"
desc = "The ascension ritual of the Path of Cosmos. \
Bring 3 corpses with bluespace dust in their body to a transmutation rune to complete the ritual. \
Bring 3 corpses with a star mark to a transmutation rune to complete the ritual. \
When completed, you become the owner of a Star Gazer. \
You will be able to command the Star Gazer with Alt+click. \
You can also give it commands through speech. \
@@ -228,22 +241,33 @@
/datum/pet_command/follow,
/datum/pet_command/attack/star_gazer
)
/// List of traits given once ascended
var/static/list/ascended_traits = list(TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, TRAIT_XRAY_VISION)
/// List of traits given to our cute lil guy
var/static/list/stargazer_traits = list(TRAIT_RESISTLOWPRESSURE, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTCOLD, TRAIT_RESISTHEAT, TRAIT_BOMBIMMUNE, TRAIT_XRAY_VISION)
/datum/heretic_knowledge/ultimate/cosmic_final/is_valid_sacrifice(mob/living/carbon/human/sacrifice)
. = ..()
if(!.)
return FALSE
return sacrifice.has_reagent(/datum/reagent/bluespace)
return sacrifice.has_status_effect(/datum/status_effect/star_mark)
/datum/heretic_knowledge/ultimate/cosmic_final/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
. = ..()
var/mob/living/basic/heretic_summon/star_gazer/star_gazer_mob = new /mob/living/basic/heretic_summon/star_gazer(loc)
user.add_traits(ascended_traits, type)
if(ishuman(user))
var/mob/living/carbon/human/ascended_human = user
var/obj/item/organ/eyes/heretic_eyes = ascended_human.get_organ_slot(ORGAN_SLOT_EYES)
ascended_human.update_sight()
heretic_eyes?.color_cutoffs = list(30, 30, 30)
ascended_human.update_sight()
var/mob/living/basic/heretic_summon/star_gazer/star_gazer_mob = new /mob/living/basic/heretic_summon/star_gazer(loc, user)
star_gazer_mob.maxHealth = INFINITY
star_gazer_mob.health = INFINITY
user.AddComponent(/datum/component/death_linked, star_gazer_mob)
star_gazer_mob.AddComponent(/datum/component/obeys_commands, star_gazer_commands, radial_menu_offset = list(30,0), radial_menu_lifetime = 15 SECONDS, radial_relative_to_user = TRUE)
star_gazer_mob.AddComponent(/datum/component/damage_aura, range = 7, burn_damage = 0.5, simple_damage = 0.5, immune_factions = list(FACTION_HERETIC), current_owner = user)
star_gazer_mob.befriend(user)
var/datum/action/cooldown/open_mob_commands/commands_action = new /datum/action/cooldown/open_mob_commands()
commands_action.Grant(user, star_gazer_mob)
@@ -251,6 +275,8 @@
if(star_touch_spell)
star_touch_spell.set_star_gazer(star_gazer_mob)
star_touch_spell.ascended = TRUE
star_gazer_mob.add_traits(stargazer_traits, type)
star_gazer_mob.leash_to(star_gazer_mob, user)
var/datum/antagonist/heretic/heretic_datum = user.mind.has_antag_datum(/datum/antagonist/heretic)
var/datum/heretic_knowledge/blade_upgrade/cosmic/blade_upgrade = heretic_datum.get_knowledge(/datum/heretic_knowledge/blade_upgrade/cosmic)
@@ -258,6 +284,46 @@
blade_upgrade.combo_duration_amount = 10 SECONDS
blade_upgrade.max_combo_duration = 30 SECONDS
blade_upgrade.increase_amount = 2 SECONDS
blade_upgrade.max_attack_range = 3
var/datum/action/cooldown/spell/conjure/cosmic_expansion/cosmic_expansion_spell = locate() in user.actions
cosmic_expansion_spell?.ascended = TRUE
var/datum/action/cooldown/mob_cooldown/replace_star_gazer/replace_gazer = new(src)
replace_gazer.Grant(user)
replace_gazer.bad_dog = WEAKREF(star_gazer_mob)
/// Replace an annoying griefer you were paired up to with a different but probably no less annoying player.
/datum/action/cooldown/mob_cooldown/replace_star_gazer
name = "Reset Star Gazer Consciousness"
desc = "Replaces the mind of your summon with that of a different ghost."
button_icon = 'icons/mob/simple/mob.dmi'
button_icon_state = "ghost"
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
check_flags = NONE
click_to_activate = FALSE
cooldown_time = 5 SECONDS
melee_cooldown_time = 0
shared_cooldown = NONE
/// Weakref to the stargazer we care about
var/datum/weakref/bad_dog
/datum/action/cooldown/mob_cooldown/replace_star_gazer/Activate(atom/target)
StartCooldown(5 MINUTES)
var/mob/living/to_reset = bad_dog.resolve()
to_chat(owner, span_hierophant("You prompt [to_reset] to shift it\'s personality..."))
var/mob/chosen_one = SSpolling.poll_ghost_candidates("Do you want to play as [span_danger("[owner.real_name]'s")] [span_notice(to_reset.name)]?", check_jobban = ROLE_PAI, poll_time = 10 SECONDS, alert_pic = to_reset, jump_target = owner, role_name_text = to_reset.name, amount_to_pick = 1)
if(isnull(chosen_one))
to_chat(owner, span_hierophant("Your request to shift [to_reset]'\s personality appears to have been denied... Looks like you're stuck with it for now."))
StartCooldown()
return FALSE
to_chat(to_reset, span_hierophant("Your summoner reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance."))
to_chat(owner, span_hierophant("The mind of [to_reset] has twisted itself to suit you better."))
message_admins("[key_name_admin(chosen_one)] has taken control of ([ADMIN_LOOKUPFLW(to_reset)])")
to_reset.ghostize(FALSE)
to_reset.PossessByPlayer(chosen_one.key)
StartCooldown()
return TRUE

View File

@@ -1,24 +1,52 @@
/// The max amount of health a ghoul has.
#define GHOUL_MAX_HEALTH 25
/// The max amount of health a voiceless dead has.
#define MUTE_MAX_HEALTH 50
/datum/heretic_knowledge_tree_column/main/flesh
neighbour_type_left = /datum/heretic_knowledge_tree_column/lock_to_flesh
neighbour_type_right = /datum/heretic_knowledge_tree_column/flesh_to_void
/datum/heretic_knowledge_tree_column/flesh
route = PATH_FLESH
ui_bgr = "node_flesh"
complexity = "Varies"
complexity_color = COLOR_ORANGE
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "flesh_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Flesh revolves around summoning ghouls and monstrosities to do your bidding.",
"Pick this path if you enjoy the fantasy of being a necromancer commanding legions of allies.",
)
pros = list(
"Can turn dead humanoids into fragile but loyal ghouls.",
"Access to a versatile list of summoned minions.",
"Your summons are very versatie and can quicky overwhelm the crew should you coordinate your attacks",
"Eating organs or being fat grants various boons (depending on the level of your passive).",
)
cons = list(
"A high degree of your progression is obtaining additional summoned monsters.",
"You have very little utility beyond your summoned monsters.",
"You gain no inherent access to defensive, offensive or mobility spells.",
"You are mostly focused around supporting your minions.",
)
tips = list(
"Your Mansus Grasp allows you to turn dead humanoids into ghouls (even mindshielded humanoids like security officers and the captain). It also Leaves a mark that causes heavy bleeding when triggered by your bloody blade.",
"As a Flesh Heretic, organs and dead bodies are your best friends! You can use them for rituals, to heal or to gain buffs.",
"Your Flesh Surgery spell can heal your summons. Your robes grant you an aura that also heals nearby summons (but not yourself).",
"Your Flesh Surgery spell also lets you steal organs from humanoids. Useful if you need a spare liver.",
"Raw Prophets can link you and other summons in a telepathic network, allowing for long distance co-ordination.",
"Flesh Stalkers are decent combatants with the ability to disguise themselves as small creatures, like beepskies and corgis. They can also utilize an EMP spell, but this can potentially harm them if they transformed into a robot!",
"Your success with this path is reliant on how knowledgable or robust your minions are. However, there is always power in numbers; the more minions, the higher your chances of success.",
"Your minions are more expendable than you are. Do not be afraid to tell them to go to their deaths. You can just recover them later... maybe.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_flesh
grasp = /datum/heretic_knowledge/limited_amount/flesh_grasp
tier1 = /datum/heretic_knowledge/limited_amount/flesh_ghoul
mark = /datum/heretic_knowledge/mark/flesh_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/flesh
unique_ability = /datum/heretic_knowledge/spell/flesh_surgery
tier2 = /datum/heretic_knowledge/summon/raw_prophet
knowledge_tier1 = /datum/heretic_knowledge/limited_amount/flesh_ghoul
guaranteed_side_tier1 = /datum/heretic_knowledge/limited_amount/risen_corpse
knowledge_tier2 = /datum/heretic_knowledge/spell/flesh_surgery
guaranteed_side_tier2 = /datum/heretic_knowledge/crucible
robes = /datum/heretic_knowledge/armor/flesh
knowledge_tier3 = /datum/heretic_knowledge/summon/raw_prophet
guaranteed_side_tier3 = /datum/heretic_knowledge/spell/crimson_cleave
blade = /datum/heretic_knowledge/blade_upgrade/flesh
tier3 = /datum/heretic_knowledge/summon/stalker
knowledge_tier4 = /datum/heretic_knowledge/summon/stalker
ascension = /datum/heretic_knowledge/ultimate/flesh_final
/datum/heretic_knowledge/limited_amount/starting/base_flesh
@@ -35,6 +63,8 @@
limit = 3 // Bumped up so they can arm up their ghouls too.
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "flesh_blade"
mark_type = /datum/status_effect/eldritch/flesh
eldritch_passive = /datum/status_effect/heretic_passive/flesh
/datum/heretic_knowledge/limited_amount/starting/base_flesh/on_research(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
@@ -45,28 +75,8 @@
to_chat(user, span_hierophant("Undertaking the Path of Flesh, you are given another objective."))
our_heretic.owner.announce_objectives()
/datum/heretic_knowledge/limited_amount/flesh_grasp
name = "Grasp of Flesh"
desc = "Your Mansus Grasp gains the ability to create a ghoul out of corpse with a soul. \
Ghouls have only 25 health and look like husks to the heathens' eyes, but can use Bloody Blades effectively. \
You can only create one at a time by this method."
gain_text = "My new found desires drove me to greater and greater heights."
limit = 1
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_flesh"
/datum/heretic_knowledge/limited_amount/flesh_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/limited_amount/flesh_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/limited_amount/flesh_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_flesh/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
if(target.stat != DEAD)
return
@@ -92,8 +102,11 @@
make_ghoul(source, target)
/// The max amount of health a ghoul has.
#define GHOUL_MAX_HEALTH 25
/// Makes [victim] into a ghoul.
/datum/heretic_knowledge/limited_amount/flesh_grasp/proc/make_ghoul(mob/living/user, mob/living/carbon/human/victim)
/datum/heretic_knowledge/limited_amount/starting/base_flesh/proc/make_ghoul(mob/living/user, mob/living/carbon/human/victim)
user.log_message("created a ghoul, controlled by [key_name(victim)].", LOG_GAME)
message_admins("[ADMIN_LOOKUPFLW(user)] created a ghoul, [ADMIN_LOOKUPFLW(victim)].")
@@ -106,11 +119,11 @@
)
/// Callback for the ghoul status effect - Tracking all of our ghouls
/datum/heretic_knowledge/limited_amount/flesh_grasp/proc/apply_to_ghoul(mob/living/ghoul)
/datum/heretic_knowledge/limited_amount/starting/base_flesh/proc/apply_to_ghoul(mob/living/ghoul)
LAZYADD(created_items, WEAKREF(ghoul))
/// Callback for the ghoul status effect - Tracking all of our ghouls
/datum/heretic_knowledge/limited_amount/flesh_grasp/proc/remove_from_ghoul(mob/living/ghoul)
/datum/heretic_knowledge/limited_amount/starting/base_flesh/proc/remove_from_ghoul(mob/living/ghoul)
LAZYREMOVE(created_items, WEAKREF(ghoul))
/datum/heretic_knowledge/limited_amount/flesh_ghoul
@@ -125,12 +138,10 @@
/obj/item/food/grown/poppy = 1,
)
limit = 2
cost = 1
cost = 2
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "ghoul_voiceless"
/datum/heretic_knowledge/limited_amount/flesh_ghoul/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
. = ..()
if(!.)
@@ -173,6 +184,9 @@
make_ghoul(user, soon_to_be_ghoul)
return TRUE
/// The max amount of health a voiceless dead has.
#define MUTE_MAX_HEALTH 50
/// Makes [victim] into a ghoul.
/datum/heretic_knowledge/limited_amount/flesh_ghoul/proc/make_ghoul(mob/living/user, mob/living/carbon/human/victim)
user.log_message("created a voiceless dead, controlled by [key_name(victim)].", LOG_GAME)
@@ -196,17 +210,6 @@
LAZYREMOVE(created_items, WEAKREF(ghoul))
REMOVE_TRAIT(ghoul, TRAIT_MUTE, MAGIC_TRAIT)
/datum/heretic_knowledge/mark/flesh_mark
name = "Mark of Flesh"
desc = "Your Mansus Grasp now applies the Mark of Flesh. The mark is triggered from an attack with your Bloody Blade. \
When triggered, the victim begins to bleed significantly."
gain_text = "That's when I saw them, the marked ones. They were out of reach. They screamed, and screamed."
mark_type = /datum/status_effect/eldritch/flesh
/datum/heretic_knowledge/knowledge_ritual/flesh
/datum/heretic_knowledge/spell/flesh_surgery
name = "Knitting of Flesh"
desc = "Grants you the spell Knit Flesh. This spell allows you to remove organs from victims \
@@ -215,7 +218,22 @@
gain_text = "But they were not out of my reach for long. With every step, the screams grew, until at last \
I learned that they could be silenced."
action_to_add = /datum/action/cooldown/spell/touch/flesh_surgery
cost = 1
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/armor/flesh
desc = "Allows you to transmute a table (or a suit), a mask and a pool of blood to create a writhing embrace. \
It grants you the ability to detect the health condition of other living (and non-living) and an aura that slowly heals your summons. \
Acts as a focus while hooded."
gain_text = "I tugged these wretched, slothing things about me, like one might a warm blanket. \
With eyes-not-mine, they will witness. With teeth-not-mine, they will clench. With limbs-not-mine, they will break."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/flesh)
research_tree_icon_state = "flesh_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/effect/decal/cleanable/blood = 1,
)
/datum/heretic_knowledge/summon/raw_prophet
name = "Raw Ritual"
@@ -230,7 +248,7 @@
/obj/item/bodypart/arm/left = 1,
)
mob_to_summon = /mob/living/basic/heretic_summon/raw_prophet
cost = 1
cost = 2
poll_ignore_define = POLL_IGNORE_RAW_PROPHET
@@ -268,10 +286,10 @@
/obj/item/paper = 1,
)
mob_to_summon = /mob/living/basic/heretic_summon/stalker
cost = 1
cost = 2
poll_ignore_define = POLL_IGNORE_STALKER
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/flesh_final
name = "Priest's Final Hymn"
@@ -297,7 +315,7 @@
worm_spell.Grant(user)
var/datum/antagonist/heretic/heretic_datum = GET_HERETIC(user)
var/datum/heretic_knowledge/limited_amount/flesh_grasp/grasp_ghoul = heretic_datum.get_knowledge(/datum/heretic_knowledge/limited_amount/flesh_grasp)
var/datum/heretic_knowledge/limited_amount/starting/base_flesh/grasp_ghoul = heretic_datum.get_knowledge(/datum/heretic_knowledge/limited_amount/starting/base_flesh)
grasp_ghoul.limit *= 3
var/datum/heretic_knowledge/limited_amount/flesh_ghoul/ritual_ghoul = heretic_datum.get_knowledge(/datum/heretic_knowledge/limited_amount/flesh_ghoul)
ritual_ghoul.limit *= 3

View File

@@ -0,0 +1,25 @@
/datum/heretic_knowledge/armor
name = "Armorer's Ritual"
desc = "Allows you to transmute a table (or a suit) and a mask to create Eldritch Armor. \
Eldritch Armor provides great protection while also acting as a focus when hooded."
gain_text = "The Rusted Hills welcomed the Blacksmith in their generosity. And the Blacksmith \
returned their generosity in kind."
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
)
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/clothing/suits/armor.dmi'
research_tree_icon_state = "eldritch_armor"
research_tree_icon_frame = 1
/datum/heretic_knowledge/armor/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
. = ..()
var/datum/antagonist/heretic/heretic_datum = GET_HERETIC(user)
if(!heretic_datum)
return
SEND_SIGNAL(heretic_datum, COMSIG_HERETIC_PASSIVE_UPGRADE_FIRST)
heretic_datum.gain_knowledge(/datum/heretic_knowledge/knowledge_ritual)

View File

@@ -1,20 +1,47 @@
/datum/heretic_knowledge_tree_column/main/lock
neighbour_type_left = /datum/heretic_knowledge_tree_column/moon_to_lock
neighbour_type_right = /datum/heretic_knowledge_tree_column/lock_to_flesh
/datum/heretic_knowledge_tree_column/lock
route = PATH_LOCK
ui_bgr = "node_lock"
complexity = "Medium"
complexity_color = COLOR_YELLOW
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "key_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Lock revolves around access, area denial, theft and gadgets.",
"Pick this path if you want a less confrontational playstyle and more interested in being a slippery rat.",
)
pros = list(
"Your mansus grasp can open any lock, unlock every terminal and bypass any access restriction.",
"lock heretics get a discount from the knowledge shop, making it the perfect path if you want to experiment with the various trinkets the shop has to offer.",
)
cons = list(
"The weakest heretic path in direct combat, period.",
"Very limited direct combat benefits.",
"You have no defensive benefits or immunities.",
"no mobility or direct additional teleportation",
"Highly reliant on sourcing power from other departments, players and the game world.",
)
tips = list(
"Your mansus grasp allows you to access everything, from airlocks, consoles and even exosuits, but it has no additional effects on players. It will however leave a mark that when triggered will make your victim unable to leave the room you are in.",
"Your blade also functions as a crowbar! You can store it in utility belts And, in a pitch, use it to force open an airlock.",
"Your Eldritch ID can create a portal between 2 different airlocks. Useful if you want to enstablish a secret base.",
"Use your labyrinth book to shake off pursuers. It creates impassible walls to anyone but you.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_knock
grasp = /datum/heretic_knowledge/lock_grasp
tier1 = /datum/heretic_knowledge/key_ring
mark = /datum/heretic_knowledge/mark/lock_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/lock
unique_ability = /datum/heretic_knowledge/limited_amount/concierge_rite
tier2 = /datum/heretic_knowledge/spell/burglar_finesse
knowledge_tier1 = /datum/heretic_knowledge/key_ring
guaranteed_side_tier1 = /datum/heretic_knowledge/painting
knowledge_tier2 = /datum/heretic_knowledge/limited_amount/concierge_rite
guaranteed_side_tier2 = /datum/heretic_knowledge/spell/opening_blast
robes = /datum/heretic_knowledge/armor/lock
knowledge_tier3 = /datum/heretic_knowledge/spell/burglar_finesse
guaranteed_side_tier3 = /datum/heretic_knowledge/summon/fire_shark
blade = /datum/heretic_knowledge/blade_upgrade/flesh/lock
tier3 = /datum/heretic_knowledge/spell/caretaker_refuge
knowledge_tier4 = /datum/heretic_knowledge/spell/caretaker_refuge
ascension = /datum/heretic_knowledge/ultimate/lock_final
/datum/heretic_knowledge/limited_amount/starting/base_knock
@@ -32,33 +59,29 @@
limit = 2
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "key_blade"
mark_type = /datum/status_effect/eldritch/lock
eldritch_passive = /datum/status_effect/heretic_passive/lock
/datum/heretic_knowledge/lock_grasp
name = "Grasp of Lock"
desc = "Your mansus grasp allows you to access anything! Right click on an airlock or a locker to force it open. \
DNA locks on mechs will be removed, and any pilot will be ejected. Works on consoles. \
Makes a distinctive knocking sound on use."
gain_text = "Nothing may remain closed from my touch."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_lock"
/datum/heretic_knowledge/lock_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
/datum/heretic_knowledge/limited_amount/starting/base_knock/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, PROC_REF(on_secondary_mansus_grasp))
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
var/datum/action/cooldown/spell/touch/mansus_grasp/grasp_spell = locate() in user.actions
grasp_spell?.invocation_type = INVOCATION_NONE
grasp_spell?.sound = null
/datum/heretic_knowledge/lock_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
/datum/heretic_knowledge/limited_amount/starting/base_knock/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/lock_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_knock/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
var/obj/item/clothing/under/suit = target.get_item_by_slot(ITEM_SLOT_ICLOTHING)
if(istype(suit) && suit.adjusted == NORMAL_STYLE)
suit.toggle_jumpsuit_adjust()
suit.update_appearance()
/datum/heretic_knowledge/lock_grasp/proc/on_secondary_mansus_grasp(mob/living/source, atom/target)
/datum/heretic_knowledge/limited_amount/starting/base_knock/proc/on_secondary_mansus_grasp(mob/living/source, atom/target)
SIGNAL_HANDLER
if(ismecha(target))
@@ -80,7 +103,14 @@
var/turf/target_turf = get_turf(target)
SEND_SIGNAL(target_turf, COMSIG_ATOM_MAGICALLY_UNLOCKED, src, source)
playsound(target, 'sound/effects/magic/hereticknock.ogg', 100, TRUE, -1)
SEND_SOUND(source, 'sound/effects/magic/hereticknock.ogg')
if(HAS_TRAIT(source, TRAIT_LOCK_GRASP_UPGRADED))
var/datum/action/cooldown/spell/touch/mansus_grasp/grasp = locate() in source.actions
if(grasp)
grasp.next_use_time -= round(grasp.cooldown_time*0.75)
grasp.build_all_button_icons()
return
return COMPONENT_USE_HAND
@@ -99,7 +129,7 @@
/obj/item/card/id/advanced = 1,
)
result_atoms = list(/obj/item/card/id/advanced/heretic)
cost = 1
cost = 2
research_tree_icon_path = 'icons/obj/card.dmi'
research_tree_icon_state = "card_gold"
@@ -115,20 +145,10 @@
result_item.shapeshift(id)
return TRUE
/datum/heretic_knowledge/mark/lock_mark
name = "Mark of Lock"
desc = "Your Mansus Grasp now applies the Mark of Lock. \
Attack a marked person to bar them from all passages for the duration of the mark. \
This will make it so that they have no access whatsoever, even public access doors will reject them."
gain_text = "The Gatekeeper was a corrupt Steward. She hindered her fellows for her own twisted amusement."
mark_type = /datum/status_effect/eldritch/lock
/datum/heretic_knowledge/knowledge_ritual/lock
/datum/heretic_knowledge/limited_amount/concierge_rite // item that creates 3 max at a time heretic only barriers, probably should limit to 1 only, holy people can also pass
/datum/heretic_knowledge/limited_amount/concierge_rite
name = "Concierge's Rite"
desc = "Allows you to transmute a crayon, a wooden plank, and a multitool to create a Labyrinth Handbook. \
It can materialize a barricade at range that only you and people resistant to magic can pass. 3 uses."
It can materialize a barricade at range that only you and people resistant to magic can pass. Has 5 charges which regenerate over time."
gain_text = "The Concierge scribbled my name into the Handbook. \"Welcome to your new home, fellow Steward.\""
required_atoms = list(
/obj/item/toy/crayon = 1,
@@ -136,9 +156,25 @@
/obj/item/multitool = 1,
)
result_atoms = list(/obj/item/heretic_labyrinth_handbook)
cost = 1
cost = 2
research_tree_icon_path = 'icons/obj/service/library.dmi'
research_tree_icon_state = "heretichandbook"
drafting_tier = 5
/datum/heretic_knowledge/armor/lock
desc = "Allows you to transmute a table (or a suit), a mask and a crowbar to create a shifting guise. \
It grants you camoflage from cameras, hides your identity, voice and muffles your footsteps. \
Acts as a focus while hooded."
gain_text = "While stewards are known to the Concierge, \
they still consort between one another and with outsiders under shaded cloaks and drawn hoods. \
Familiarity is treachery, even to oneself."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/lock)
research_tree_icon_state = "lock_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/item/crowbar = 1,
)
/datum/heretic_knowledge/spell/burglar_finesse
name = "Burglar's Finesse"
@@ -147,9 +183,9 @@
gain_text = "Consorting with Burglar spirits is frowned upon, but a Steward will always want to learn about new doors."
action_to_add = /datum/action/cooldown/spell/pointed/burglar_finesse
cost = 1
cost = 2
/datum/heretic_knowledge/blade_upgrade/flesh/lock //basically a chance-based weeping avulsion version of the former
/datum/heretic_knowledge/blade_upgrade/flesh/lock
name = "Opening Blade"
desc = "Your blade has a chance to cause a weeping avulsion on attack."
gain_text = "The Pilgrim-Surgeon was not an Steward. Nonetheless, its blades and sutures proved a match for their keys."
@@ -169,7 +205,8 @@
You are invincible but unable to harm anything. Cancelled by being hit with an anti-magic item."
gain_text = "Jealously, the Guard and the Hound hunted me. But I unlocked my form, and was but a haze, untouchable."
action_to_add = /datum/action/cooldown/spell/caretaker
cost = 1
cost = 2
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/lock_final
name = "Unlock the Labyrinth"

View File

@@ -1,57 +1,79 @@
/datum/heretic_knowledge_tree_column/main/moon
neighbour_type_left = /datum/heretic_knowledge_tree_column/ash_to_moon
neighbour_type_right = /datum/heretic_knowledge_tree_column/moon_to_lock
/datum/heretic_knowledge_tree_column/moon
route = PATH_MOON
ui_bgr = "node_moon"
complexity = "Hard"
complexity_color = COLOR_RED
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "moon_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Moon revolves around sanity, sowing confusion and discord, and skirting the conventional rules of combat.",
"Play this path if you are already experienced with Heretic and want to try something highly unconventional, or simply if you desire to play a pacifist Heretic (Yes, really!)."
)
pros = list(
"High amount of tools to confound foes.",
"Sows chaos through the station via lunatics.",
"Practically immune to disabling effects while wearing the Resplendent Regalia."
)
cons = list(
"No mobility.",
"Mo direct tools to damage your opponents.",
"Reliant on misdirection and confusion.",
"Lunatics can become liabilities.",
"Fairly fragile despite their unique protection mechanics.",
"Death while wearing the Resplendent Regalia results in a gorey end.",
)
tips = list(
"Your Mansus Grasp will make your victim briefly hallucinate and apply a mark that, when triggered by your moon blade, will apply confusion and pacify them (the latter will get removed if the victim receives too much damage at once).",
"Your moon blade is special compared to the other heretic blades. It can be used even if you are pacified.",
"Your passive makes you completely impervious to brain traumas and slowly regenerates your brain health. Makes sure to upgrade it to bolster the regeneration effect.",
"Your Resplendent Regalia utterly changes the rules of combat for you and your opponents; You become fully immune to disabling effect, and all damage received (lethal or non lethal) will be converted into brain damage. However. the robes themselves have no armor, and prevent you from using guns as well as pacifying you (you can still use your moon blade).",
"Your moon amulette allows you to channel its effects through your moon blade. When toggled on, your Moon blade will no longer do lethal damage, but do sanity damage and become unblockable.",
"If the sanity of your opponents goes below a certain threshold, they'll become a lunatic. Lunatics are prompted to start attacking everyone (including you). Should you want to sacrifice them (or to get them to leave you be), hit them again with your moon blade to put them to sleep.",
"Ringleader's Rise summons an army of clones. They do barely any damage, but should they be attacked by non-heretics, they will explode and cause sanity and brain damage to those around them.",
"Your ascension will grant you an aura that converts nearby people to loyal lunatics. However, if they have a mindshield implant, their heads will instead detonate after a time.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_moon
grasp = /datum/heretic_knowledge/moon_grasp
tier1 = /datum/heretic_knowledge/spell/moon_smile
mark = /datum/heretic_knowledge/mark/moon_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/moon
unique_ability = /datum/heretic_knowledge/spell/moon_parade
tier2 = /datum/heretic_knowledge/moon_amulet
knowledge_tier1 = /datum/heretic_knowledge/spell/mind_gate
guaranteed_side_tier1 = /datum/heretic_knowledge/phylactery
knowledge_tier2 = /datum/heretic_knowledge/moon_amulet
guaranteed_side_tier2 = /datum/heretic_knowledge/codex_morbus
robes = /datum/heretic_knowledge/armor/moon
knowledge_tier3 = /datum/heretic_knowledge/spell/moon_parade
guaranteed_side_tier3 = /datum/heretic_knowledge/unfathomable_curio
blade = /datum/heretic_knowledge/blade_upgrade/moon
tier3 = /datum/heretic_knowledge/spell/moon_ringleader
knowledge_tier4 = /datum/heretic_knowledge/spell/moon_ringleader
ascension = /datum/heretic_knowledge/ultimate/moon_final
/datum/heretic_knowledge/limited_amount/starting/base_moon
name = "Moonlight Troupe"
desc = "Opens up the Path of Moon to you. \
Allows you to transmute 2 sheets of iron and a knife into an Lunar Blade. \
Allows you to transmute 2 sheets of glass and a knife into an Lunar Blade. \
You can only create two at a time."
gain_text = "Under the light of the moon the laughter echoes."
required_atoms = list(
/obj/item/knife = 1,
/obj/item/stack/sheet/iron = 2,
/obj/item/stack/sheet/glass = 2,
)
result_atoms = list(/obj/item/melee/sickly_blade/moon)
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "moon_blade"
mark_type = /datum/status_effect/eldritch/moon
eldritch_passive = /datum/status_effect/heretic_passive/moon
/datum/heretic_knowledge/limited_amount/starting/base_moon/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
ADD_TRAIT(user, TRAIT_EMPATH, REF(src))
/datum/heretic_knowledge/moon_grasp
name = "Grasp of Lunacy"
desc = "Your Mansus Grasp will cause your victims to hallucinate everyone as lunar mass, \
and hides your identity for a short duration."
gain_text = "The troupe on the side of the moon showed me truth, and I took it."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_moon"
/datum/heretic_knowledge/limited_amount/starting/base_moon/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
/datum/heretic_knowledge/moon_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/moon_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/moon_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
if(target.can_block_magic(MAGIC_RESISTANCE_MIND))
if(target.can_block_magic(MAGIC_RESISTANCE_MOON))
to_chat(target, span_danger("You hear echoing laughter from above..but it is dull and distant."))
return
@@ -64,39 +86,23 @@
carbon_target.cause_hallucination(/datum/hallucination/delusion/preset/moon, "delusion/preset/moon hallucination caused by mansus grasp")
carbon_target.mob_mood.adjust_sanity(-30)
/datum/heretic_knowledge/spell/moon_smile
name = "Smile of the moon"
desc = "Grants you Smile of the moon, a ranged spell muting, blinding, deafening and knocking down the target for a\
duration based on their sanity."
gain_text = "The moon smiles upon us all and those who see its true side can bring its joy."
/datum/heretic_knowledge/spell/mind_gate
name = "Mind Gate"
desc = "Grants you Mind Gate, a spell which mutes,deafens, blinds, inflicts hallucinations, \
confusion, oxygen loss and brain damage to its target over 10 seconds.\
The caster takes 20 brain damage per use."
gain_text = "My mind swings open like a gate, and its insight will let me perceive the truth."
action_to_add = /datum/action/cooldown/spell/pointed/moon_smile
cost = 1
/datum/heretic_knowledge/mark/moon_mark
name = "Mark of Moon"
desc = "Your Mansus Grasp now applies the Mark of Moon, pacifying the victim until attacked. \
The mark can also be triggered from an attack with your Moon Blade, leaving the victim confused."
gain_text = "The troupe on the moon would dance all day long \
and in that dance the moon would smile upon us \
but when the night came its smile would dull forced to gaze on the earth."
mark_type = /datum/status_effect/eldritch/moon
/datum/heretic_knowledge/knowledge_ritual/moon
/datum/heretic_knowledge/spell/moon_parade
name = "Lunar Parade"
desc = "Grants you Lunar Parade, a spell that - after a short charge - sends a carnival forward \
when hitting someone they are forced to join the parade and suffer hallucinations."
gain_text = "The music like a reflection of the soul compelled them, like moths to a flame they followed"
action_to_add = /datum/action/cooldown/spell/pointed/projectile/moon_parade
cost = 1
action_to_add = /datum/action/cooldown/spell/pointed/mind_gate
cost = 2
/datum/heretic_knowledge/moon_amulet
name = "Moonlight Amulet"
desc = "Allows you to transmute 2 sheets of glass, a heart and a tie to create a Moonlight Amulet. \
If the item is used on someone with low sanity they go berserk attacking everyone, \
if their sanity isn't low enough it decreases their mood."
if their sanity isn't low enough it decreases their mood. \
Wearing this will grant you the ability to see heathens through walls and make your blades harmless, they will instead directly attack their mind. \
Provides thermal vision and doubles the brain regen of a moon heretic while worn."
gain_text = "At the head of the parade he stood, the moon condensed into one mass, a reflection of the soul."
required_atoms = list(
@@ -105,19 +111,41 @@
/obj/item/clothing/neck/tie = 1,
)
result_atoms = list(/obj/item/clothing/neck/heretic_focus/moon_amulet)
cost = 1
cost = 2
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "moon_amulette"
research_tree_icon_frame = 9
/datum/heretic_knowledge/armor/moon
desc = "Allows you to transmute a table (or a suit), a mask and two sheets of glass to create a Resplendant Regalia, this robe will render the user fully immune to disabling effects and convert all forms of damage into brain damage, while also pacifying the user and render him unable to use ranged weapons (Moon blade will bypass pacifism). \
Acts as a focus while hooded."
gain_text = "Trails of light and mirth flowed from every arm of this magnificent attire. \
The troupe twirled in irridescent cascades, dazzling onlookers with the truth they sought. \
I observed, basking in the light, to find my self."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/moon)
research_tree_icon_state = "moon_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/item/stack/sheet/glass = 2,
)
/datum/heretic_knowledge/spell/moon_parade
name = "Lunar Parade"
desc = "Grants you Lunar Parade, a spell that - after a short charge - sends a carnival forward \
when hitting someone they are forced to join the parade and suffer hallucinations."
gain_text = "The music like a reflection of the soul compelled them, like moths to a flame they followed"
action_to_add = /datum/action/cooldown/spell/pointed/projectile/moon_parade
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/blade_upgrade/moon
name = "Moonlight Blade"
desc = "Your blade now deals brain damage, causes random hallucinations and does sanity damage."
desc = "Your blade now deals brain damage, causes random hallucinations and does sanity damage. \
Deals more brain damage if your victim is insane or unconscious."
gain_text = "His wit was sharp as a blade, cutting through the lie to bring us joy."
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "blade_upgrade_moon"
@@ -125,16 +153,19 @@
if(source == target || !isliving(target))
return
if(target.can_block_magic(MAGIC_RESISTANCE_MIND))
if(target.can_block_magic(MAGIC_RESISTANCE_MOON))
return
target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10, 100)
target.cause_hallucination( \
get_random_valid_hallucination_subtype(/datum/hallucination/body), \
"upgraded path of moon blades", \
)
target.emote(pick("giggle", "laugh"))
target.mob_mood.adjust_sanity(-10)
target.mob_mood?.adjust_sanity(-10)
if(target.stat == CONSCIOUS && target.mob_mood?.sanity >= SANITY_NEUTRAL)
target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 10)
return
target.adjustOrganLoss(ORGAN_SLOT_BRAIN, 25)
/datum/heretic_knowledge/spell/moon_ringleader
name = "Ringleaders Rise"
@@ -145,17 +176,17 @@
The ringleader pointed up and the dim light of truth illuminated us further."
action_to_add = /datum/action/cooldown/spell/aoe/moon_ringleader
cost = 1
cost = 2
research_tree_icon_frame = 5
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/moon_final
name = "The Last Act"
desc = "The ascension ritual of the Path of Moon. \
Bring 3 corpses with more than 50 brain damage to a transmutation rune to complete the ritual. \
When completed, you become a harbinger of madness gaining and aura of passive sanity decrease, \
confusion increase and, if their sanity is low enough, brain damage and blindness. \
crewmembers with low enough sanity will be converted into acolytes. \
1/5th of the crew will turn into acolytes and follow your command, they will all receive moonlight amulets."
gain_text = "We dived down towards the crowd, his soul splitting off in search of greater venture \
for where the Ringleader had started the parade, I shall continue it unto the suns demise \
@@ -198,62 +229,91 @@
var/max_lunatics = ceil(max(length(GLOB.manifest.locked), length(lunatic_candidates)) * 0.2)
for(var/mob/living/carbon/human/crewmate as anything in lunatic_candidates)
// Heretics, lunatics and monsters shouldn't become lunatics because they either have a master or have a mansus grasp
if(IS_HERETIC_OR_MONSTER(crewmate))
to_chat(crewmate, span_boldwarning("[user]'s rise is influencing those who are weak willed. Their minds shall rend." ))
continue
// Mindshielded and anti-magic folks are immune against this effect because this is a magical mind effect
if(HAS_MIND_TRAIT(crewmate, TRAIT_UNCONVERTABLE) || crewmate.can_block_magic(MAGIC_RESISTANCE))
to_chat(crewmate, span_boldwarning("You feel shielded from something." ))
continue
if(amount_of_lunatics > max_lunatics)
to_chat(crewmate, span_boldwarning("You feel uneasy, as if for a brief moment something was gazing at you."))
continue
var/datum/antagonist/lunatic/lunatic = crewmate.mind.add_antag_datum(/datum/antagonist/lunatic)
lunatic.set_master(user.mind, user)
var/obj/item/clothing/neck/heretic_focus/moon_amulet/amulet = new(crewmate.drop_location())
var/static/list/slots = list(
LOCATION_NECK,
LOCATION_HANDS,
LOCATION_RPOCKET,
LOCATION_LPOCKET,
LOCATION_BACKPACK,
)
crewmate.equip_in_one_of_slots(amulet, slots, qdel_on_fail = FALSE)
crewmate.emote("laugh")
amount_of_lunatics++
if(attempt_conversion(crewmate, user))
amount_of_lunatics++
/datum/heretic_knowledge/ultimate/moon_final/proc/attempt_conversion(mob/living/carbon/convertee, mob/user)
// Heretics, lunatics and monsters shouldn't become lunatics because they either have a master or have a mansus grasp
if(IS_HERETIC_OR_MONSTER(convertee))
to_chat(convertee, span_boldwarning("[user]'s rise is influencing those who are weak willed. Their minds shall rend." ))
return FALSE
// Mindshielded and anti-magic folks are immune against this effect because this is a magical mind effect
if(HAS_MIND_TRAIT(convertee, TRAIT_UNCONVERTABLE) || convertee.can_block_magic(MAGIC_RESISTANCE))
to_chat(convertee, span_boldwarning("You feel shielded from something." ))
return FALSE
if(!convertee.mind)
return FALSE
var/datum/antagonist/lunatic/lunatic = convertee.mind.add_antag_datum(/datum/antagonist/lunatic)
lunatic.set_master(user.mind, user)
var/obj/item/clothing/neck/heretic_focus/moon_amulet/amulet = new(convertee.drop_location())
var/static/list/slots = list(
LOCATION_NECK,
LOCATION_HANDS,
LOCATION_RPOCKET,
LOCATION_LPOCKET,
LOCATION_BACKPACK,
)
convertee.equip_in_one_of_slots(amulet, slots, qdel_on_fail = FALSE)
INVOKE_ASYNC(convertee, TYPE_PROC_REF(/mob, emote), "laugh")
return TRUE
/datum/heretic_knowledge/ultimate/moon_final/proc/on_life(mob/living/source, seconds_per_tick, times_fired)
SIGNAL_HANDLER
visible_hallucination_pulse(
center = get_turf(source),
radius = 7,
hallucination_duration = 60 SECONDS
)
for(var/mob/living/carbon/carbon_view in view(5, source))
for(var/mob/living/carbon/carbon_view in range(7, source))
var/carbon_sanity = carbon_view.mob_mood.sanity
if(carbon_view.stat != CONSCIOUS)
continue
if(IS_HERETIC_OR_MONSTER(carbon_view))
continue
if(carbon_view.can_block_magic(MAGIC_RESISTANCE_MIND)) //Somehow a shitty piece of tinfoil is STILL able to hold out against the power of an ascended heretic.
if(carbon_view.can_block_magic(MAGIC_RESISTANCE_MOON)) //Somehow a shitty piece of tinfoil is STILL able to hold out against the power of an ascended heretic.
continue
new /obj/effect/temp_visual/moon_ringleader(get_turf(carbon_view))
if(carbon_view.has_status_effect(/datum/status_effect/confusion))
to_chat(carbon_view, span_big(span_hypnophrase("YOUR HEAD RATTLES WITH A THOUSAND VOICES JOINED IN A MADDENING CACOPHONY OF SOUND AND MUSIC. EVERY FIBER OF YOUR BEING SAYS 'RUN'.")))
carbon_view.adjust_confusion(2 SECONDS)
carbon_view.mob_mood.adjust_sanity(-5)
var/carbon_sanity = carbon_view.mob_mood.sanity
if(carbon_sanity < 30)
if(SPT_PROB(20, seconds_per_tick))
to_chat(carbon_view, span_warning("you feel your mind beginning to rend!"))
carbon_view.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
carbon_view.mob_mood.adjust_sanity(-20)
if(carbon_sanity < 10)
if(SPT_PROB(20, seconds_per_tick))
to_chat(carbon_view, span_warning("it echoes through you!"))
visible_hallucination_pulse(
center = get_turf(carbon_view),
radius = 7,
hallucination_duration = 50 SECONDS
)
carbon_view.adjust_temp_blindness(5 SECONDS)
if(carbon_sanity >= 10)
return
// So our sanity is dead, time to fuck em up
if(SPT_PROB(20, seconds_per_tick))
to_chat(carbon_view, span_warning("it echoes through you!"))
visible_hallucination_pulse(
center = get_turf(carbon_view),
radius = 7,
hallucination_duration = 50 SECONDS
)
carbon_view.adjust_temp_blindness(5 SECONDS)
if(should_mind_explode(carbon_view))
to_chat(carbon_view, span_boldbig(span_red(\
"YOUR SENSES REEL AS YOUR MIND IS ENVELOPED BY AN OTHERWORLDLY FORCE ATTEMPTING TO REWRITE YOUR VERY BEING. \
YOU CANNOT EVEN BEGIN TO SCREAM BEFORE YOUR IMPLANT ACTIVATES ITS PSIONIC FAIL-SAFE PROTOCOL, TAKING YOUR HEAD WITH IT.")))
var/obj/item/bodypart/head/head = locate() in carbon_view.bodyparts
if(head)
head.dismember()
else
carbon_view.gib(DROP_ALL_REMAINS)
var/datum/effect_system/reagents_explosion/explosion = new()
explosion.set_up(1, get_turf(carbon_view), TRUE, 0)
explosion.start(src)
else
attempt_conversion(carbon_view, source)
/datum/heretic_knowledge/ultimate/moon_final/proc/should_mind_explode(mob/living/carbon/target)
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
return TRUE
if(IS_CULTIST_OR_CULTIST_MOB(target))
return TRUE
return FALSE

View File

@@ -1,20 +1,53 @@
/datum/heretic_knowledge_tree_column/main/rust
neighbour_type_left = /datum/heretic_knowledge_tree_column/blade_to_rust
neighbour_type_right = /datum/heretic_knowledge_tree_column/rust_to_cosmic
/datum/heretic_knowledge_tree_column/rust
route = PATH_RUST
ui_bgr = "node_rust"
complexity = "Medium"
complexity_color = COLOR_YELLOW
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "rust_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Rust revolves around durability, corruption and brute forcing your way through obstacles.",
"Pick this path if you enjoy a standing your ground and letting the fight come to you.",
)
pros = list(
"Standing on rusted tiles makes you highly durable; regenerating wounds and removing stuns.",
"Rusted tiles harm your foes and slow them down.",
"You are able to destroy walls, objects, mechs, structures and airlocks with ease.",
"You can instantly obliterate silicons or synthetic crew members with your Mansus Grasp.",
"You have a high amount of disruption abilities to make it easier to fight in your territory.",
)
cons = list(
"Extremely overt; throws stealth completely out as an option.",
"If you are not on rusted tiles, you become significantly more vulnerable.",
"Being locked to a territorial conflict makes it much easier to use destructive tools (like bombs) against you.",
"Your high amount of defensive power is at the cost of offensive power.",
)
tips = list(
"Your Mansus Grasp will instantly destroy mechs, silicons and androids. Hitting a marked target with your blade will cause heavy disgust and make them vomit, knocking them down briefly.",
"Your Mansus Grasp and your spells are capable of rusting walls and floors, making them beneficial to you and harmful to the crew and silicons. Spread rust as much as possible.",
"Rusted turfs will heal you, regulate your blood temperature, make you resistant to batons knockdown, regenerate your stamina and blood and heal your wound and limbs once you level up your passive.",
"Always fight on your turf. Your opponent entering your turf are at a significant disadvantage.",
"Your Reassembled Raiment is only empowered while you are on your rusted tiles. If you want the most out of its power, stay on your rusted tiles.",
"Your ability to destroy objects and walls improves as your passive ugprade increases; eventually you will be able to melt through airlocks, reinforced walls and even titanium walls.",
"Spreading rust can be fairly slow, especially early on. Consider summoning a few rust walkers to help you expand your domain.",
"Rusted Construction allows you to produce barriers for cover or escape, or even block off someone else's escape in a pinch. Make the most of it to manipulate the environment to your needs.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_rust
grasp = /datum/heretic_knowledge/rust_fist
tier1 = /datum/heretic_knowledge/rust_regen
mark = /datum/heretic_knowledge/mark/rust_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/rust
unique_ability = /datum/heretic_knowledge/spell/rust_construction
tier2 = /datum/heretic_knowledge/spell/area_conversion
knowledge_tier1 = /datum/heretic_knowledge/spell/area_conversion
guaranteed_side_tier1 = /datum/heretic_knowledge/rust_sower
knowledge_tier2 = /datum/heretic_knowledge/spell/rust_construction
guaranteed_side_tier2 = /datum/heretic_knowledge/summon/rusty
robes = /datum/heretic_knowledge/armor/rust
knowledge_tier3 = /datum/heretic_knowledge/spell/entropic_plume
guaranteed_side_tier3 = /datum/heretic_knowledge/crucible
blade = /datum/heretic_knowledge/blade_upgrade/rust
tier3 = /datum/heretic_knowledge/spell/entropic_plume
knowledge_tier4 = /datum/heretic_knowledge/spell/rust_charge
ascension = /datum/heretic_knowledge/ultimate/rust_final
/datum/heretic_knowledge/limited_amount/starting/base_rust
@@ -30,34 +63,34 @@
result_atoms = list(/obj/item/melee/sickly_blade/rust)
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "rust_blade"
mark_type = /datum/status_effect/eldritch/rust
eldritch_passive = /datum/status_effect/heretic_passive/rust
/datum/heretic_knowledge/rust_fist
name = "Grasp of Rust"
desc = "Your Mansus Grasp will deal 500 damage to non-living matter and rust any surface it touches. \
Already rusted surfaces are destroyed. Surfaces and structures can only be rusted by using Right-Click. \
Allows you to rust basic iron walls and floors."
gain_text = "On the ceiling of the Mansus, rust grows as moss does on a stone."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_rust"
/datum/heretic_knowledge/rust_fist/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/limited_amount/starting/base_rust/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY, PROC_REF(on_secondary_mansus_grasp))
our_heretic.increase_rust_strength()
user.RemoveElement(/datum/element/leeching_walk/minor)
/datum/heretic_knowledge/rust_fist/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, list(COMSIG_HERETIC_MANSUS_GRASP_ATTACK, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY))
/datum/heretic_knowledge/limited_amount/starting/base_rust/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY)
user.AddElement(/datum/element/leeching_walk/minor)
/datum/heretic_knowledge/rust_fist/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_rust/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
for(var/obj/item/bodypart/robotic_limb as anything in carbon_target.bodyparts)
if(IS_ROBOTIC_LIMB(robotic_limb))
robotic_limb.receive_damage(500)
if(!issilicon(target) && !(target.mob_biotypes & MOB_ROBOTIC))
return
source.do_rust_heretic_act(target)
/datum/heretic_knowledge/rust_fist/proc/on_secondary_mansus_grasp(mob/living/source, atom/target)
/datum/heretic_knowledge/limited_amount/starting/base_rust/proc/on_secondary_mansus_grasp(mob/living/source, atom/target)
SIGNAL_HANDLER
// Rusting an airlock causes it to lose power, mostly to prevent the airlock from shocking you.
@@ -69,20 +102,14 @@
source.do_rust_heretic_act(target)
return COMPONENT_USE_HAND
/datum/heretic_knowledge/rust_regen
name = "Leeching Walk"
desc = "Grants you passive healing and resistance to batons while standing over rust."
gain_text = "The speed was unparalleled, the strength unnatural. The Blacksmith was smiling."
cost = 1
research_tree_icon_path = 'icons/effects/eldritch.dmi'
research_tree_icon_state = "cloud_swirl"
/datum/heretic_knowledge/spell/rust_charge
name = "Rust Charge"
desc = "A charge that must be started on a rusted tile and will destroy any rusted objects you come into contact with, will deal high damage to others and rust around you during the charge."
gain_text = "The hills sparkled now, as I neared them my mind began to wander. I quickly regained my resolve and pushed forward, this last leg would be the most treacherous."
/datum/heretic_knowledge/rust_regen/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
user.AddElement(/datum/element/leeching_walk)
/datum/heretic_knowledge/rust_regen/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
user.RemoveElement(/datum/element/leeching_walk)
action_to_add = /datum/action/cooldown/mob_cooldown/charge/rust
cost = 2
is_final_knowledge = TRUE
/datum/heretic_knowledge/mark/rust_mark
name = "Mark of Rust"
@@ -90,13 +117,6 @@
When triggered, your victim will suffer heavy disgust and confusion. \
Allows you to rust reinforced walls and floors as well as plasteel."
gain_text = "The Blacksmith looks away. To a place lost long ago. \"Rusted Hills help those in dire need... at a cost.\""
mark_type = /datum/status_effect/eldritch/rust
/datum/heretic_knowledge/mark/rust_mark/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
our_heretic.increase_rust_strength()
/datum/heretic_knowledge/knowledge_ritual/rust
/datum/heretic_knowledge/spell/rust_construction
name = "Rust Construction"
@@ -105,7 +125,21 @@
gain_text = "Images of foreign and ominous structures began to dance in my mind. Covered head to toe in thick rust, \
they no longer looked man made. Or perhaps they never were in the first place."
action_to_add = /datum/action/cooldown/spell/pointed/rust_construction
cost = 1
cost = 2
/datum/heretic_knowledge/armor/rust
desc = "Allows you to transmute a table (or a suit), a mask and any trash item to create a Salvaged Remains. \
Has extra armor, tackle resistance and syringe immunity while standing on rust. \
Acts as a focus while hooded."
gain_text = "From beneath warped scrap, the Blacksmith pulls forth an ancient fabric. \
\"Whatever this once stood for is lost. So now, we give it new purpose.\""
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/rust)
research_tree_icon_state = "rust_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
/obj/item/trash = 1,
)
/datum/heretic_knowledge/spell/area_conversion
name = "Aggressive Spread"
@@ -113,13 +147,9 @@
Already rusted surfaces are destroyed \ Also improves the rusting abilities of non rust-heretics."
gain_text = "All wise men know well not to visit the Rusted Hills... Yet the Blacksmith's tale was inspiring."
action_to_add = /datum/action/cooldown/spell/aoe/rust_conversion
cost = 1
cost = 2
research_tree_icon_frame = 5
/datum/heretic_knowledge/spell/area_conversion/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
our_heretic.increase_rust_strength(TRUE)
/datum/heretic_knowledge/blade_upgrade/rust
name = "Toxic Blade"
desc = "Your Rusty Blade now disgusts enemies on attack \ Allows you to rust Titanium and Plastitanium.."
@@ -128,10 +158,6 @@
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "blade_upgrade_rust"
/datum/heretic_knowledge/blade_upgrade/rust/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
our_heretic.increase_rust_strength()
/datum/heretic_knowledge/blade_upgrade/rust/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
if(source == target || !isliving(target))
return
@@ -139,6 +165,7 @@
/datum/heretic_knowledge/spell/area_conversion/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
. = ..()
/datum/heretic_knowledge/spell/entropic_plume
name = "Entropic Plume"
desc = "Grants you Entropic Plume, a spell that releases a vexing wave of Rust. \
@@ -148,14 +175,8 @@
The Blacksmith was gone, and you hold their blade. Champions of hope, the Rustbringer is nigh!"
action_to_add = /datum/action/cooldown/spell/cone/staggered/entropic_plume
cost = 1
/datum/heretic_knowledge/spell/entropic_plume/on_gain(mob/user)
. = ..()
var/datum/antagonist/heretic/our_heretic = GET_HERETIC(user)
our_heretic.increase_rust_strength(TRUE)
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/ultimate/rust_final
name = "Rustbringer's Oath"
@@ -234,7 +255,7 @@
for (var/iterator in 1 to greatest_dist)
if(!turfs_to_transform["[iterator]"])
continue
addtimer(CALLBACK(src, PROC_REF(transform_area), turfs_to_transform["[iterator]"]), (5 SECONDS) * iterator)
addtimer(CALLBACK(src, PROC_REF(transform_area), turfs_to_transform["[iterator]"]), (2 SECONDS) * iterator)
/datum/heretic_knowledge/ultimate/rust_final/proc/transform_area(list/turfs)
turfs = shuffle(turfs)
@@ -287,7 +308,7 @@
return
var/need_mob_update = FALSE
var/base_heal_amt = 2.5 * DELTA_WORLD_TIME(SSmobs)
var/base_heal_amt = 1 * DELTA_WORLD_TIME(SSmobs)
need_mob_update += source.adjustBruteLoss(-base_heal_amt, updating_health = FALSE)
need_mob_update += source.adjustFireLoss(-base_heal_amt, updating_health = FALSE)
need_mob_update += source.adjustToxLoss(-base_heal_amt, updating_health = FALSE, forced = TRUE)

View File

@@ -1,4 +1,6 @@
// Some general sidepath options.
/*!
* Contains the reroll targets knowledge perk
*/
/datum/heretic_knowledge/reroll_targets
name = "The Relentless Heartbeat"
@@ -13,9 +15,10 @@
cost = 1
research_tree_icon_path = 'icons/mob/actions/actions_animal.dmi'
research_tree_icon_state = "gaze"
is_shop_only = TRUE
drafting_tier = 2
/datum/heretic_knowledge/reroll_targets/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = GET_HERETIC(user)
// Check first if they have a Living Heart. If it's missing, we should
// throw a fail to show the heretic that there's no point in rerolling

View File

@@ -211,11 +211,11 @@
// Heads give 3 points, cultists give 1 point (and a special reward), normal sacrifices give 2 points.
heretic_datum.total_sacrifices++
if((sac_job_flag & JOB_HEAD_OF_STAFF))
heretic_datum.knowledge_points += 3
heretic_datum.adjust_knowledge_points(3)
heretic_datum.high_value_sacrifices++
feedback += " <i>graciously</i>"
if(cultist_datum)
heretic_datum.knowledge_points += 1
heretic_datum.adjust_knowledge_points(1)
grant_reward(user, sacrifice, loc)
// easier to read
var/rewards_given = heretic_datum.rewards_given
@@ -234,7 +234,7 @@
to_chat(user, non_flavor_warning)
return
else
heretic_datum.knowledge_points += 2
heretic_datum.adjust_knowledge_points(2)
to_chat(user, span_hypnophrase("[feedback]."))
if(!begin_sacrifice(sacrifice))
@@ -499,7 +499,7 @@
sac_target.clear_mood_event("shadow_realm")
if(IS_HERETIC(sac_target))
var/datum/antagonist/heretic/victim_heretic = sac_target.mind?.has_antag_datum(/datum/antagonist/heretic)
victim_heretic.knowledge_points -= 3
victim_heretic.adjust_knowledge_points(-3)
// Wherever we end up, we sure as hell won't be able to explain
sac_target.adjust_timed_status_effect(40 SECONDS, /datum/status_effect/speech/slurring/heretic)

View File

@@ -1,60 +0,0 @@
/datum/heretic_knowledge_tree_column/ash_to_moon
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/ash
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/moon
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/medallion
tier2 = /datum/heretic_knowledge/ether
tier3 = /datum/heretic_knowledge/summon/ashy
// Sidepaths for knowledge between Ash and Flesh.
/datum/heretic_knowledge/medallion
name = "Ashen Eyes"
desc = "Allows you to transmute a pair of eyes, a candle, and a glass shard into an Eldritch Medallion. \
The Eldritch Medallion grants you thermal vision while worn, and also functions as a focus."
gain_text = "Piercing eyes guided them through the mundane. Neither darkness nor terror could stop them."
required_atoms = list(
/obj/item/organ/eyes = 1,
/obj/item/shard = 1,
/obj/item/flashlight/flare/candle = 1,
)
result_atoms = list(/obj/item/clothing/neck/eldritch_amulet)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "eye_medalion"
/datum/heretic_knowledge/ether
name = "Ether Of The Newborn"
desc = "Transmutes a pool of vomit and a shard into a single use potion, drinking it will remove any sort of abnormality from your body including diseases, traumas and implants \
on top of restoring it to full health, at the cost of losing consciousness for an entire minute."
gain_text = "Vision and thought grow hazy as the fumes of this ichor swirl up to meet me. \
Through the haze, I find myself staring back in relief, or something grossly resembling my visage. \
It is this wretched thing that I consign to my fate, and whose own that I snatch through the haze of dreams. Fools that we are."
required_atoms = list(
/obj/item/shard = 1,
/obj/effect/decal/cleanable/vomit = 1,
)
result_atoms = list(/obj/item/ether)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "poison_flask"
/datum/heretic_knowledge/summon/ashy
name = "Ashen Ritual"
desc = "Allows you to transmute a head, a pile of ash, and a book to create an Ash Spirit. \
Ash Spirits have a short range jaunt and the ability to cause bleeding in foes at range. \
They also have the ability to create a ring of fire around themselves for a length of time."
gain_text = "I combined my principle of hunger with my desire for destruction. The Marshal knew my name, and the Nightwatcher gazed on."
required_atoms = list(
/obj/effect/decal/cleanable/ash = 1,
/obj/item/bodypart/head = 1,
/obj/item/book = 1,
)
mob_to_summon = /mob/living/basic/heretic_summon/ash_spirit
cost = 1
poll_ignore_define = POLL_IGNORE_ASH_SPIRIT

View File

@@ -1,136 +0,0 @@
/datum/heretic_knowledge_tree_column/blade_to_rust
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/blade
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/rust
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/armor
tier2 = list(/datum/heretic_knowledge/crucible, /datum/heretic_knowledge/rifle)
tier3 = list(/datum/heretic_knowledge/spell/rust_charge, /datum/heretic_knowledge/greaves_of_the_prophet)
// Sidepaths for knowledge between Rust and Blade.
/datum/heretic_knowledge/armor
name = "Armorer's Ritual"
desc = "Allows you to transmute a table and a gas mask to create Eldritch Armor. \
Eldritch Armor provides great protection while also acting as a focus when hooded."
gain_text = "The Rusted Hills welcomed the Blacksmith in their generosity. And the Blacksmith \
returned their generosity in kind."
required_atoms = list(
/obj/structure/table = 1,
/obj/item/clothing/mask/gas = 1,
)
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/clothing/suits/armor.dmi'
research_tree_icon_state = "eldritch_armor"
research_tree_icon_frame = 12
/datum/heretic_knowledge/crucible
name = "Mawed Crucible"
desc = "Allows you to transmute a portable water tank and a table to create a Mawed Crucible. \
The Mawed Crucible can brew powerful potions for combat and utility, but must be fed bodyparts and organs between uses."
gain_text = "This is pure agony. I wasn't able to summon the figure of the Aristocrat, \
but with the Priest's attention I stumbled upon a different recipe..."
required_atoms = list(
/obj/structure/reagent_dispensers/watertank = 1,
/obj/structure/table = 1,
)
result_atoms = list(/obj/structure/destructible/eldritch_crucible)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "crucible"
/datum/heretic_knowledge/rifle
name = "Lionhunter's Rifle"
desc = "Allows you to transmute a piece of wood, with hide \
from any animal,and a camera to create the Lionhunter's rifle. \
The Lionhunter's Rifle is a long ranged ballistic weapon with three shots. \
These shots function as normal, albeit weak high-caliber munitions when fired from \
close range or at inanimate objects. You can aim the rifle at distant foes, \
causing the shot to mark your victim with your grasp and teleport you directly to them."
gain_text = "I met an old man in an antique shop who wielded a very unusual weapon. \
I could not purchase it at the time, but they showed me how they made it ages ago."
required_atoms = list(
/obj/item/stack/sheet/mineral/wood = 1,
/obj/item/stack/sheet/animalhide = 1,
/obj/item/camera = 1,
)
result_atoms = list(/obj/item/gun/ballistic/rifle/lionhunter)
cost = 1
research_tree_icon_path = 'icons/obj/weapons/guns/ballistic.dmi'
research_tree_icon_state = "goldrevolver"
/datum/heretic_knowledge/rifle_ammo
name = "Lionhunter Rifle Ammunition"
desc = "Allows you to transmute 3 ballistic ammo casings (used or unused) of any caliber, \
including shotgun shells to create an extra clip of ammunition for the Lionhunter Rifle."
gain_text = "The weapon came with three rough iron balls, intended to be used as ammunition. \
They were very effective, for simple iron, but used up quickly. I soon ran out. \
No replacement munitions worked in their stead. It was peculiar in what it wanted."
required_atoms = list(
/obj/item/ammo_casing = 3,
)
result_atoms = list(/obj/item/ammo_box/speedloader/strilka310/lionhunter)
cost = 0
research_tree_icon_path = 'icons/obj/weapons/guns/ammo.dmi'
research_tree_icon_state = "310_strip"
/// A list of calibers that the ritual will deny. Only ballistic calibers are allowed.
var/static/list/caliber_blacklist = list(
CALIBER_LASER,
CALIBER_ENERGY,
CALIBER_FOAM,
CALIBER_ARROW,
CALIBER_HARPOON,
CALIBER_HOOK,
)
/datum/heretic_knowledge/rifle_ammo/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
for(var/obj/item/ammo_casing/casing in atoms)
if(!(casing.caliber in caliber_blacklist))
continue
// Remove any casings in the caliber_blacklist list from atoms
atoms -= casing
// We removed any invalid casings from the atoms list,
// return to allow the ritual to fill out selected atoms with the new list
return TRUE
/datum/heretic_knowledge/spell/rust_charge
name = "Rust Charge"
desc = "A charge that must be started on a rusted tile and will destroy any rusted objects you come into contact with, will deal high damage to others and rust around you during the charge."
gain_text = "The hills sparkled now, as I neared them my mind began to wander. I quickly regained my resolve and pushed forward, this last leg would be the most treacherous."
action_to_add = /datum/action/cooldown/mob_cooldown/charge/rust
cost = 1
/datum/heretic_knowledge/greaves_of_the_prophet
name = "Greaves Of The Prophet"
desc = "Allows you to combine a pair of Jackboots and 2 sheets of Titanium into a pair of Armored Greaves, they confer to the user fully immunity to slips."
gain_text = " \
Gristle churns into joint, a pop, and the fool twists a blackened foot from the \
jaws of another. At their game for centuries, this mangled tree of limbs twists, \
thrashing snares buried into snarling gums, seeking to shred the weight of grafted \
neighbors. Weighed down by lacerated feet, this canopy of rancid idiots ever seeks \
the undoing of its own bonds. I dread the thought of walking in their wake, but \
I must press on all the same. Their rhythms keep the feud fresh with indifference \
to barrier or border. Pulling more into their turmoil as they waltz."
cost = 1
required_atoms = list(
/obj/item/clothing/shoes/jackboots = 1,
/obj/item/stack/sheet/mineral/titanium = 2,
)
result_atoms = list(/obj/item/clothing/shoes/greaves_of_the_prophet)
research_tree_icon_path = 'icons/obj/clothing/shoes.dmi'
research_tree_icon_state = "hereticgreaves"

View File

@@ -1,62 +0,0 @@
/datum/heretic_knowledge_tree_column/cosmic_to_ash
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/cosmic
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/ash
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/summon/fire_shark
tier2 = /datum/heretic_knowledge/spell/space_phase
tier3 = /datum/heretic_knowledge/eldritch_coin
// Sidepaths for knowledge between Cosmos and Ash.
/datum/heretic_knowledge/summon/fire_shark
name = "Scorching Shark"
desc = "Allows you to transmute a pool of ash, a liver, and a sheet of plasma into a Fire Shark. \
Fire Sharks are fast and strong in groups, but die quickly. They are also highly resistant against fire attacks. \
Fire Sharks inject phlogiston into its victims and spawn plasma once they die."
gain_text = "The cradle of the nebula was cold, but not dead. Light and heat flits even through the deepest darkness, and is hunted by its own predators."
required_atoms = list(
/obj/effect/decal/cleanable/ash = 1,
/obj/item/organ/liver = 1,
/obj/item/stack/sheet/mineral/plasma = 1,
)
mob_to_summon = /mob/living/basic/heretic_summon/fire_shark
cost = 1
poll_ignore_define = POLL_IGNORE_FIRE_SHARK
research_tree_icon_dir = EAST
/datum/heretic_knowledge/spell/space_phase
name = "Space Phase"
desc = "Grants you Space Phase, a spell that allows you to move freely through space. \
You can only phase in and out when you are on a space or misc turf."
gain_text = "You feel like your body can move through space as if you where dust."
action_to_add = /datum/action/cooldown/spell/jaunt/space_crawl
cost = 1
research_tree_icon_frame = 6
/datum/heretic_knowledge/eldritch_coin
name = "Eldritch Coin"
desc = "Allows you to transmute a sheet of plasma and a diamond to create an Eldritch Coin. \
The coin will open or close nearby doors when landing on heads and toggle their bolts \
when landing on tails. If you insert the coin into an airlock, it will be consumed \
to fry its electronics, opening the airlock permanently unless bolted. "
gain_text = "The Mansus is a place of all sorts of sins. But greed held a special role."
required_atoms = list(
/obj/item/stack/sheet/mineral/diamond = 1,
/obj/item/stack/sheet/mineral/plasma = 1,
)
result_atoms = list(/obj/item/coin/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/economy.dmi'
research_tree_icon_state = "coin_heretic"

View File

@@ -1,63 +0,0 @@
/datum/heretic_knowledge_tree_column/flesh_to_void
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/flesh
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/void
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/void_cloak
tier2 = /datum/heretic_knowledge/spell/blood_siphon
tier3 = list(/datum/heretic_knowledge/spell/void_prison, /datum/heretic_knowledge/spell/cleave)
// Sidepaths for knowledge between Flesh and Void.
/datum/heretic_knowledge/void_cloak
name = "Void Cloak"
desc = "Allows you to transmute a glass shard, a bedsheet, and any outer clothing item (such as armor or a suit jacket) \
to create a Void Cloak. While the hood is down, the cloak functions as a focus, \
and while the hood is up, the cloak is completely invisible. It also provide decent armor and \
has pockets which can hold one of your blades, various ritual components (such as organs), and small heretical trinkets."
gain_text = "The Owl is the keeper of things that are not quite in practice, but in theory are. Many things are."
required_atoms = list(
/obj/item/shard = 1,
/obj/item/clothing/suit = 1,
/obj/item/bedsheet = 1,
)
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/void)
cost = 1
research_tree_icon_path = 'icons/obj/clothing/suits/armor.dmi'
research_tree_icon_state = "void_cloak"
/datum/heretic_knowledge/spell/blood_siphon
name = "Blood Siphon"
desc = "Grants you Blood Siphon, a spell that drains a victim of blood and health, transferring it to you. \
Also has a chance to transfer wounds from you to the victim."
gain_text = "\"No matter the man, we bleed all the same.\" That's what the Marshal told me."
action_to_add = /datum/action/cooldown/spell/pointed/blood_siphon
cost = 1
/datum/heretic_knowledge/spell/void_prison
name = "Void Prison"
desc = "Grants you Void Prison, a spell that places your victim into ball, making them unable to do anything or speak. \
Applies void chill afterwards."
gain_text = "At first, I see myself, waltzing along a snow-laden street. \
I try to yell, grab hold of this fool and tell them to run. \
But the only welts made are on my own beating fist. \
My smiling face turns to regard me, reflecting back in glassy eyes the empty path I have been lead down."
action_to_add = /datum/action/cooldown/spell/pointed/void_prison
cost = 1
/datum/heretic_knowledge/spell/cleave
name = "Blood Cleave"
desc = "Grants you Cleave, an area-of-effect targeted spell \
that causes heavy bleeding and blood loss to anyone afflicted."
gain_text = "At first I didn't understand these instruments of war, but the Priest \
told me to use them regardless. Soon, he said, I would know them well."
action_to_add = /datum/action/cooldown/spell/pointed/cleave
cost = 1

View File

@@ -0,0 +1,121 @@
/*!
* Tier 4 knowledge: Combat related knowledge
*/
/datum/heretic_knowledge/spell/space_phase
name = "Space Phase"
desc = "Grants you Space Phase, a spell that allows you to move freely through space. \
You can only phase in and out when you are on a space or misc turf."
gain_text = "You feel like your body can move through space as if you where dust."
action_to_add = /datum/action/cooldown/spell/jaunt/space_crawl
cost = 2
research_tree_icon_frame = 6
drafting_tier = 4
/datum/heretic_knowledge/unfathomable_curio
name = "Unfathomable Curio"
desc = "Allows you to transmute 3 rods, lungs and any belt into an Unfathomable Curio, \
a belt that can hold blades and items for rituals. Whilst worn it will also \
veil you, allowing you to take 5 hits without suffering damage, this veil will recharge very slowly \
outside of combat."
gain_text = "The mansus holds many a curio, some are not meant for the mortal eye."
required_atoms = list(
/obj/item/organ/lungs = 1,
/obj/item/stack/rods = 3,
/obj/item/storage/belt = 1,
)
result_atoms = list(/obj/item/storage/belt/unfathomable_curio)
cost = 2
research_tree_icon_path = 'icons/obj/clothing/belts.dmi'
research_tree_icon_state = "unfathomable_curio"
drafting_tier = 4
/datum/heretic_knowledge/rust_sower
name = "Rust Sower Grenade"
desc = "Allows you to combine a chemical grenade casing and some moldy food to conjure a cursed grenade filled with Eldritch Rust, upon detonating it releases a huge cloud that blinds organics, rusts affected turfs and obliterates Silicons and Mechs."
gain_text = "The choked vines of the Rusted Hills are burdened with such overripe fruits. It undoes the markers of progress, leaving a clean slate to work into new shapes."
required_atoms = list(
list(
/obj/item/food/breadslice/moldy,
/obj/item/food/badrecipe/moldy,
/obj/item/food/deadmouse/moldy,
/obj/item/food/pizzaslice/moldy,
/obj/item/food/boiledegg/rotten,
/obj/item/food/egg/rotten
) = 1,
/obj/item/grenade/chem_grenade = 1
)
result_atoms = list(/obj/item/grenade/chem_grenade/rust_sower)
cost = 2
research_tree_icon_path = 'icons/obj/weapons/grenade.dmi'
research_tree_icon_state = "rustgrenade"
drafting_tier = 4
/datum/heretic_knowledge/spell/crimson_cleave
name = "Crimson Cleave"
desc = "Grants you Crimson Cleave, a targeted spell which siphons health in a small AOE. Cleanses all wounds upon casting"
gain_text = "At first I didn't understand these instruments of war, but the Priest \
told me to use them regardless. Soon, he said, I would know them well."
action_to_add = /datum/action/cooldown/spell/pointed/crimson_cleave
cost = 2
drafting_tier = 4
/datum/heretic_knowledge/rifle
name = "Lionhunter's Rifle"
desc = "Allows you to transmute a piece of wood, with hide \
from any animal, and a camera to create the Lionhunter's rifle. \
The Lionhunter's Rifle is a long ranged ballistic weapon with three shots. \
These shots function as normal, albeit weak high-caliber munitions when fired from \
close range or at inanimate objects. You can aim the rifle at distant foes, \
causing the shot to mark your victim with your grasp and teleport you directly to them."
gain_text = "I met an old man in an antique shop who wielded a very unusual weapon. \
I could not purchase it at the time, but they showed me how they made it ages ago."
required_atoms = list(
/obj/item/stack/sheet/mineral/wood = 1,
/obj/item/stack/sheet/animalhide = 1,
/obj/item/camera = 1,
)
result_atoms = list(/obj/item/gun/ballistic/rifle/lionhunter)
cost = 2
research_tree_icon_path = 'icons/obj/weapons/guns/ballistic.dmi'
research_tree_icon_state = "goldrevolver"
drafting_tier = 2
/datum/heretic_knowledge/rifle_ammo
name = "Lionhunter Rifle Ammunition"
desc = "Allows you to transmute 3 ballistic ammo casings (used or unused) of any caliber, \
including shotgun shells to create an extra clip of ammunition for the Lionhunter Rifle."
gain_text = "The weapon came with three rough iron balls, intended to be used as ammunition. \
They were very effective, for simple iron, but used up quickly. I soon ran out. \
No replacement munitions worked in their stead. It was peculiar in what it wanted."
required_atoms = list(
/obj/item/ammo_casing = 3,
)
result_atoms = list(/obj/item/ammo_box/speedloader/strilka310/lionhunter)
cost = 0
research_tree_icon_path = 'icons/obj/weapons/guns/ammo.dmi'
research_tree_icon_state = "310_strip"
/// A list of calibers that the ritual will deny. Only ballistic calibers are allowed.
var/static/list/caliber_blacklist = list(
CALIBER_LASER,
CALIBER_ENERGY,
CALIBER_FOAM,
CALIBER_ARROW,
CALIBER_HARPOON,
CALIBER_HOOK,
)
/datum/heretic_knowledge/rifle_ammo/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
for(var/obj/item/ammo_casing/casing in atoms)
if(!(casing.caliber in caliber_blacklist))
continue
// Remove any casings in the caliber_blacklist list from atoms
atoms -= casing
// We removed any invalid casings from the atoms list,
// return to allow the ritual to fill out selected atoms with the new list
return TRUE

View File

@@ -0,0 +1,102 @@
/*!
* Tier 1 knowledge: Stealth and general utility
*/
/datum/heretic_knowledge/void_cloak
name = "Void Cloak"
desc = "Allows you to transmute a glass shard, a bedsheet, and any outer clothing item (such as armor or a suit jacket) \
to create a Void Cloak. While the hood is down, the cloak functions as a focus and protects you from space. \
While the hood is up, the cloak is completely invisible. It also provide decent armor and \
has pockets which can hold one of your blades, various ritual components (such as organs), and small heretical trinkets."
gain_text = "The Owl is the keeper of things that are not quite in practice, but in theory are. Many things are."
required_atoms = list(
/obj/item/shard = 1,
/obj/item/clothing/suit = 1,
/obj/item/bedsheet = 1,
)
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/void)
cost = 1
research_tree_icon_path = 'icons/obj/clothing/suits/armor.dmi'
research_tree_icon_state = "void_cloak"
drafting_tier = 1
/datum/heretic_knowledge/medallion
name = "Ashen Eyes"
desc = "Allows you to transmute a pair of eyes, a candle, and a glass shard into an Eldritch Medallion. \
The Eldritch Medallion grants you thermal vision while worn, and also functions as a focus."
gain_text = "Piercing eyes guided them through the mundane. Neither darkness nor terror could stop them."
required_atoms = list(
/obj/item/organ/eyes = 1,
/obj/item/shard = 1,
/obj/item/flashlight/flare/candle = 1,
)
result_atoms = list(/obj/item/clothing/neck/eldritch_amulet)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "eye_medalion"
drafting_tier = 1
/datum/heretic_knowledge/essence // AKA Eldritch Flask
name = "Priest's Ritual"
desc = "Allows you to transmute a tank of water and a glass shard into a Flask of Eldritch Essence. \
Eldritch Essence can be consumed for potent healing, or given to heathens for deadly poisoning."
gain_text = "This is an old recipe. The Owl whispered it to me. \
Created by the Priest - the Liquid that both was and is not."
required_atoms = list(
/obj/structure/reagent_dispensers/watertank = 1,
/obj/item/shard = 1,
)
result_atoms = list(/obj/item/reagent_containers/cup/beaker/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "eldritch_flask"
drafting_tier = 1
/datum/heretic_knowledge/phylactery
name = "Phylactery of Damnation"
desc = "Allows you to transmute a sheet of glass and a poppy into a Phylactery that can instantly draw blood, even from long distances. \
Be warned, your target may still feel a prick."
gain_text = "A tincture twisted into the shape of a bloodsucker vermin. \
Whether it chose the shape for itself, or this is the humor of the sickened mind that conjured this vile implement into being is something best not pondered."
required_atoms = list(
/obj/item/stack/sheet/glass = 1,
/obj/item/food/grown/poppy = 1,
)
result_atoms = list(/obj/item/reagent_containers/cup/phylactery)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "phylactery_2"
drafting_tier = 1
/datum/heretic_knowledge/crucible
name = "Mawed Crucible"
desc = "Allows you to transmute a portable water tank and a table to create a Mawed Crucible. \
The Mawed Crucible can brew powerful potions for combat and utility, but must be fed bodyparts and organs between uses."
gain_text = "This is pure agony. I wasn't able to summon the figure of the Aristocrat, \
but with the Priest's attention I stumbled upon a different recipe..."
required_atoms = list(
/obj/structure/reagent_dispensers/watertank = 1,
/obj/structure/table = 1,
)
result_atoms = list(/obj/structure/destructible/eldritch_crucible)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "crucible"
drafting_tier = 1
/datum/heretic_knowledge/eldritch_coin
name = "Eldritch Coin"
desc = "Allows you to transmute a sheet of plasma and a diamond to create an Eldritch Coin. \
The coin will open or close nearby doors when landing on heads and toggle their bolts \
when landing on tails. If you insert the coin into an airlock, it will be consumed \
to fry its electronics, opening the airlock permanently unless bolted. "
gain_text = "The Mansus is a place of all sorts of sins. But greed held a special role."
required_atoms = list(
/obj/item/stack/sheet/mineral/diamond = 1,
/obj/item/stack/sheet/mineral/plasma = 1,
)
result_atoms = list(/obj/item/coin/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/economy.dmi'
research_tree_icon_state = "coin_heretic"
drafting_tier = 1

View File

@@ -1,16 +1,58 @@
// Sidepaths for knowledge between Void and Blade.
/*!
* Tier 3 knowledge: Summons
*/
/datum/heretic_knowledge_tree_column/void_to_blade
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/void
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/blade
/datum/heretic_knowledge/summon/rusty
name = "Rusted Ritual"
desc = "Allows you to transmute a pool of vomit, some cable coil, and 10 sheets of iron into a Rust Walker. \
Rust Walkers excel at spreading rust and are moderately strong in combat."
gain_text = "I combined my knowledge of creation with my desire for corruption. The Marshal knew my name, and the Rusted Hills echoed out."
required_atoms = list(
/obj/effect/decal/cleanable/vomit = 1,
/obj/item/stack/sheet/iron = 10,
/obj/item/stack/cable_coil = 15,
)
mob_to_summon = /mob/living/basic/heretic_summon/rust_walker
cost = 2
poll_ignore_define = POLL_IGNORE_RUST_SPIRIT
drafting_tier = 3
route = PATH_SIDE
/datum/heretic_knowledge/summon/maid_in_mirror
name = "Maid in the Mirror"
desc = "Allows you to transmute five sheets of glass, any suit, and a pair of lungs to create a Maid in the Mirror. \
Maid in the Mirrors are decent combatants that can become incorporeal by phasing in and out of the mirror realm, serving as powerful scouts and ambushers. \
Their attacks also apply a stack of void chill."
gain_text = "Within each reflection, lies a gateway into an unimaginable world of colors never seen and \
people never met. The ascent is glass, and the walls are knives. Each step is blood, if you do not have a guide."
tier1 = /datum/heretic_knowledge/limited_amount/risen_corpse
tier2 = /datum/heretic_knowledge/rune_carver
tier3 = /datum/heretic_knowledge/summon/maid_in_mirror
required_atoms = list(
/obj/item/stack/sheet/glass = 5,
/obj/item/clothing/suit = 1,
/obj/item/organ/lungs = 1,
)
cost = 2
mob_to_summon = /mob/living/basic/heretic_summon/maid_in_the_mirror
poll_ignore_define = POLL_IGNORE_MAID_IN_MIRROR
drafting_tier = 3
/datum/heretic_knowledge/summon/ashy
name = "Ashen Ritual"
desc = "Allows you to transmute a Bonfire and a book to create an Ash Spirit. \
Ash Spirits have a short range jaunt and the ability to cause bleeding in foes at range. \
They also have the ability to create a ring of fire around themselves for a length of time. \
They have a low amount of health, but will passively recover given enough time to do so."
gain_text = "I combined my principle of hunger with my desire for destruction. The Marshal knew my name, and the Nightwatcher gazed on."
required_atoms = list(
/obj/effect/decal/cleanable/ash = 1,
/obj/item/book = 1,
/obj/structure/bonfire = 1,
)
mob_to_summon = /mob/living/basic/heretic_summon/ash_spirit
cost = 2
poll_ignore_define = POLL_IGNORE_ASH_SPIRIT
drafting_tier = 3
/// The max health given to Shattered Risen
#define RISEN_MAX_HEALTH 125
@@ -30,11 +72,10 @@
/obj/item/clothing/gloves/latex = 1,
)
limit = 1
cost = 1
cost = 2
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "ghoul_shattered"
drafting_tier = 3
/datum/heretic_knowledge/limited_amount/risen_corpse/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
. = ..()
@@ -116,43 +157,22 @@
demolition_mod = 1.5
sharpness = SHARP_EDGED
/datum/heretic_knowledge/rune_carver
name = "Carving Knife"
desc = "Allows you to transmute a knife, a shard of glass, and a piece of paper to create a Carving Knife. \
The Carving Knife allows you to etch difficult to see traps that trigger on heathens who walk overhead. \
Also makes for a handy throwing weapon."
gain_text = "Etched, carved... eternal. There is power hidden in everything. I can unveil it! \
I can carve the monolith to reveal the chains!"
/datum/heretic_knowledge/summon/fire_shark
name = "Scorching Shark"
desc = "Allows you to transmute a pool of ash, a liver, and a sheet of plasma into a Fire Shark. \
Fire Sharks are fast and strong in groups, but die quickly. They are also highly resistant against fire attacks. \
Fire Sharks inject phlogiston into its victims and spawn plasma once they die."
gain_text = "The cradle of the nebula was cold, but not dead. Light and heat flits even through the deepest darkness, and is hunted by its own predators."
required_atoms = list(
/obj/item/knife = 1,
/obj/item/shard = 1,
/obj/item/paper = 1,
/obj/effect/decal/cleanable/ash = 1,
/obj/item/organ/liver = 1,
/obj/item/stack/sheet/mineral/plasma = 1,
)
result_atoms = list(/obj/item/melee/rune_carver)
cost = 1
mob_to_summon = /mob/living/basic/heretic_summon/fire_shark
cost = 2
poll_ignore_define = POLL_IGNORE_FIRE_SHARK
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "rune_carver"
/datum/heretic_knowledge/summon/maid_in_mirror
name = "Maid in the Mirror"
desc = "Allows you to transmute five sheets of titanium, a flash, a suit of armor, and a pair of lungs \
to create a Maid in the Mirror. Maid in the Mirrors are decent combatants that can become incorporeal by \
phasing in and out of the mirror realm, serving as powerful scouts and ambushers. \
However, they are weak to mortal gaze and take damage by being examined."
gain_text = "Within each reflection, lies a gateway into an unimaginable world of colors never seen and \
people never met. The ascent is glass, and the walls are knives. Each step is blood, if you do not have a guide."
required_atoms = list(
/obj/item/stack/sheet/mineral/titanium = 5,
/obj/item/clothing/suit/armor = 1,
/obj/item/assembly/flash = 1,
/obj/item/organ/lungs = 1,
)
cost = 1
mob_to_summon = /mob/living/basic/heretic_summon/maid_in_the_mirror
poll_ignore_define = POLL_IGNORE_MAID_IN_MIRROR
research_tree_icon_dir = EAST
drafting_tier = 3

View File

@@ -1,44 +1,107 @@
/datum/heretic_knowledge_tree_column/moon_to_lock
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/moon
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/lock
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/spell/mind_gate
tier2 = list(/datum/heretic_knowledge/unfathomable_curio, /datum/heretic_knowledge/painting)
tier3 = /datum/heretic_knowledge/codex_morbus
// Sidepaths for knowledge between Knock and Moon.
/datum/heretic_knowledge/spell/mind_gate
name = "Mind Gate"
desc = "Grants you Mind Gate, a spell which inflicts hallucinations, \
confusion, oxygen loss and brain damage to its target over 10 seconds.\
The caster takes 20 brain damage per use."
gain_text = "My mind swings open like a gate, and its insight will let me perceive the truth."
action_to_add = /datum/action/cooldown/spell/pointed/mind_gate
cost = 1
/datum/heretic_knowledge/unfathomable_curio
name = "Unfathomable Curio"
desc = "Allows you to transmute 3 rods, lungs and any belt into an Unfathomable Curio, \
a belt that can hold blades and items for rituals. Whilst worn it will also \
veil you, allowing you to take 5 hits without suffering damage, this veil will recharge very slowly \
outside of combat."
gain_text = "The mansus holds many a curio, some are not meant for the mortal eye."
/*!
* Tier 2 knowledge: Defensive tools and curses
*/
/**
* Codex Morbus, an upgrade to the base codex
* Functionally an upgraded version of the codex, but it also has the ability to cast curses by right clicking at a rune.
* Requires you to have the blood of your victim in your off-hand
*/
/datum/heretic_knowledge/codex_morbus
name = "Codex Morbus"
desc = "Allows you to to combine a codex cicatrix, and a body into a Codex Morbus. \
It draws runes and siphons essences a bit faster. \
Right Click on a rune to curse crewmembers, the target's blood is required in your off hand for a curse to take effect (Best combined with Phylactery Of Damnation)."
gain_text = "The spine of this leather-bound tome creaks with an eerily pained sigh. \
To ply page from place takes considerable effort, and I dare not linger on the suggestions the book makes for longer than necessary. \
It speaks of coming plagues, of waiting supplicants of dead and forgotten gods, and the undoing of mortal kind. \
It speaks of needles to peel the skin of the world back and leaving it to fester. And it speaks to me by name."
required_atoms = list(
/obj/item/organ/lungs = 1,
/obj/item/stack/rods = 3,
/obj/item/storage/belt = 1,
/obj/item/codex_cicatrix = 1,
/mob/living/carbon/human = 1,
)
result_atoms = list(/obj/item/storage/belt/unfathomable_curio)
cost = 1
result_atoms = list(/obj/item/codex_cicatrix/morbus)
cost = 2
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "book_morbus"
drafting_tier = 2
research_tree_icon_path = 'icons/obj/clothing/belts.dmi'
research_tree_icon_state = "unfathomable_curio"
/datum/heretic_knowledge/codex_morbus/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
. = ..()
var/mob/living/carbon/human/to_fuck_up = locate() in selected_atoms
for(var/_limb in to_fuck_up.bodyparts)
var/obj/item/bodypart/limb = _limb
limb.force_wound_upwards(/datum/wound/slash/flesh/critical)
for(var/obj/item/bodypart/limb as anything in to_fuck_up.bodyparts)
to_fuck_up.cause_wound_of_type_and_severity(WOUND_BLUNT, limb, WOUND_SEVERITY_CRITICAL)
return TRUE
/datum/heretic_knowledge/greaves_of_the_prophet
name = "Greaves Of The Prophet"
desc = "Allows you to combine a pair of shoes and 2 sheets of titanium or silver into a pair of Armored Greaves, they confer to the user full immunity to slips."
gain_text = " \
Gristle churns into joint, a pop, and the fool twists a blackened foot from the \
jaws of another. At their game for centuries, this mangled tree of limbs twists, \
thrashing snares buried into snarling gums, seeking to shred the weight of grafted \
neighbors. Weighed down by lacerated feet, this canopy of rancid idiots ever seeks \
the undoing of its own bonds. I dread the thought of walking in their wake, but \
I must press on all the same. Their rhythms keep the feud fresh with indifference \
to barrier or border. Pulling more into their turmoil as they waltz."
required_atoms = list(
/obj/item/clothing/shoes = 1,
list(/obj/item/stack/sheet/mineral/titanium, /obj/item/stack/sheet/mineral/silver) = 2,
)
result_atoms = list(/obj/item/clothing/shoes/greaves_of_the_prophet)
cost = 2
research_tree_icon_path = 'icons/obj/clothing/shoes.dmi'
research_tree_icon_state = "hereticgreaves"
drafting_tier = 2
/datum/heretic_knowledge/spell/opening_blast
name = "Wave Of Desperation"
desc = "Grants you Wave Of Desparation, a spell which can only be cast while restrained. \
It removes your restraints, repels and knocks down adjacent people, and applies the Mansus Grasp to everything nearby. \
However, you will fall unconscious a short time after casting this spell."
gain_text = "My shackles undone in dark fury, their feeble bindings crumble before my power."
action_to_add = /datum/action/cooldown/spell/aoe/wave_of_desperation
cost = 2
drafting_tier = 2
/datum/heretic_knowledge/rune_carver
name = "Carving Knife"
desc = "Allows you to transmute a knife, a shard of glass, and a piece of paper to create a Carving Knife. \
The Carving Knife allows you to etch difficult to see traps that trigger on heathens who walk overhead. \
Also makes for a handy throwing weapon."
gain_text = "Etched, carved... eternal. There is power hidden in everything. I can unveil it! \
I can carve the monolith to reveal the chains!"
required_atoms = list(
/obj/item/knife = 1,
/obj/item/shard = 1,
/obj/item/paper = 1,
)
result_atoms = list(/obj/item/melee/rune_carver)
cost = 2
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "rune_carver"
drafting_tier = 2
/datum/heretic_knowledge/ether
name = "Ether Of The Newborn"
desc = "Transmutes a pool of vomit and a shard into a single use potion, drinking it will remove any sort of abnormality from your body including diseases, traumas and implants \
on top of restoring it to full health, at the cost of losing consciousness for an entire minute."
gain_text = "Vision and thought grow hazy as the fumes of this ichor swirl up to meet me. \
Through the haze, I find myself staring back in relief, or something grossly resembling my visage. \
It is this wretched thing that I consign to my fate, and whose own that I snatch through the haze of dreams. Fools that we are."
required_atoms = list(
/obj/item/shard = 1,
/obj/effect/decal/cleanable/vomit = 1,
)
result_atoms = list(/obj/item/ether)
cost = 2
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "poison_flask"
drafting_tier = 2
/datum/heretic_knowledge/painting
name = "Unsealed Arts"
@@ -51,14 +114,12 @@
Master of the Rusted Mountain: Requires a piece of Trash. Curses non-heretics to rust the floor they walk on."
gain_text = "A wind of inspiration blows through me. Beyond the veil and past the gate great works exist, yet to be painted. \
They yearn for mortal eyes, so I shall give them an audience."
required_atoms = list(/obj/item/canvas = 1)
result_atoms = list(/obj/item/canvas)
cost = 1
cost = 2
research_tree_icon_path = 'icons/obj/signs.dmi'
research_tree_icon_state = "eldritch_painting_weeping"
drafting_tier = 2
/datum/heretic_knowledge/painting/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
if(locate(/obj/item/organ/eyes) in atoms)
@@ -103,36 +164,3 @@
user.balloon_alert(user, "no additional atom present!")
return FALSE
/**
* Codex Morbus, an upgrade to the base codex
* Functionally an upgraded version of the codex, but it also has the ability to cast curses by right clicking at a rune.
* Requires you to have the blood of your victim in your off-hand
*/
/datum/heretic_knowledge/codex_morbus
name = "Codex Morbus"
desc = "Allows you to to combine a codex cicatrix, and a body into a Codex Morbus. \
It draws runes and siphons essences a bit faster. \
Right Click on a rune to curse crewmembers, the target's blood is required in your off hand for a curse to take effect (Best combined with Phylactery Of Damnation)."
gain_text = "The spine of this leather-bound tome creaks with an eerily pained sigh. \
To ply page from place takes considerable effort, and I dare not linger on the suggestions the book makes for longer than necessary. \
It speaks of coming plagues, of waiting supplicants of dead and forgotten gods, and the undoing of mortal kind. \
It speaks of needles to peel the skin of the world back and leaving it to fester. And it speaks to me by name."
required_atoms = list(
/obj/item/codex_cicatrix = 1,
/mob/living/carbon/human = 1,
)
result_atoms = list(/obj/item/codex_cicatrix/morbus)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "book_morbus"
/datum/heretic_knowledge/codex_morbus/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
. = ..()
var/mob/living/carbon/human/to_fuck_up = locate() in selected_atoms
for(var/_limb in to_fuck_up.bodyparts)
var/obj/item/bodypart/limb = _limb
limb.force_wound_upwards(/datum/wound/slash/flesh/critical)
for(var/obj/item/bodypart/limb as anything in to_fuck_up.bodyparts)
to_fuck_up.cause_wound_of_type_and_severity(WOUND_BLUNT, limb, WOUND_SEVERITY_CRITICAL)
return TRUE

View File

@@ -1,50 +0,0 @@
/datum/heretic_knowledge_tree_column/lock_to_flesh
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/lock
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/flesh
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/phylactery
tier2 = /datum/heretic_knowledge/spell/opening_blast
tier3 = /datum/heretic_knowledge/spell/apetra_vulnera
/**
* Phylactery of Damnation
*/
/datum/heretic_knowledge/phylactery
name = "Phylactery of Damnation"
desc = "Allows you to transmute a sheet of glass and a poppy into a Phylactery that can instantly draw blood, even from long distances. \
Be warned, your target may still feel a prick."
gain_text = "A tincture twisted into the shape of a bloodsucker vermin. \
Whether it chose the shape for itself, or this is the humor of the sickened mind that conjured this vile implement into being is something best not pondered."
required_atoms = list(
/obj/item/stack/sheet/glass = 1,
/obj/item/food/grown/poppy = 1,
)
result_atoms = list(/obj/item/reagent_containers/cup/phylactery)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "phylactery_2"
// Sidepaths for knowledge between Knock and Flesh.
/datum/heretic_knowledge/spell/opening_blast
name = "Wave Of Desperation"
desc = "Grants you Wave Of Desparation, a spell which can only be cast while restrained. \
It removes your restraints, repels and knocks down adjacent people, and applies the Mansus Grasp to everything nearby. \
However, you will fall unconscious a short time after casting this spell."
gain_text = "My shackles undone in dark fury, their feeble bindings crumble before my power."
action_to_add = /datum/action/cooldown/spell/aoe/wave_of_desperation
cost = 1
/datum/heretic_knowledge/spell/apetra_vulnera
name = "Apetra Vulnera"
desc = "Grants you Apetra Vulnera, a spell \
which causes heavy bleeding on all bodyparts of the victim that have more than 15 brute damage. \
Wounds a random limb if no limb is sufficiently damaged."
gain_text = "Flesh opens, and blood spills. My master seeks sacrifice, and I shall appease."
action_to_add = /datum/action/cooldown/spell/pointed/apetra_vulnera
cost = 1

View File

@@ -1,87 +0,0 @@
/datum/heretic_knowledge_tree_column/rust_to_cosmic
neighbour_type_left = /datum/heretic_knowledge_tree_column/main/rust
neighbour_type_right = /datum/heretic_knowledge_tree_column/main/cosmic
route = PATH_SIDE
tier1 = /datum/heretic_knowledge/essence
tier2 = list(/datum/heretic_knowledge/entropy_pulse, /datum/heretic_knowledge/rust_sower)
tier3 = /datum/heretic_knowledge/summon/rusty
// Sidepaths for knowledge between Rust and Cosmos.
/datum/heretic_knowledge/essence
name = "Priest's Ritual"
desc = "Allows you to transmute a tank of water and a glass shard into a Flask of Eldritch Essence. \
Eldritch Essence can be consumed for potent healing, or given to heathens for deadly poisoning."
gain_text = "This is an old recipe. The Owl whispered it to me. \
Created by the Priest - the Liquid that both was and is not."
required_atoms = list(
/obj/structure/reagent_dispensers/watertank = 1,
/obj/item/shard = 1,
)
result_atoms = list(/obj/item/reagent_containers/cup/beaker/eldritch)
cost = 1
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "eldritch_flask"
/datum/heretic_knowledge/rust_sower
name = "Rust Sower Grenade"
desc = "Allws you to combine a chemical grenade casing and a liver to conjure a cursed grenade filled with Eldritch Rust, upon detonating it releases a huge cloud that blinds organics, rusts affected turfs and obliterates Silicons and Mechs."
gain_text = "The choked vines of the Rusted Hills are burdened with such overripe fruits. It undoes the markers of progress, leaving a clean slate to work into new shapes."
required_atoms = list(
/obj/item/grenade/chem_grenade = 1,
/obj/item/organ/liver = 1,
)
result_atoms = list(/obj/item/grenade/chem_grenade/rust_sower)
cost = 1
research_tree_icon_path = 'icons/obj/weapons/grenade.dmi'
research_tree_icon_state = "rustgrenade"
/datum/heretic_knowledge/entropy_pulse
name = "Pulse of Entropy"
desc = "Allows you to transmute 10 iron sheets and a garbage item to fill the surrounding vicinity of the rune with rust."
gain_text = "Reality begins to whisper to me. To give it its entropic end."
required_atoms = list(
/obj/item/stack/sheet/iron = 10,
/obj/item/trash = 1,
)
cost = 0
research_tree_icon_path = 'icons/mob/actions/actions_ecult.dmi'
research_tree_icon_state = "corrode"
research_tree_icon_frame = 10
var/rusting_range = 8
/datum/heretic_knowledge/entropy_pulse/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
for(var/turf/nearby_turf in view(rusting_range, loc))
if(get_dist(nearby_turf, loc) <= 1) //tiles on rune should always be rusted
nearby_turf.rust_heretic_act()
//we exclude closed turf to avoid exposing cultist bases
if(prob(10) || isclosedturf(nearby_turf))
continue
nearby_turf.rust_heretic_act()
return TRUE
/datum/heretic_knowledge/summon/rusty
name = "Rusted Ritual"
desc = "Allows you to transmute a pool of vomit, some cable coil, and 10 sheets of iron into a Rust Walker. \
Rust Walkers excel at spreading rust and are moderately strong in combat."
gain_text = "I combined my knowledge of creation with my desire for corruption. The Marshal knew my name, and the Rusted Hills echoed out."
required_atoms = list(
/obj/effect/decal/cleanable/vomit = 1,
/obj/item/stack/sheet/iron = 10,
/obj/item/stack/cable_coil = 15,
)
mob_to_summon = /mob/living/basic/heretic_summon/rust_walker
cost = 1
poll_ignore_define = POLL_IGNORE_RUST_SPIRIT

View File

@@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge())
*/
/datum/heretic_knowledge/codex_cicatrix
name = "Codex Cicatrix"
desc = "Allows you to transmute a book, any unique pen (anything but generic pens), and your pick from any carcass (animal or human), leather, or hide to create a Codex Cicatrix. \
desc = "Allows you to transmute a book, any pen, and your pick from any carcass (animal or human), leather, or hide to create a Codex Cicatrix. \
The Codex Cicatrix can be used when draining influences to gain additional knowledge, but comes at greater risk of being noticed. \
It can also be used to draw and remove transmutation runes easier, and as a spell focus in a pinch."
gain_text = "The occult leaves fragments of knowledge and power anywhere and everywhere. The Codex Cicatrix is one such example. \
@@ -221,7 +221,6 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge())
/obj/item/pen = 1,
list(/mob/living, /obj/item/stack/sheet/leather, /obj/item/stack/sheet/animalhide, /obj/item/food/deadmouse) = 1,
)
banned_atom_types = list(/obj/item/pen)
result_atoms = list(/obj/item/codex_cicatrix)
cost = 1
is_starting_knowledge = TRUE
@@ -230,11 +229,6 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge())
research_tree_icon_path = 'icons/obj/antags/eldritch.dmi'
research_tree_icon_state = "book"
/datum/heretic_knowledge/codex_cicatrix/parse_required_item(atom/item_path, number_of_things)
if(item_path == /obj/item/pen)
return "unique type of pen"
return ..()
/datum/heretic_knowledge/codex_cicatrix/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
. = ..()
if(!.)
@@ -311,13 +305,15 @@ GLOBAL_LIST_INIT(heretic_start_knowledge, initialize_starting_knowledge())
. = TRUE
heretic_datum.feast_of_owls = TRUE
heretic_datum.update_heretic_aura()
user.set_temp_blindness(reward * 1 SECONDS)
user.AdjustParalyzed(reward * 1 SECONDS)
user.playsound_local(get_turf(user), 'sound/music/antag/heretic/heretic_gain_intense.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
for(var/i in 1 to reward)
user.emote("scream")
playsound(loc, 'sound/items/eatfood.ogg', 100, TRUE)
heretic_datum.knowledge_points++
heretic_datum.adjust_knowledge_points(1)
to_chat(user, span_danger("You feel something invisible tearing away at your very essence!"))
user.do_jitter_animation()
sleep(1 SECONDS)

View File

@@ -1,20 +1,50 @@
/datum/heretic_knowledge_tree_column/main/void
neighbour_type_left = /datum/heretic_knowledge_tree_column/flesh_to_void
neighbour_type_right = /datum/heretic_knowledge_tree_column/void_to_blade
/datum/heretic_knowledge_tree_column/void
route = PATH_VOID
ui_bgr = "node_void"
complexity = "Easy"
complexity_color = COLOR_GREEN
icon = list(
"icon" = 'icons/obj/weapons/khopesh.dmi',
"state" = "void_blade",
"frame" = 1,
"dir" = SOUTH,
"moving" = FALSE,
)
description = list(
"The Path of Void focuses on stealth, freezing cold, mobility and depressurization.",
"Pick this path if you enjoy being a highly mobile assassin who leaves their foes struggling to catch up.",
)
pros = list(
"Protection from the hazards of space.",
"Your spells apply a stacking debuff that chills and slows targets.",
"High amount of mobility spells.",
"Highly stealthy.",
)
cons = list(
"Though protected from space, you are not nearly as mobile in it as you are on foot.",
"Has a difficult time fighting opponents immune to cold effects.",
"Has a difficult time with silicon-based lifeforms.",
)
tips = list(
"Your Mansus Grasp allows you to mute your targets, making it ideal for silent assassinations (keep in mind that it won't short circuit their suit sensors, make sure you turn them off after you kill them). Yhe grasp also applies a mark that when triggered by the void blade will apply the maximum amount of stacks of void chill to your target, slowing them down to a crawl.",
"Void Cloak can be used to hide one of your blades and a Codex Cicatrix when the hood is down, while acting as a focus when it's up.",
"Void chill is a debuff applied by your spells, your grasp, your mark and your blade once you unlock the upgrade. Each stack slows your target movement speed by 10% and make them gradually colder, up to a maximum of 5 stacks.",
"At 5 stacks void chill will also prevent your target from heating up.",
"You are immune to low pressure and cold damage at the start of the shift. Upgrade your passive to level 2 to no longer need to breathe. Use this to your advantage.",
"Void prison can put a target in stasis for 10 seconds. Ideal if you are fighting multiple opponents and need to isolate one target at a time.",
"Void Conduit is your signature ability. It slowly destroys windows and airlocks around its area of effect. Use it to depressurize the station and expand your domain.",
)
start = /datum/heretic_knowledge/limited_amount/starting/base_void
grasp = /datum/heretic_knowledge/void_grasp
tier1 = /datum/heretic_knowledge/cold_snap
mark = /datum/heretic_knowledge/mark/void_mark
ritual_of_knowledge = /datum/heretic_knowledge/knowledge_ritual/void
unique_ability = /datum/heretic_knowledge/spell/void_conduit
tier2 = /datum/heretic_knowledge/spell/void_phase
knowledge_tier1 = /datum/heretic_knowledge/spell/void_phase
guaranteed_side_tier1 = /datum/heretic_knowledge/void_cloak
knowledge_tier2 = /datum/heretic_knowledge/spell/void_prison
guaranteed_side_tier2 = /datum/heretic_knowledge/ether
robes = /datum/heretic_knowledge/armor/void
knowledge_tier3 = /datum/heretic_knowledge/spell/void_pull
guaranteed_side_tier3 = /datum/heretic_knowledge/summon/maid_in_mirror
blade = /datum/heretic_knowledge/blade_upgrade/void
tier3 = /datum/heretic_knowledge/spell/void_pull
knowledge_tier4 = /datum/heretic_knowledge/spell/void_conduit
ascension = /datum/heretic_knowledge/ultimate/void_final
/datum/heretic_knowledge/limited_amount/starting/base_void
@@ -28,6 +58,8 @@
result_atoms = list(/obj/item/melee/sickly_blade/void)
research_tree_icon_path = 'icons/obj/weapons/khopesh.dmi'
research_tree_icon_state = "void_blade"
mark_type = /datum/status_effect/eldritch/void
eldritch_passive = /datum/status_effect/heretic_passive/void
/datum/heretic_knowledge/limited_amount/starting/base_void/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
if(!isopenturf(loc))
@@ -41,23 +73,8 @@
return ..()
/datum/heretic_knowledge/void_grasp
name = "Grasp of Void"
desc = "Your Mansus Grasp will temporarily mute and chill the victim."
gain_text = "I saw the cold watcher who observes me. The chill mounts within me. \
They are quiet. This isn't the end of the mystery."
cost = 1
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "grasp_void"
/datum/heretic_knowledge/void_grasp/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
RegisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK, PROC_REF(on_mansus_grasp))
/datum/heretic_knowledge/void_grasp/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
UnregisterSignal(user, COMSIG_HERETIC_MANSUS_GRASP_ATTACK)
/datum/heretic_knowledge/void_grasp/proc/on_mansus_grasp(mob/living/source, mob/living/target)
SIGNAL_HANDLER
/datum/heretic_knowledge/limited_amount/starting/base_void/on_mansus_grasp(mob/living/source, mob/living/target)
. = ..()
if(!iscarbon(target))
return
@@ -66,59 +83,6 @@
carbon_target.adjust_silence(10 SECONDS)
carbon_target.apply_status_effect(/datum/status_effect/void_chill, 2)
/datum/heretic_knowledge/cold_snap
name = "Aristocrat's Way"
desc = "Grants you immunity to cold temperatures, and removes your need to breathe. \
You can still take damage due to a lack of pressure."
gain_text = "I found a thread of cold breath. It lead me to a strange shrine, all made of crystals. \
Translucent and white, a depiction of a nobleman stood before me."
cost = 1
research_tree_icon_path = 'icons/effects/effects.dmi'
research_tree_icon_state = "the_freezer"
/// Traits we apply to become immune to the environment
var/static/list/gain_traits = list(TRAIT_NO_SLIP_ICE, TRAIT_NO_SLIP_SLIDE)
/datum/heretic_knowledge/cold_snap/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
user.add_traits(list(TRAIT_NOBREATH, TRAIT_RESISTCOLD), type)
RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(check_environment))
/datum/heretic_knowledge/cold_snap/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
user.remove_traits(list(TRAIT_RESISTCOLD, TRAIT_NOBREATH), type)
UnregisterSignal(user, COMSIG_LIVING_LIFE)
///Checks if our traits should be active
/datum/heretic_knowledge/cold_snap/proc/check_environment(mob/living/user)
SIGNAL_HANDLER
var/datum/gas_mixture/environment = user.loc?.return_air()
if(!isnull(environment))
var/affected_temperature = environment.return_temperature()
var/affected_pressure = environment.return_pressure()
if(affected_temperature <= T0C || affected_pressure < ONE_ATMOSPHERE)
user.add_traits(gain_traits, type)
else
user.remove_traits(gain_traits, type)
/datum/heretic_knowledge/mark/void_mark
name = "Mark of Void"
desc = "Your Mansus Grasp now applies the Mark of Void. The mark is triggered from an attack with your Void Blade. \
When triggered, further silences the victim and swiftly lowers the temperature of their body and the air around them."
gain_text = "A gust of wind? A shimmer in the air? The presence is overwhelming, \
my senses began to betray me. My mind is my own enemy."
mark_type = /datum/status_effect/eldritch/void
/datum/heretic_knowledge/knowledge_ritual/void
/datum/heretic_knowledge/spell/void_conduit
name = "Void Conduit"
desc = "Grants you Void Conduit, a spell which summons a pulsing gate to the Void itself. Every pulse breaks windows and airlocks, while afflicting Heathens with an eldritch chill and shielding Heretics against low pressure."
gain_text = "The hum in the still, cold air turns to a cacophonous rattle. \
Over the noise, there is no distinction to the clattering of window panes and the yawning knowledge that ricochets through my skull. \
The doors won't close. I can't keep the cold out now."
action_to_add = /datum/action/cooldown/spell/conjure/void_conduit
cost = 1
/datum/heretic_knowledge/spell/void_phase
name = "Void Phase"
desc = "Grants you Void Phase, a long range targeted teleport spell. \
@@ -126,9 +90,59 @@
gain_text = "The entity calls themself the Aristocrat. They effortlessly walk through air like \
nothing - leaving a harsh, cold breeze in their wake. They disappear, and I am left in the blizzard."
action_to_add = /datum/action/cooldown/spell/pointed/void_phase
cost = 1
cost = 2
research_tree_icon_frame = 7
/datum/heretic_knowledge/spell/void_prison
name = "Void Prison"
desc = "Grants you Void Prison, a spell that places your victim into a ball, making them unable to do anything or speak. \
Applies void chill afterwards."
gain_text = "At first, I see myself, waltzing along a snow-laden street. \
I try to yell, grab hold of this fool and tell them to run. \
But the only welts made are on my own beating fist. \
My smiling face turns to regard me, reflecting back in glassy eyes the empty path I have been lead down."
action_to_add = /datum/action/cooldown/spell/pointed/void_prison
cost = 2
drafting_tier = 5
/datum/heretic_knowledge/armor/void
name = "Hollow Weave"
desc = "Allows you to transmute a table (or a suit) and a mask in sub-zero temperatures to create a Hollow Weave, this armor will periodically nullify attacks and grant you a short stealth camoflage to reposition yourself. \
Acts as a focus while hooded."
gain_text = "Stepping through the cold air, I am shocked by a new sensation. \
Thousands of almost imperceivable threads cling to my form. \
I am left adrift with every step. \
Even as I hear the crunch of snow as I plant my foot to the ground, I feel nothing."
result_atoms = list(/obj/item/clothing/suit/hooded/cultrobes/eldritch/void)
research_tree_icon_state = "void_armor"
required_atoms = list(
list(/obj/structure/table, /obj/item/clothing/suit) = 1,
/obj/item/clothing/mask = 1,
)
/datum/heretic_knowledge/armor/void/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
if(!isopenturf(loc))
loc.balloon_alert(user, "ritual failed, invalid location!")
return FALSE
var/turf/open/our_turf = loc
if(our_turf.GetTemperature() > T0C)
loc.balloon_alert(user, "ritual failed, not cold enough!")
return FALSE
return ..()
/datum/heretic_knowledge/spell/void_pull
name = "Void Pull"
desc = "Grants you Void Pull, a spell that pulls all nearby heathens towards you, stunning them briefly."
gain_text = "All is fleeting, but what else stays? I'm close to ending what was started. \
The Aristocrat reveals themselves to me again. They tell me I am late. Their pull is immense, I cannot turn back."
action_to_add = /datum/action/cooldown/spell/aoe/void_pull
cost = 2
research_tree_icon_frame = 6
/datum/heretic_knowledge/blade_upgrade/void
name = "Seeking Blade"
desc = "Your blade now freezes enemies. Additionally, you can now attack distant marked targets with your Void Blade, teleporting directly next to them."
@@ -156,17 +170,15 @@
/datum/heretic_knowledge/blade_upgrade/void/proc/follow_up_attack(mob/living/user, mob/living/target, obj/item/melee/sickly_blade/blade)
blade.melee_attack_chain(user, target)
/datum/heretic_knowledge/spell/void_pull
name = "Void Pull"
desc = "Grants you Void Pull, a spell that pulls all nearby heathens towards you, stunning them briefly."
gain_text = "All is fleeting, but what else stays? I'm close to ending what was started. \
The Aristocrat reveals themselves to me again. They tell me I am late. Their pull is immense, I cannot turn back."
action_to_add = /datum/action/cooldown/spell/aoe/void_pull
cost = 1
research_tree_icon_frame = 6
/datum/heretic_knowledge/spell/void_conduit
name = "Void Conduit"
desc = "Grants you Void Conduit, a spell which summons a pulsing gate to the Void itself. Every pulse breaks windows and airlocks, while afflicting Heathens with an eldritch chill and shielding Heretics against low pressure."
gain_text = "The hum in the still, cold air turns to a cacophonous rattle. \
Over the noise, there is no distinction to the clattering of window panes and the yawning knowledge that ricochets through my skull. \
The doors won't close. I can't keep the cold out now."
action_to_add = /datum/action/cooldown/spell/conjure/void_conduit
cost = 2
is_final_knowledge = TRUE
/datum/heretic_knowledge/ultimate/void_final
name = "Waltz at the End of Time"

View File

@@ -16,6 +16,23 @@
aoe_radius = 2
/datum/action/cooldown/spell/aoe/rust_conversion/before_cast(atom/cast_on)
. = ..()
if(. & SPELL_CANCEL_CAST)
return
return SPELL_NO_IMMEDIATE_COOLDOWN
/datum/action/cooldown/spell/aoe/rust_conversion/after_cast(atom/cast_on)
. = ..()
var/datum/status_effect/heretic_passive/rust/rust_passive = owner.has_status_effect(/datum/status_effect/heretic_passive/rust)
if(!rust_passive)
StartCooldown(cooldown_time)
return
var/new_cooldown = 35 SECONDS - (rust_passive.passive_level * 5 SECONDS)
StartCooldown(new_cooldown)
/datum/action/cooldown/spell/aoe/rust_conversion/get_things_to_cast_on(atom/center)
var/list/things_to_convert = RANGE_TURFS(aoe_radius, center)

View File

@@ -1,6 +1,6 @@
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash
name = "Ashen Passage"
desc = "A short range spell that allows you to pass unimpeded through walls."
desc = "A short range spell that allows you to pass unimpeded through walls, removing restraints if empowered."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
button_icon = 'icons/mob/actions/actions_ecult.dmi'
@@ -20,6 +20,59 @@
jaunt_type = /obj/effect/dummy/phased_mob/spell_jaunt/red
jaunt_in_type = /obj/effect/temp_visual/dir_setting/ash_shift
jaunt_out_type = /obj/effect/temp_visual/dir_setting/ash_shift/out
/// If we are on fire while wearing ash robes, we can empower our next cast
var/empowered_cast = FALSE
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/Grant(mob/grant_to)
. = ..()
RegisterSignal(grant_to, COMSIG_FIRE_STACKS_UPDATED, PROC_REF(update_status_on_signal))
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/Remove(mob/remove_from)
. = ..()
UnregisterSignal(remove_from, COMSIG_FIRE_STACKS_UPDATED)
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/apply_button_overlay(atom/movable/screen/movable/action_button/current_button, force)
. = ..()
// Put an active border whenever our spell is able to be casted empowered
if(!ishuman(owner))
return
var/mob/living/carbon/human/human_owner = owner
if(!istype(human_owner.wear_suit, /obj/item/clothing/suit/hooded/cultrobes/eldritch/ash))
return
if(human_owner.fire_stacks <= 3)
return
current_button.cut_overlay(current_button.button_overlay)
current_button.button_overlay = mutable_appearance(icon = overlay_icon, icon_state = "bg_spell_border_active_green")
current_button.add_overlay(current_button.button_overlay)
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/cast(mob/living/cast_on)
if(!iscarbon(owner))
return ..()
// Wearing Ash heretic armor empowers your spells if you have over 3 fire stacks
if(!ishuman(owner))
return ..()
var/mob/living/carbon/human/human_owner = owner
if(human_owner.fire_stacks <= 3)
return ..()
if(!istype(human_owner.wear_suit, /obj/item/clothing/suit/hooded/cultrobes/eldritch/ash))
return ..()
empowered_cast = TRUE
human_owner.setStaminaLoss(0)
human_owner.SetAllImmobility(0)
var/mob/living/carbon/carbon_owner = owner
carbon_owner.uncuff()
var/obj/item/clothing/shoes/shoes = carbon_owner.shoes
if(istype(shoes) && shoes.tied == SHOES_KNOTTED)
shoes.adjust_laces(SHOES_TIED, carbon_owner)
return ..()
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/do_jaunt(mob/living/cast_on)
jaunt_duration = (empowered_cast ? 1.5 SECONDS : initial(jaunt_duration))
return ..()
/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash/do_steam_effects()
return

View File

@@ -30,7 +30,7 @@
return
for(var/mob/living/alive in orange(5, owner))
if(alive.stat != DEAD && alive.client)
if(alive.stat != DEAD && alive.client && (owner in view(alive)))
owner.balloon_alert(owner, "other minds nearby!")
return . | SPELL_CANCEL_CAST

View File

@@ -1,6 +1,6 @@
/datum/action/cooldown/spell/conjure/cosmic_expansion
name = "Cosmic Expansion"
desc = "This spell generates a 3x3 domain of cosmic fields. \
desc = "This spell generates a 5x5 domain of cosmic fields. \
Creatures up to 7 tiles away will also receive a star mark."
background_icon_state = "bg_heretic"
overlay_icon_state = "bg_heretic_border"
@@ -9,14 +9,14 @@
sound = 'sound/effects/magic/cosmic_expansion.ogg'
school = SCHOOL_FORBIDDEN
cooldown_time = 45 SECONDS
cooldown_time = 15 SECONDS
invocation = "C'SM'S 'XP'ND!"
invocation_type = INVOCATION_SHOUT
spell_requirements = NONE
summon_amount = 9
summon_radius = 1
summon_amount = 25
summon_radius = 2
summon_type = list(/obj/effect/forcefield/cosmic_field)
/// The range at which people will get marked with a star mark.
var/star_mark_range = 7
@@ -24,16 +24,18 @@
var/obj/effect/expansion_effect = /obj/effect/temp_visual/cosmic_domain
/// If the heretic is ascended or not
var/ascended = FALSE
/// Weakref to our summoner, only relevant if we are a stargazer. Prevents us from harming our master
var/datum/weakref/summoner
/datum/action/cooldown/spell/conjure/cosmic_expansion/cast(mob/living/cast_on)
new expansion_effect(get_turf(cast_on))
for(var/mob/living/nearby_mob in range(star_mark_range, cast_on))
if(cast_on == nearby_mob || cast_on.buckled == nearby_mob)
if(cast_on == nearby_mob || cast_on.buckled == nearby_mob || IS_HERETIC_OR_MONSTER(nearby_mob) || cast_on == summoner?.resolve())
continue
nearby_mob.apply_status_effect(/datum/status_effect/star_mark, cast_on)
if (ascended)
if (ascended && length(summon_type))
for(var/turf/cast_turf as anything in get_turfs(get_turf(cast_on)))
new /obj/effect/forcefield/cosmic_field(cast_turf)
create_cosmic_field(cast_turf, owner, summon_type[1])
return ..()
/datum/action/cooldown/spell/conjure/cosmic_expansion/proc/get_turfs(turf/target_turf)
@@ -42,3 +44,17 @@
target_turfs += get_ranged_target_turf(target_turf, direction, 2)
target_turfs += get_ranged_target_turf(target_turf, direction, 3)
return target_turfs
/datum/action/cooldown/spell/conjure/cosmic_expansion/post_summon(obj/effect/forcefield/cosmic_field/summoned_object, atom/cast_on)
. = ..()
if(isstargazer(owner))
summoned_object.slows_projectiles()
summoned_object.prevents_explosions()
return
var/datum/status_effect/heretic_passive/cosmic/cosmic_passive = owner.has_status_effect(/datum/status_effect/heretic_passive/cosmic)
if(!cosmic_passive)
return
if(cosmic_passive.passive_level > 1)
summoned_object.prevents_explosions()
if(cosmic_passive.passive_level > 2)
summoned_object.slows_projectiles()

View File

@@ -70,6 +70,13 @@
silicon_image.override = TRUE
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/silicons, "cosmic", silicon_image)
ADD_TRAIT(src, TRAIT_MOPABLE, INNATE_TRAIT)
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
COMSIG_ATOM_EXITED = PROC_REF(on_exited)
)
AddElement(/datum/element/connect_loc, loc_connections)
for(var/mob/living/mobs in get_turf(src))
RegisterSignal(mobs, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_self))
/obj/effect/cosmic_rune/attack_paw(mob/living/user, list/modifiers)
return attack_hand(user, modifiers)
@@ -92,10 +99,32 @@
return
invoke(user)
/obj/effect/cosmic_rune/proc/on_entered(datum/source, atom/movable/arrived)
SIGNAL_HANDLER
if(!isliving(arrived))
return
RegisterSignal(arrived, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_self))
/// If something clicks on themselves while on top of the rune, we instead will act as if they clicked on the rune instead
/obj/effect/cosmic_rune/proc/on_attack_self(datum/source, mob/living/user)
SIGNAL_HANDLER
if(source == user)
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, attack_hand), user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/effect/cosmic_rune/proc/on_exited(datum/source, exiter)
SIGNAL_HANDLER
UnregisterSignal(exiter, COMSIG_ATOM_ATTACK_HAND)
/// For invoking the rune
/obj/effect/cosmic_rune/proc/invoke(mob/living/user)
var/obj/effect/cosmic_rune/linked_rune_resolved = linked_rune?.resolve()
new rune_effect(get_turf(src))
var/atom/pulled_thing
if(IS_HERETIC(user))
if(user.pulling)
pulled_thing = user.pulling
do_teleport(user.pulling, get_turf(linked_rune_resolved), no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
do_teleport(
user,
get_turf(linked_rune_resolved),
@@ -104,9 +133,13 @@
asoundin = 'sound/effects/magic/cosmic_energy.ogg',
asoundout = 'sound/effects/magic/cosmic_energy.ogg',
)
if(pulled_thing) // Regrab after the teleports are done
user.start_pulling(pulled_thing)
for(var/mob/living/person_on_rune in get_turf(src))
if(person_on_rune.has_status_effect(/datum/status_effect/star_mark))
do_teleport(person_on_rune, get_turf(linked_rune_resolved), no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
if(!IS_HERETIC(user))
user.apply_status_effect(/datum/status_effect/star_mark)
new rune_effect(get_turf(linked_rune_resolved))
/// For if someone failed to invoke the rune

Some files were not shown because too many files have changed in this diff Show More