Merge pull request #4519 from Neerti/12/15/2017_berserking

Adds Berserk
This commit is contained in:
Anewbe
2018-01-11 20:57:50 -06:00
committed by GitHub
32 changed files with 646 additions and 15 deletions

View File

@@ -33,7 +33,8 @@
#define ARCHAEO_REMAINS_ROBOT 33
#define ARCHAEO_REMAINS_XENO 34
#define ARCHAEO_GASMASK 35
#define MAX_ARCHAEO 35
#define ARCHAEO_ALIEN_ITEM 36
#define MAX_ARCHAEO 36
#define DIGSITE_GARDEN 1
#define DIGSITE_ANIMAL 2

View File

@@ -10,6 +10,7 @@
name = ""
icon = 'icons/mob/screen1.dmi'
layer = 20.0
appearance_flags = TILE_BOUND|PIXEL_SCALE|NO_CLIENT_COLOR
unacidable = 1
var/obj/master = null //A reference to the object in the slot. Grabs or items, generally.
var/datum/hud/hud = null // A reference to the owner HUD, if any.

View File

@@ -0,0 +1,33 @@
/datum/power/changeling/enrage
name = "Enrage"
desc = "We evolve modifications to our mind and body, allowing us to call on intense periods of rage for our benefit."
helptext = "Berserks us, giving massive bonuses to fighting in close quarters for thirty seconds, and losing the ability to \
be accurate at ranged while active. Afterwards, we will suffer extreme amounts of exhaustion for a period of two minutes, \
during which we will be much weaker and slower than before. We cannot berserk again while exhausted. This ability requires \
a significant amount of nutrition to use, and cannot be used if too hungry. Using this ability will end most forms of disables."
enhancedtext = "The length of exhaustion after berserking is reduced to one minute, from two, and requires half as much nutrition."
ability_icon_state = "ling_berserk"
genomecost = 2
allowduringlesserform = 1
verbpath = /mob/living/proc/changeling_berserk
// Makes the ling very upset.
/mob/living/proc/changeling_berserk()
set category = "Changeling"
set name = "Enrage (30)"
set desc = "Causes you to go Berserk."
var/datum/changeling/changeling = changeling_power(30,0,100)
if(!changeling)
return 0
var/modifier_to_use = /datum/modifier/berserk/changeling
if(src.mind.changeling.recursive_enhancement)
modifier_to_use = /datum/modifier/berserk/changeling/recursive
to_chat(src, "<span class='notice'>We optimize our levels of anger, which will avoid excessive stress on ourselves.</span>")
if(add_modifier(modifier_to_use, 30 SECONDS))
changeling.chem_charges -= 30
feedback_add_details("changeling_powers","EN")
return 1

View File

@@ -234,7 +234,9 @@
// apparently called whenever an item is removed from a slot, container, or anything else.
/obj/item/proc/dropped(mob/user as mob)
..()
if(zoom) zoom() //binoculars, scope, etc
if(zoom)
zoom() //binoculars, scope, etc
appearance_flags &= ~NO_CLIENT_COLOR
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
@@ -259,8 +261,11 @@
// note this isn't called during the initial dressing of a player
/obj/item/proc/equipped(var/mob/user, var/slot)
layer = 20
if(user.client) user.client.screen |= src
if(user.pulling == src) user.stop_pulling()
if(user.client)
user.client.screen |= src
if(user.pulling == src)
user.stop_pulling()
appearance_flags |= NO_CLIENT_COLOR
return
//Defines which slots correspond to which slot flags

View File

@@ -31,6 +31,12 @@
return
var/weapon_attack_speed = user.get_attack_speed(I) / 10
var/weapon_damage = I.force
var/modified_damage_percent = 1
for(var/datum/modifier/M in user.modifiers)
if(!isnull(M.outgoing_melee_damage_percent))
weapon_damage *= M.outgoing_melee_damage_percent
modified_damage_percent *= M.outgoing_melee_damage_percent
if(istype(I, /obj/item/weapon/gun))
var/obj/item/weapon/gun/G = I
@@ -53,7 +59,7 @@
qdel(P)
var/DPS = weapon_damage / weapon_attack_speed
to_chat(user, "<span class='notice'>Damage: [weapon_damage]</span>")
to_chat(user, "<span class='notice'>Damage: [weapon_damage][modified_damage_percent != 1 ? " (Modified by [modified_damage_percent*100]%)":""]</span>")
to_chat(user, "<span class='notice'>Attack Speed: [weapon_attack_speed]/s</span>")
to_chat(user, "<span class='notice'>\The [I] does <b>[DPS]</b> damage per second.</span>")
if(DPS > 0)

View File

@@ -6,6 +6,7 @@
* Pumpkin head
* Kitty ears
* Holiday hats
Crown of Wrath
*/
/*
@@ -208,3 +209,67 @@
icon_state = "santahatgreen"
item_state_slots = list(slot_r_hand_str = "santahatgreen", slot_l_hand_str = "santahatgreen")
body_parts_covered = 0
/*
* Xenoarch/Surface Loot Hats
*/
// Triggers an effect when the wearer is 'in grave danger'.
// Causes brainloss when it happens.
/obj/item/clothing/head/psy_crown
name = "broken crown"
desc = "A crown-of-thorns with a missing gem."
var/tension_threshold = 150
var/cooldown = null // world.time of when this was last triggered.
var/cooldown_duration = 3 MINUTES // How long the cooldown should be.
var/flavor_equip = null // Message displayed to someone who puts this on their head. Drones don't get a message.
var/flavor_unequip = null // Ditto, but for taking it off.
var/flavor_drop = null // Ditto, but for dropping it.
var/flavor_activate = null // Ditto, for but activating.
var/brainloss_cost = 3 // Whenever it activates, inflict this much brainloss on the wearer, as its not good for the mind to wear things that manipulate it.
/obj/item/clothing/head/psy_crown/proc/activate_ability(var/mob/living/wearer)
cooldown = world.time + cooldown_duration
to_chat(wearer, flavor_activate)
to_chat(wearer, "<span class='danger'>The inside of your head hurts...</span>")
wearer.adjustBrainLoss(brainloss_cost)
/obj/item/clothing/head/psy_crown/equipped(var/mob/living/carbon/human/H)
..()
if(istype(H) && H.head == src && H.is_sentient())
processing_objects += src
to_chat(H, flavor_equip)
/obj/item/clothing/head/psy_crown/dropped(var/mob/living/carbon/human/H)
..()
processing_objects -= src
if(H.is_sentient())
if(loc == H) // Still inhand.
to_chat(H, flavor_unequip)
else
to_chat(H, flavor_drop)
/obj/item/clothing/head/psy_crown/Destroy()
processing_objects -= src
return ..()
/obj/item/clothing/head/psy_crown/process()
if(isliving(loc))
var/mob/living/L = loc
if(world.time >= cooldown && L.is_sentient() && L.get_tension() >= tension_threshold)
activate_ability(L)
/obj/item/clothing/head/psy_crown/wrath
name = "red crown"
desc = "A crown-of-thorns set with a red gemstone that seems to glow unnaturally. It feels rather disturbing to touch."
description_info = "This has a chance to cause the wearer to become extremely angry when in extreme danger."
icon_state = "wrathcrown"
flavor_equip = "<span class='warning'>You feel a bit angrier after putting on this crown.</span>"
flavor_unequip = "<span class='notice'>You feel calmer after removing the crown.</span>"
flavor_drop = "<span class='notice'>You feel much calmer after letting go of the crown.</span>"
flavor_activate = "<span class='danger'>An otherworldly feeling seems to enter your mind, and it ignites your mind in fury!</span>"
/obj/item/clothing/head/psy_crown/wrath/activate_ability(var/mob/living/wearer)
..()
wearer.add_modifier(/datum/modifier/berserk, 30 SECONDS)

View File

@@ -19,6 +19,7 @@
var/light_range = null // How far the light for the above var goes. Not implemented yet.
var/light_intensity = null // Ditto. Not implemented yet.
var/mob_overlay_state = null // Icon_state for an overlay to apply to a (human) mob while this exists. This is actually implemented.
var/client_color = null // If set, the client will have the world be shown in this color, from their perspective.
// Now for all the different effects.
// Percentage modifiers are expressed as a multipler. (e.g. +25% damage should be written as 1.25)
@@ -43,6 +44,7 @@
var/metabolism_percent // Adjusts the mob's metabolic rate, which affects reagent processing. Won't affect mobs without reagent processing.
var/icon_scale_percent // Makes the holder's icon get scaled up or down.
var/attack_speed_percent // Makes the holder's 'attack speed' (click delay) shorter or longer.
var/pain_immunity // Makes the holder not care about pain while this is on. Only really useful to human mobs.
/datum/modifier/New(var/new_holder, var/new_origin)
holder = new_holder
@@ -52,6 +54,11 @@
origin = weakref(holder)
..()
// Checks if the modifier should be allowed to be applied to the mob before attaching it.
// Override for special criteria, e.g. forbidding robots from receiving it.
/datum/modifier/proc/can_apply(var/mob/living/L)
return TRUE
// Checks to see if this datum should continue existing.
/datum/modifier/proc/check_if_valid()
if(expire_at && expire_at < world.time) // Is our time up?
@@ -66,8 +73,14 @@
holder.update_modifier_visuals()
if(icon_scale_percent) // Correct the scaling.
holder.update_transform()
if(client_color)
holder.update_client_color()
qdel(src)
// Override this for special effects when it gets added to the mob.
/datum/modifier/proc/on_applied()
return
// Override this for special effects when it gets removed.
/datum/modifier/proc/on_expire()
return
@@ -114,15 +127,21 @@
// If we're at this point, the mob doesn't already have it, or it does but stacking is allowed.
var/datum/modifier/mod = new modifier_type(src, origin)
if(!mod.can_apply(src))
qdel(mod)
return
if(expire_at)
mod.expire_at = world.time + expire_at
if(mod.on_created_text)
to_chat(src, mod.on_created_text)
modifiers.Add(mod)
mod.on_applied()
if(mod.mob_overlay_state)
update_modifier_visuals()
if(mod.icon_scale_percent)
update_transform()
if(mod.client_color)
update_client_color()
return mod

View File

@@ -0,0 +1,182 @@
// File for modifier defines that don't fit anywhere else. Since this is a misc file, it's doomed to get filled with everything like all the others.
/*
Berserk is a modifier that grants vastly increased melee capability for a short period of time, easily allowing the
holder to do more than twice the damage they would normally do, as it both increases outgoing melee damage, and
reduces their attack delay. The screen will also turn deep red and the holder will get larger in size.
The modifier also gives some defenses, in that it gives additional max health (this can bite them in the ass later since
its not permanent), makes them move slightly faster, cancels disabling effects when it triggers, and reduces the power of
future disables by a very large amount. It also suppresses pain until it expires, however berserking while under massive pain
is likely to cause them to pass out when exhaustion hits.
Due to the intense rage felt by the holder, the focus needed to use ranged weapons is lost, making accuracy with them
massively reduced. The holder also feels less of a need to evade attacks and will be easier to hit.
Berserk can be extended by having another instance try to affect the holder while in the middle of a berserk.
After the modifier expires, a second modifier representing exhaustion is placed, which inflicts massive maluses and prevents
further berserks until it expires. This generally means that someone getting caught while exhausted will be much easier to fight,
as they will be much slower, attack slower, do less melee damage, be easier to hit, and disabling effects will affect them harder.
Berserking causes the holder to feel hungrier. If they are starving, this modifier cannot be applied. Diona cannot
be berserked, or those who are suffering from exhaustion. Non-Drone Synthetics that receive the berserk modifier will
instead get a version that has no benefits, but will not cost nutrition or cause exhaustion. Drones cannot receive berserk, as
they are emotionless automatrons.
Berserk is a somewhat rare modifier to obtain freely (and for good reason), however here are ways to see it in action;
- Red Slimes will berserk if they go rabid.
- Red slime core reactions will berserk slimes that can see the user in addition to making them go rabid.
- Red slime core reactions will berserk prometheans that can see the user.
- Bears will berserk when losing a fight.
- Changelings can evolve a 2 point ability to use a changeling-specific variant of Berserk, that replaces the text with a 'we' variant.
Recursive Enhancement allows the changeling to instead used an improved variant that features less exhaustion time and less nutrition drain.
- Xenoarch artifacts may have forced berserking as one of their effects. This is especially fun if an artifact that makes hostile mobs is nearby.
Will cause three brainloss in those affected due to the artifact meddling with their mind.
- A rare alien artifact might be found on the Surface, or obtained from Xenoarch, that causes berserking when it thinks
the wearer is in danger, however in addition to the usual drawbacks, each use causes three brainloss in the user, due to how
the artifact triggers the rage.
*/
/datum/modifier/berserk
name = "berserk"
desc = "You are filled with an overwhelming rage."
client_color = "#FF0000" // Make everything red!
mob_overlay_state = "berserk"
on_created_text = "<span class='critical'>You feel an intense and overwhelming rage overtake you as you go berserk!</span>"
on_expired_text = "<span class='notice'>The blaze of rage inside you has ran out.</span>"
stacks = MODIFIER_STACK_EXTEND
// The good stuff.
slowdown = -1 // Move a bit faster.
attack_speed_percent = 0.66 // Attack at 2/3 the normal delay.
outgoing_melee_damage_percent = 1.5 // 50% more damage from melee.
max_health_percent = 1.5 // More health as a buffer, however the holder might fall into crit after this expires if they're mortally wounded.
disable_duration_percent = 0.25 // Disables only last 25% as long.
icon_scale_percent = 1.2 // Look scarier.
pain_immunity = TRUE // Avoid falling over from shock (at least until it expires).
// The less good stuff.
accuracy = -5 // Aiming requires focus.
accuracy_dispersion = 3 // Ditto.
evasion = -3 // Too angry to dodge.
var/nutrition_cost = 150
var/exhaustion_duration = 2 MINUTES // How long the exhaustion modifier lasts after it expires. Set to 0 to not apply one.
var/last_shock_stage = 0
// For changelings.
/datum/modifier/berserk/changeling
on_created_text = "<span class='critical'>We feel an intense and overwhelming rage overtake us as we go berserk!</span>"
on_expired_text = "<span class='notice'>The blaze of rage inside us has ran out.</span>"
// For changelings who bought the Recursive Enhancement evolution.
/datum/modifier/berserk/changeling/recursive
exhaustion_duration = 1 MINUTE
nutrition_cost = 75
/datum/modifier/berserk/on_applied()
if(ishuman(holder)) // Most other mobs don't really use nutrition and can't get it back.
holder.nutrition = max(0, holder.nutrition - nutrition_cost)
holder.visible_message("<span class='critical'>\The [holder] descends into an all consuming rage!</span>")
// End all stuns.
holder.SetParalysis(0)
holder.SetStunned(0)
holder.SetWeakened(0)
holder.setHalLoss(0)
holder.lying = 0
holder.update_canmove()
// Temporarily end pain.
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
last_shock_stage = H.shock_stage
H.shock_stage = 0
/datum/modifier/berserk/on_expire()
if(exhaustion_duration > 0 && holder.stat != DEAD)
holder.add_modifier(/datum/modifier/berserk_exhaustion, exhaustion_duration)
if(prob(last_shock_stage))
to_chat(holder, "<span class='warning'>You pass out from the pain you were suppressing.</span>")
holder.Paralyse(5)
if(ishuman(holder))
var/mob/living/carbon/human/H = holder
H.shock_stage = last_shock_stage
/datum/modifier/berserk/can_apply(var/mob/living/L)
if(L.stat)
to_chat(L, "<span class='warning'>You can't be unconscious or dead to berserk.</span>")
return FALSE // It would be weird to see a dead body get angry all of a sudden.
if(!L.is_sentient())
return FALSE // Drones don't feel anything.
if(L.has_modifier_of_type(/datum/modifier/berserk_exhaustion))
to_chat(L, "<span class='warning'>You recently berserked, and cannot do so again while exhausted.</span>")
return FALSE // On cooldown.
if(L.isSynthetic())
L.add_modifier(/datum/modifier/berserk_synthetic, 30 SECONDS)
return FALSE // Borgs can get angry but their metal shell can't be pushed harder by just being mad. Same for Posibrains.
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.species.name == "Diona")
to_chat(L, "<span class='warning'>You feel strange for a moment, but it passes.</span>")
return FALSE // Happy trees aren't affected by blood rages.
if(L.nutrition < nutrition_cost)
to_chat(L, "<span class='warning'>You are too hungry to berserk.</span>")
return FALSE // Too hungry to enrage.
return ..()
/datum/modifier/berserk/tick()
if(holder.stat == DEAD)
expire(silent = TRUE)
// Applied when berserk expires. Acts as a downside as well as the cooldown for berserk.
/datum/modifier/berserk_exhaustion
name = "exhaustion"
desc = "You recently exerted yourself extremely hard, and need a rest."
on_created_text = "<span class='warning'>You feel extremely exhausted.</span>"
on_expired_text = "<span class='notice'>You feel less exhausted now.</span>"
stacks = MODIFIER_STACK_EXTEND
slowdown = 2
attack_speed_percent = 1.5
outgoing_melee_damage_percent = 0.6
disable_duration_percent = 1.5
evasion = -2
/datum/modifier/berserk_exhaustion/on_applied()
holder.visible_message("<span class='warning'>\The [holder] looks exhausted.</span>")
// Synth version with no benefits due to a loss of focus inside a metal shell, which can't be pushed harder just be being mad.
// Fortunately there is no exhaustion or nutrition cost.
/datum/modifier/berserk_synthetic
name = "recklessness"
desc = "You are filled with an overwhelming rage, however your metal shell prevents taking advantage of this."
client_color = "#FF0000" // Make everything red!
mob_overlay_state = "berserk"
on_created_text = "<span class='danger'>You feel an intense and overwhelming rage overtake you as you go berserk! \
Unfortunately, your lifeless body cannot benefit from this. You feel reckless...</span>"
on_expired_text = "<span class='notice'>The blaze of rage inside your mind has ran out.</span>"
stacks = MODIFIER_STACK_EXTEND
// Just being mad isn't gonna overclock your body when you're a beepboop.
accuracy = -5 // Aiming requires focus.
accuracy_dispersion = 3 // Ditto.
evasion = -3 // Too angry to dodge.

View File

@@ -296,6 +296,9 @@
/mob/living/bot/proc/explode()
qdel(src)
/mob/living/bot/is_sentient()
return FALSE
/******************************************************************/
// Navigation procs
// Used for A-star pathfinding

View File

@@ -1506,12 +1506,20 @@
/mob/living/carbon/human/can_feel_pain(var/obj/item/organ/check_organ)
if(isSynthetic())
return 0
for(var/datum/modifier/M in modifiers)
if(M.pain_immunity == TRUE)
return 0
if(check_organ)
if(!istype(check_organ))
return 0
return check_organ.organ_can_feel_pain()
return !(species.flags & NO_PAIN)
/mob/living/carbon/human/is_sentient()
if(get_FBP_type() == FBP_DRONE)
return FALSE
return ..()
/mob/living/carbon/human/is_muzzled()
return (wear_mask && (istype(wear_mask, /obj/item/clothing/mask/muzzle) || istype(src.wear_mask, /obj/item/weapon/grenade)))

View File

@@ -1013,6 +1013,9 @@ default behaviour is:
/mob/living/proc/equip_post_job()
return
// Used to check if something is capable of thought, in the traditional sense.
/mob/living/proc/is_sentient()
return TRUE
/mob/living/update_transform()
// First, get the correct size.
@@ -1025,4 +1028,40 @@ default behaviour is:
var/matrix/M = matrix()
M.Scale(desired_scale)
M.Translate(0, 16*(desired_scale-1))
src.transform = M
animate(src, transform = M, time = 10)
// This handles setting the client's color variable, which makes everything look a specific color.
// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
/mob/living/update_client_color()
if(!client)
return
var/list/colors_to_blend = list()
for(var/datum/modifier/M in modifiers)
if(!isnull(M.client_color))
colors_to_blend += M.client_color
if(colors_to_blend.len)
var/final_color
if(colors_to_blend.len == 1) // If it's just one color we can skip all of this work.
final_color = colors_to_blend[1]
else // Otherwise we need to do some messy additive blending.
var/R = 0
var/G = 0
var/B = 0
for(var/C in colors_to_blend)
var/RGB = hex2rgb(C)
R = between(0, R + RGB[1], 255)
G = between(0, G + RGB[2], 255)
B = between(0, B + RGB[3], 255)
final_color = rgb(R,G,B)
if(final_color)
var/old_color = client.color // Don't know if BYOND has an internal optimization to not care about animate() calls that effectively do nothing.
if(final_color != old_color) // Gonna do a check just incase.
animate(client, color = final_color, time = 10)
else // No colors, so remove the client's color.
animate(client, color = null, time = 10)

View File

@@ -791,5 +791,10 @@ var/list/ai_verbs_default = list(
if(rig)
rig.force_rest(src)
/mob/living/silicon/ai/is_sentient()
// AI cores don't store what brain was used to build them so we're just gonna assume they can think to some degree.
// If that is ever fixed please update this proc.
return TRUE
#undef AI_CHECK_WIRELESS
#undef AI_CHECK_RADIO

View File

@@ -67,6 +67,9 @@ var/list/mob_hat_cache = list()
hat.loc = get_turf(src)
..()
/mob/living/silicon/robot/drone/is_sentient()
return FALSE
/mob/living/silicon/robot/drone/construction
icon_state = "constructiondrone"
law_type = /datum/ai_laws/construction_drone

View File

@@ -13,6 +13,7 @@
handle_actions()
handle_instability()
// For some reason borg Life() doesn't call ..()
handle_modifiers()
handle_light()
if(client)

View File

@@ -1090,3 +1090,6 @@
src << "Hack attempt detected."
return 1
return
/mob/living/silicon/robot/is_sentient()
return braintype != "Drone"

View File

@@ -1,6 +1,6 @@
// Hivebots are tuned towards how many default lasers are needed to kill them.
// As such, if laser damage is ever changed, you should change this define.
#define LASERS_TO_KILL *40
#define LASERS_TO_KILL *30
// Default hivebot is melee, and a bit more meaty, so it can meatshield for their ranged friends.
/mob/living/simple_animal/hostile/hivebot

View File

@@ -11,8 +11,8 @@
intelligence_level = SA_ANIMAL
cooperative = 1
maxHealth = 60
health = 60
maxHealth = 120
health = 120
turns_per_move = 5
see_in_dark = 6
stop_when_pulled = 0
@@ -43,9 +43,20 @@
meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
var/stance_step = 0
// var/stance_step = 0
/mob/living/simple_animal/hostile/bear/handle_stance()
/mob/living/simple_animal/hostile/bear/handle_stance(var/new_stance)
// Below was a bunch of code that made this specific mob be 'alert' and will hurt you when it gets closer.
// It's commented out because it made infinite loops and the AI is going to be moved/rewritten sometime soon (famous last words)
// and it would be better if this 'alert before attacking' behaviour was on the parent instead of a specific type of mob anyways.
// Instead we're just gonna get angry if we're dying.
..(new_stance)
if(stance == STANCE_ATTACK || stance == STANCE_ATTACKING)
if((health / maxHealth) <= 0.5) // At half health, and fighting someone currently.
add_modifier(/datum/modifier/berserk, 30 SECONDS)
/*
switch(stance)
if(STANCE_TIRED)
stop_automated_movement = 1
@@ -87,6 +98,7 @@
return
else
..()
*/
/mob/living/simple_animal/hostile/bear/update_icons()
..()
@@ -103,7 +115,7 @@
. = ..()
if(.)
custom_emote(1,"stares alertly at [.]")
handle_stance(STANCE_ALERT)
// handle_stance(STANCE_ALERT)
/mob/living/simple_animal/hostile/bear/PunchTarget()
if(!Adjacent(target_mob))

View File

@@ -1474,6 +1474,9 @@
return
set_target(new_target)
/mob/living/simple_animal/is_sentient()
return intelligence_level != SA_PLANT && intelligence_level != SA_ROBOTIC
//Commands, reactions, etc
/mob/living/simple_animal/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
..()

View File

@@ -469,6 +469,10 @@
enrage() // How dare you try to control the red slime.
say("Grrr...!")
/mob/living/simple_animal/slime/red/enrage()
..()
add_modifier(/datum/modifier/berserk, 30 SECONDS)
/mob/living/simple_animal/slime/green
desc = "This slime is radioactive."

View File

@@ -46,5 +46,6 @@
client.perspective = MOB_PERSPECTIVE
reload_fullscreen() // Reload any fullscreen overlays this mob has.
add_click_catcher()
update_client_color()
//set macro to normal incase it was overriden (like cyborg currently does)
winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5")

View File

@@ -1118,3 +1118,11 @@ mob/proc/yank_out_object()
return
var/obj/screen/zone_sel/selector = mob.zone_sel
selector.set_selected_zone(next_in_list(mob.zone_sel.selecting,zones))
// This handles setting the client's color variable, which makes everything look a specific color.
// This proc is here so it can be called without needing to check if the client exists, or if the client relogs.
// This is for inheritence since /mob/living will serve most cases. If you need ghosts to use this you'll have to implement that yourself.
/mob/proc/update_client_color()
if(client && client.color)
animate(client, color = null, time = 10)
return

View File

@@ -0,0 +1,131 @@
// This code is used to give a very rough estimate of how screwed an individual player might be at any given moment when fighting monsters.
// You could use this to have an effect trigger when someone is in serious danger, or as a means for an AI to guess which mob needs to die first.
// The idea and the code structure was taken from Dungeon Crawl Stone Soup.
/atom/movable/proc/get_threat(var/mob/living/threatened)
return 0
/atom/movable/proc/guess_threat_level(var/mob/living/threatened)
return 0
/mob/living/simple_animal
var/threat_level = null // Set this if you want an explicit danger rating.
/mob/living/simple_animal/guess_threat_level(var/mob/living/threatened)
if(threat_level) // If they have a predefined number, use it.
return threat_level
// Otherwise we need to guess how scary this thing is.
var/threat_guess = 0
// First lets consider their attack ability.
var/potential_damage = 0
if(!ranged) //Melee damage.
potential_damage = (melee_damage_lower + melee_damage_upper) / 2
else
if(projectiletype)
var/obj/item/projectile/P = new projectiletype(src)
if(P.nodamage || P.taser_effect) // Tasers are somewhat less scary.
potential_damage = P.agony / 2
else
potential_damage = P.damage
if(P.damage_type == HALLOSS) // Not sure if any projectiles do this, but can't be too safe.
potential_damage /= 2
// Rubber bullets, I guess.
potential_damage += P.agony / 2
if(rapid) // This makes them shoot three times per cycle.
potential_damage *= 3
qdel(P)
threat_guess += potential_damage
// Then consider their defense.
threat_guess += getMaxHealth() / 5 // 100 health translates to 20 threat.
return threat_guess
/mob/living/get_threat(var/mob/living/threatened)
if(stat)
return 0
/mob/living/simple_animal/get_threat(var/mob/living/threatened)
. = ..()
if(!hostile)
return 0 // Can't hurt anyone.
if(incapacitated(INCAPACITATION_DISABLED))
return 0 // Can't currently hurt you if it's stunned.
var/friendly = threatened.faction == faction
var/threat = guess_threat_level()
// Hurt entities contribute less tension.
threat *= health
threat /= getMaxHealth()
// Allies reduce tension instead of adding.
if(friendly)
threat = -threat
else
if(threatened.invisibility > see_invisible)
threat /= 2 // Target cannot be seen by src.
if(invisibility > threatened.see_invisible)
threat *= 2 // Target cannot see src.
// Handle statuses.
if(confused)
threat /= 2
if(has_modifier_of_type(/datum/modifier/berserk))
threat *= 2
// Handle ability to harm.
// Being five tiles away from some spiders is a lot less scary than being in melee range of five spiders at once.
if(!ranged)
threat /= max(get_dist(src, threatened), 1)
return threat
// Gives a rough idea of how much danger someone is in. Meant to be used for PvE things since PvP has too many unknown variables.
/mob/living/proc/get_tension()
var/tension = 0
var/list/potential_threats = list()
// First, get everything threatening to us.
for(var/thing in view(src))
if(isliving(thing))
potential_threats += thing
if(istype(thing, /obj/machinery/porta_turret))
potential_threats += thing
var/danger = FALSE
// Now to get all the threats.
for(var/atom/movable/AM in potential_threats)
var/tension_from_AM = AM.get_threat(src)
tension += tension_from_AM
if(tension_from_AM > 0)
danger = TRUE
if(!danger)
return 0
// Tension is roughly doubled when about to fall into crit.
var/max_health = getMaxHealth()
tension *= 2 * max_health / (health + max_health)
// Being unable to act is really tense.
if(incapacitated(INCAPACITATION_DISABLED) && !lying)
tension *= 10
return tension
if(confused)
tension *= 2
return tension

View File

@@ -48,6 +48,17 @@
if(prob(25))
my_effect.trigger = pick(TRIGGER_WATER, TRIGGER_ACID, TRIGGER_VOLATILE, TRIGGER_TOXIN)
/obj/machinery/artifact/proc/choose_effect()
var/effect_type = input(usr, "What type do you want?", "Effect Type") as null|anything in typesof(/datum/artifact_effect) - /datum/artifact_effect
if(effect_type)
my_effect = new effect_type(src)
if(alert(usr, "Do you want a secondary effect?", "Second Effect", "No", "Yes") == "Yes")
var/second_effect_type = input(usr, "What type do you want as well?", "Second Effect Type") as null|anything in typesof(/datum/artifact_effect) - list(/datum/artifact_effect, effect_type)
secondary_effect = new second_effect_type(src)
else
secondary_effect = null
/obj/machinery/artifact/process()
var/turf/L = loc
if(!istype(L)) // We're inside a container or on null turf, either way stop processing effects

View File

@@ -0,0 +1,43 @@
/datum/artifact_effect/berserk
name = "berserk"
effect_type = EFFECT_PSIONIC
/datum/artifact_effect/berserk/proc/apply_berserk(var/mob/living/L)
if(!istype(L))
return FALSE
if(!L.is_sentient())
return FALSE // Drons are presumably deaf to any psionic things.
if(L.add_modifier(/datum/modifier/berserk, 30 SECONDS))
to_chat(L, "<span class='danger'>An otherworldly feeling seems to enter your mind, and it ignites your mind in fury!</span>")
L.adjustBrainLoss(3) // Playing with berserking alien psychic artifacts isn't good for the mind.
to_chat(L, "<span class='danger'>The inside of your head hurts...</span>")
return TRUE
else
if(L.has_modifier_of_type(/datum/modifier/berserk)) // Already angry.
to_chat(L, "<span class='warning'>An otherworldly feeling seems to enter your mind again, and it fans your inner flame, extending your rage.</span>")
else // Exhausted or something.
to_chat(L, "<span class='warning'>An otherworldly feeling seems to enter your mind, and you briefly feel an intense anger, but \
it quickly passes.</span>")
return FALSE
/datum/artifact_effect/berserk/DoEffectTouch(var/mob/toucher)
if(toucher && isliving(toucher))
apply_berserk(toucher)
return TRUE
/datum/artifact_effect/berserk/DoEffectAura()
if(holder)
var/turf/T = get_turf(holder)
for(var/mob/living/L in range(src.effectrange,T))
if(prob(10))
apply_berserk(L)
return TRUE
/datum/artifact_effect/berserk/DoEffectPulse()
if(holder)
var/turf/T = get_turf(holder)
for(var/mob/living/L in range(src.effectrange,T))
apply_berserk(L)
return TRUE

View File

@@ -409,6 +409,37 @@
new_item = new /obj/item/clothing/mask/gas/poltergeist(src.loc)
else
new_item = new /obj/item/clothing/mask/gas(src.loc)
if(36)
// Alien stuff.
apply_prefix = FALSE
apply_material_decorations = FALSE
var/list/alien_stuff = list(
/obj/item/device/multitool/alien,
/obj/item/stack/cable_coil/alien,
/obj/item/weapon/crowbar/alien,
/obj/item/weapon/screwdriver/alien,
/obj/item/weapon/weldingtool/alien,
/obj/item/weapon/wirecutters/alien,
/obj/item/weapon/wrench/alien,
/obj/item/weapon/surgical/FixOVein/alien,
/obj/item/weapon/surgical/bone_clamp/alien,
/obj/item/weapon/surgical/cautery/alien,
/obj/item/weapon/surgical/circular_saw/alien,
/obj/item/weapon/surgical/hemostat/alien,
/obj/item/weapon/surgical/retractor/alien,
/obj/item/weapon/surgical/scalpel/alien,
/obj/item/weapon/surgical/surgicaldrill/alien,
/obj/item/weapon/cell/device/weapon/recharge/alien,
/obj/item/clothing/suit/armor/alien,
/obj/item/clothing/head/helmet/alien,
/obj/item/clothing/head/psy_crown/wrath
)
var/new_type = pick(alien_stuff)
new_item = new new_type(src.loc)
item_type = new_item.name
var/decorations = ""
if(apply_material_decorations)
source_material = pick("cordite","quadrinium",DEFAULT_WALL_MATERIAL,"titanium","aluminium","ferritic-alloy","plasteel","duranium")

View File

@@ -76,6 +76,7 @@ var/global/list/finds_as_strings = list(
100;ARCHAEO_TELEBEACON,
100;ARCHAEO_TOOL,
100;ARCHAEO_STOCKPARTS,
100;ARCHAEO_ALIEN_ITEM,
75;ARCHAEO_SHARD,
75;ARCHAEO_RODS,
75;ARCHAEO_UNKNOWN,
@@ -111,6 +112,7 @@ var/global/list/finds_as_strings = list(
50;ARCHAEO_CULTROBES,
50;ARCHAEO_CULTBLADE,
50;ARCHAEO_GASMASK,
50;ARCHAEO_ALIEN_ITEM,
25;ARCHAEO_HANDCUFFS,
25;ARCHAEO_BEARTRAP,
25;ARCHAEO_TOOL)

View File

@@ -564,12 +564,19 @@
if(S.stat || S.docile || S.rabid)
continue
S.add_modifier(/datum/modifier/berserk, 30 SECONDS)
if(S.client) // Player slimes always have free will.
to_chat(S, "<span class='warning'>An intense wave of rage almost overcomes you, but you remain in control of yourself.</span>")
to_chat(S, "<span class='warning'>An intense wave of rage is felt from inside, but you remain in control of yourself.</span>")
continue
S.enrage()
for(var/mob/living/carbon/human/H in view(get_turf(holder.my_atom)))
if(H.species.name == "Promethean")
H.add_modifier(/datum/modifier/berserk, 30 SECONDS)
to_chat(H, "<span class='warning'>An intense wave of rage is felt from inside, but you remain in control of yourself.</span>")
log_and_message_admins("Red extract reaction (enrage) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]")
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -405,6 +405,7 @@
#include "code\game\gamemodes\changeling\powers\endoarmor.dm"
#include "code\game\gamemodes\changeling\powers\enfeebling_string.dm"
#include "code\game\gamemodes\changeling\powers\engorged_glands.dm"
#include "code\game\gamemodes\changeling\powers\enrage.dm"
#include "code\game\gamemodes\changeling\powers\epinephrine_overdose.dm"
#include "code\game\gamemodes\changeling\powers\escape_restraints.dm"
#include "code\game\gamemodes\changeling\powers\extract_dna_sting.dm"
@@ -1642,6 +1643,7 @@
#include "code\modules\mob\update_icons.dm"
#include "code\modules\mob\_modifiers\cloning.dm"
#include "code\modules\mob\_modifiers\modifiers.dm"
#include "code\modules\mob\_modifiers\modifiers_misc.dm"
#include "code\modules\mob\_modifiers\traits.dm"
#include "code\modules\mob\_modifiers\traits_phobias.dm"
#include "code\modules\mob\dead\death.dm"
@@ -2259,6 +2261,7 @@
#include "code\modules\tables\rack.dm"
#include "code\modules\tables\tables.dm"
#include "code\modules\tables\update_triggers.dm"
#include "code\modules\tension\tension.dm"
#include "code\modules\turbolift\_turbolift.dm"
#include "code\modules\turbolift\turbolift.dm"
#include "code\modules\turbolift\turbolift_areas.dm"
@@ -2301,6 +2304,7 @@
#include "code\modules\xenoarcheaology\artifacts\gigadrill.dm"
#include "code\modules\xenoarcheaology\artifacts\replicator.dm"
#include "code\modules\xenoarcheaology\effects\badfeeling.dm"
#include "code\modules\xenoarcheaology\effects\berserk.dm"
#include "code\modules\xenoarcheaology\effects\cellcharge.dm"
#include "code\modules\xenoarcheaology\effects\celldrain.dm"
#include "code\modules\xenoarcheaology\effects\cold.dm"