This commit is contained in:
Ghommie
2020-01-05 17:42:54 +01:00
1180 changed files with 44972 additions and 24238 deletions
+1 -1
View File
@@ -68,4 +68,4 @@
new /datum/hallucination/chat(owner, TRUE, FALSE, "<span class='hypnophrase'>[hypnotic_phrase]</span>")
/datum/brain_trauma/hypnosis/handle_hearing(datum/source, list/hearing_args)
hearing_args[HEARING_MESSAGE] = target_phrase.Replace(hearing_args[HEARING_MESSAGE], "<span class='hypnophrase'>$1</span>")
hearing_args[HEARING_RAW_MESSAGE] = target_phrase.Replace(hearing_args[HEARING_RAW_MESSAGE], "<span class='hypnophrase'>$1</span>")
+2 -2
View File
@@ -149,8 +149,8 @@
friend_talk(message)
/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode))
/mob/camera/imaginary_friend/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
to_chat(src, compose_message(speaker, message_language, raw_message, radio_freq, spans, message_mode, FALSE, source))
/mob/camera/imaginary_friend/proc/friend_talk(message)
message = capitalize(trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)))
+1 -1
View File
@@ -241,7 +241,7 @@
if(prob(25))
var/deja_vu = pick_n_take(hear_dejavu)
var/static/regex/quoted_spoken_message = regex("\".+\"", "gi")
hearing_args[HEARING_MESSAGE] = quoted_spoken_message.Replace(hearing_args[HEARING_MESSAGE], "\"[deja_vu]\"") //Quotes included to avoid cases where someone says part of their name
hearing_args[HEARING_RAW_MESSAGE] = quoted_spoken_message.Replace(hearing_args[HEARING_RAW_MESSAGE], "\"[deja_vu]\"") //Quotes included to avoid cases where someone says part of their name
return
if(hear_dejavu.len >= 15)
if(prob(50))
+1 -1
View File
@@ -88,7 +88,7 @@
if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg))
addtimer(CALLBACK(src, .proc/freak_out, null, word), 10) //to react AFTER the chat message
hearing_args[HEARING_MESSAGE] = reg.Replace(hearing_args[HEARING_MESSAGE], "<span class='phobia'>$1</span>")
hearing_args[HEARING_RAW_MESSAGE] = reg.Replace(hearing_args[HEARING_RAW_MESSAGE], "<span class='phobia'>$1</span>")
break
/datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args)
@@ -198,9 +198,9 @@
/datum/brain_trauma/severe/split_personality/brainwashing/handle_hearing(datum/source, list/hearing_args)
if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == hearing_args[HEARING_SPEAKER])
return
var/message = hearing_args[HEARING_MESSAGE]
var/message = hearing_args[HEARING_RAW_MESSAGE]
if(findtext(message, codeword))
hearing_args[HEARING_MESSAGE] = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
hearing_args[HEARING_RAW_MESSAGE] = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
addtimer(CALLBACK(src, /datum/brain_trauma/severe/split_personality.proc/switch_personalities), 10)
/datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args)
+3 -2
View File
@@ -53,7 +53,7 @@
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
return
SEND_SIGNAL(src, COMSIG_COMPONENT_REGISTER_PARENT) //CITADEL EDIT
/datum/component/proc/Initialize(...)
return
@@ -85,7 +85,7 @@
UnregisterFromParent()
/datum/component/proc/UnregisterFromParent()
return
SEND_SIGNAL(src, COMSIG_COMPONENT_UNREGISTER_PARENT) //CITADEL EDIT
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
@@ -184,6 +184,7 @@
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/datum/proc/GetComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
+2
View File
@@ -19,12 +19,14 @@
src.damage_multiplier = damage_multiplier
/datum/component/bane/RegisterWithParent()
. = ..()
if(speciestype)
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/speciesCheck)
else
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/mobCheck)
/datum/component/bane/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_ITEM_AFTERATTACK)
/datum/component/bane/proc/speciesCheck(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
+2
View File
@@ -21,9 +21,11 @@
RegisterSignal(parent, bounce, .proc/bounce_up)
/datum/component/bouncy/RegisterWithParent()
. = ..()
RegisterSignal(parent, bounce_signals, .proc/bounce_up)
/datum/component/bouncy/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, bounce_signals)
/datum/component/bouncy/proc/bounce_up(datum/source)
+72 -1
View File
@@ -4,8 +4,9 @@
var/bonus_modifier = 0 //percentage increase to bonus item chance
var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
var/butchering_enabled = TRUE
var/can_be_blunt = FALSE
/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled)
/datum/component/butchering/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
if(_speed)
speed = _speed
if(_effectiveness)
@@ -16,6 +17,56 @@
butcher_sound = _butcher_sound
if(disabled)
butchering_enabled = FALSE
if(_can_be_blunt)
can_be_blunt = _can_be_blunt
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/onItemAttack)
/datum/component/butchering/proc/onItemAttack(obj/item/source, mob/living/M, mob/living/user)
if(user.a_intent != INTENT_HARM)
return
if(M.stat == DEAD && (M.butcher_results || M.guaranteed_butcher_results)) //can we butcher it?
if(butchering_enabled && (can_be_blunt || source.get_sharpness()))
INVOKE_ASYNC(src, .proc/startButcher, source, M, user)
return COMPONENT_ITEM_NO_ATTACK
if(ishuman(M) && source.force && source.get_sharpness())
var/mob/living/carbon/human/H = M
if((H.health <= H.crit_threshold || (user.pulling == H && user.grab_state >= GRAB_NECK) || H.IsSleeping()) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH) // Only sleeping, neck grabbed, or crit, can be sliced.
if(H.has_status_effect(/datum/status_effect/neck_slice))
user.show_message("<span class='warning'>[H]'s neck has already been already cut, you can't make the bleeding any worse!</span>", 1, \
"<span class='warning'>Their neck has already been already cut, you can't make the bleeding any worse!</span>")
return COMPONENT_ITEM_NO_ATTACK
INVOKE_ASYNC(src, .proc/startNeckSlice, source, H, user)
return COMPONENT_ITEM_NO_ATTACK
/datum/component/butchering/proc/startButcher(obj/item/source, mob/living/M, mob/living/user)
to_chat(user, "<span class='notice'>You begin to butcher [M]...</span>")
playsound(M.loc, butcher_sound, 50, TRUE, -1)
if(do_mob(user, M, speed) && M.Adjacent(source))
Butcher(user, M)
/datum/component/butchering/proc/startNeckSlice(obj/item/source, mob/living/carbon/human/H, mob/living/user)
user.visible_message("<span class='danger'>[user] is slitting [H]'s throat!</span>", \
"<span class='danger'>You start slicing [H]'s throat!</span>", \
"<span class='notice'>You hear a cutting noise!</span>", ignored_mobs = H)
H.show_message("<span class='userdanger'>Your throat is being slit by [user]!</span>", 1, \
"<span class = 'userdanger'>Something is cutting into your neck!</span>", NONE)
log_combat(user, H, "starts slicing the throat of")
playsound(H.loc, butcher_sound, 50, TRUE, -1)
if(do_mob(user, H, CLAMP(500 / source.force, 30, 100)) && H.Adjacent(source))
if(H.has_status_effect(/datum/status_effect/neck_slice))
user.show_message("<span class='warning'>[H]'s neck has already been already cut, you can't make the bleeding any worse!</span>", 1, \
"<span class='warning'>Their neck has already been already cut, you can't make the bleeding any worse!</span>")
return
H.visible_message("<span class='danger'>[user] slits [H]'s throat!</span>", \
"<span class='userdanger'>[user] slits your throat...</span>")
log_combat(user, H, "finishes slicing the throat of")
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD)
H.bleed_rate = CLAMP(H.bleed_rate + 20, 0, 30)
H.apply_status_effect(/datum/status_effect/neck_slice)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
var/turf/T = meat.drop_location()
@@ -50,3 +101,23 @@
/datum/component/butchering/proc/ButcherEffects(mob/living/meat) //extra effects called on butchering, override this via subtypes
return
///Special snowflake component only used for the recycler.
/datum/component/butchering/recycler
/datum/component/butchering/recycler/Initialize(_speed, _effectiveness, _bonus_modifier, _butcher_sound, disabled, _can_be_blunt)
if(!istype(parent, /obj/machinery/recycler)) //EWWW
return COMPONENT_INCOMPATIBLE
. = ..()
if(. == COMPONENT_INCOMPATIBLE)
return
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/onCrossed)
/datum/component/butchering/recycler/proc/onCrossed(datum/source, mob/living/L)
if(!istype(L))
return
var/obj/machinery/recycler/eater = parent
if(eater.safety_mode || (eater.stat & (BROKEN|NOPOWER))) //I'm so sorry.
return
if(L.stat == DEAD && (L.butcher_results || L.guaranteed_butcher_results))
Butcher(parent, L)
+2
View File
@@ -17,6 +17,7 @@
apply()
/datum/component/decal/RegisterWithParent()
. = ..()
if(first_dir)
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/rotate_react)
if(cleanable)
@@ -25,6 +26,7 @@
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
/datum/component/decal/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE))
/datum/component/decal/Destroy()
@@ -30,11 +30,13 @@
return ..()
/datum/component/fantasy/RegisterWithParent()
. = ..()
var/obj/item/master = parent
originalName = master.name
modify()
/datum/component/fantasy/UnregisterFromParent()
. = ..()
unmodify()
/datum/component/fantasy/InheritComponent(datum/component/fantasy/newComp, original, list/arguments)
+2
View File
@@ -9,6 +9,7 @@
src.fire_stacks = fire_stacks
/datum/component/igniter/RegisterWithParent()
. = ..()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
@@ -17,6 +18,7 @@
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/igniter/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/igniter/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
+2
View File
@@ -10,6 +10,7 @@
src.throw_anchored = throw_anchored
/datum/component/knockback/RegisterWithParent()
. = ..()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
@@ -18,6 +19,7 @@
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/knockback/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
+2
View File
@@ -10,6 +10,7 @@
src.flat_heal = flat_heal
/datum/component/lifesteal/RegisterWithParent()
. = ..()
if(isgun(parent))
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
@@ -18,6 +19,7 @@
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/lifesteal/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/lifesteal/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
-9
View File
@@ -150,15 +150,6 @@
if(9)
setSanity(sanity+0.4, maximum=SANITY_GREAT)
if(HAS_TRAIT(owner, TRAIT_DEPRESSION))
if(prob(0.05))
add_event(null, "depression", /datum/mood_event/depression)
clear_event(null, "jolly")
if(HAS_TRAIT(owner, TRAIT_JOLLY))
if(prob(0.05))
add_event(null, "jolly", /datum/mood_event/jolly)
clear_event(null, "depression")
HandleNutrition(owner)
/datum/component/mood/proc/setSanity(amount, minimum=SANITY_INSANE, maximum=SANITY_NEUTRAL)//I'm sure bunging this in here will have no negative repercussions.
+7 -4
View File
@@ -11,8 +11,9 @@
var/list/datum/nanite_program/programs = list()
var/max_programs = NANITE_PROGRAM_LIMIT
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans, and does not display the program list on nanite scans
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
return COMPONENT_INCOMPATIBLE
@@ -34,6 +35,7 @@
cloud_sync()
/datum/component/nanites/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_HAS_NANITES, .proc/confirm_nanites)
RegisterSignal(parent, COMSIG_NANITE_UI_DATA, .proc/nanite_ui_data)
RegisterSignal(parent, COMSIG_NANITE_GET_PROGRAMS, .proc/get_programs)
@@ -57,6 +59,7 @@
RegisterSignal(parent, COMSIG_NANITE_SIGNAL, .proc/receive_signal)
/datum/component/nanites/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_HAS_NANITES,
COMSIG_NANITE_UI_DATA,
COMSIG_NANITE_GET_PROGRAMS,
@@ -250,8 +253,8 @@
to_chat(user, "<span class='info'>Cloud ID: [cloud_id ? cloud_id : "Disabled"]</span>")
to_chat(user, "<span class='info'>================</span>")
to_chat(user, "<span class='info'>Program List:</span>")
if(stealth)
to_chat(user, "<span class='alert'>%#$ENCRYPTED&^@</span>")
if(!diagnostics)
to_chat(user, "<span class='alert'>Diagnostics Disabled</span>")
else
for(var/X in programs)
var/datum/nanite_program/NP = X
+2
View File
@@ -20,12 +20,14 @@
begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/datum/component/orbiter/RegisterWithParent()
. = ..()
var/atom/target = parent
while(ismovableatom(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react)
target = target.loc
/datum/component/orbiter/UnregisterFromParent()
. = ..()
var/atom/target = parent
while(ismovableatom(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+1
View File
@@ -106,6 +106,7 @@
if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))
return
BaseRot(user, rotation)
return TRUE
/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user)
if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction))
+2
View File
@@ -13,10 +13,12 @@
src.override_projectile_range = override_projectile_range
/datum/component/shrapnel/RegisterWithParent()
. = ..()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
/datum/component/shrapnel/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_PROJECTILE_ON_HIT))
/datum/component/shrapnel/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
+42
View File
@@ -0,0 +1,42 @@
/datum/component/shrink
var/olddens
var/oldopac
dupe_mode = COMPONENT_DUPE_HIGHLANDER
/datum/component/shrink/Initialize(shrink_time)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
var/atom/parent_atom = parent
parent_atom.transform = parent_atom.transform.Scale(0.5,0.5)
olddens = parent_atom.density
oldopac = parent_atom.opacity
parent_atom.density = 0
parent_atom.opacity = 0
if(isliving(parent_atom))
var/mob/living/L = parent_atom
L.add_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY, update=TRUE, priority=100, multiplicative_slowdown=4)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.unequip_everything()
C.visible_message("<span class='warning'>[C]'s belongings fall off of [C.p_them()] as they shrink down!</span>",
"<span class='userdanger'>Your belongings fall away as everything grows bigger!</span>")
if(ishuman(C))
var/mob/living/carbon/human/H = C
H.physiology.damage_resistance -= 100//carbons take double damage while shrunk
parent_atom.visible_message("<span class='warning'>[parent_atom] shrinks down to a tiny size!</span>",
"<span class='userdanger'>Everything grows bigger!</span>")
QDEL_IN(src, shrink_time)
/datum/component/shrink/Destroy()
var/atom/parent_atom = parent
parent_atom.transform = parent_atom.transform.Scale(2,2)
parent_atom.density = olddens
parent_atom.opacity = oldopac
if(isliving(parent_atom))
var/mob/living/L = parent_atom
L.remove_movespeed_modifier(MOVESPEED_ID_SHRINK_RAY)
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.physiology.damage_resistance += 100
..()
+25
View File
@@ -0,0 +1,25 @@
/datum/component/sizzle
var/mutable_appearance/sizzling
var/sizzlealpha = 0
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/datum/component/sizzle/Initialize()
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
setup_sizzle()
/datum/component/sizzle/InheritComponent(datum/component/C, i_am_original)
var/atom/food = parent
sizzlealpha += 5
sizzling.alpha = sizzlealpha
food.cut_overlay(sizzling)
food.add_overlay(sizzling)
/datum/component/sizzle/proc/setup_sizzle()
var/atom/food = parent
var/icon/grill_marks = icon(initial(food.icon), initial(food.icon_state)) //we only want to apply grill marks to the initial icon_state for each object
grill_marks.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
grill_marks.Blend(icon('icons/obj/kitchen.dmi', "grillmarks"), ICON_MULTIPLY) //adds grill marks and the remaining white areas become transparent
sizzling = new(grill_marks)
sizzling.alpha = sizzlealpha
food.add_overlay(sizzling)
@@ -66,7 +66,7 @@
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
. = TRUE
var/atom/real_location = real_location()
if(I.loc != real_location)
if(I.loc != real_location && real_location)
I.forceMove(real_location)
refresh_mob_views()
+10 -9
View File
@@ -57,7 +57,7 @@
var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise.
var/screen_start_y = 2
//End
var/limited_random_access = FALSE //Quick if statement in accessible_items to determine if we care at all about what people can access at once.
var/limited_random_access_stack_position = 0 //If >0, can only access top <x> items
var/limited_random_access_stack_bottom_up = FALSE //If TRUE, above becomes bottom <x> items
@@ -647,9 +647,9 @@
if(M == viewing)
to_chat(usr, "<span class='notice'>You put [I] [insert_preposition]to [parent].</span>")
else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", MSG_VISUAL)
/datum/component/storage/proc/update_icon()
if(isobj(parent))
@@ -762,7 +762,7 @@
if(!isliving(user) || !user.CanReach(parent))
return
if(check_locked(source, user, TRUE))
return
return TRUE
var/atom/A = parent
if(!quickdraw)
@@ -770,19 +770,20 @@
user_show_to_mob(user)
if(rustle_sound)
playsound(A, "rustle", 50, 1, -5)
return
return TRUE
if(!user.incapacitated())
if(user.can_hold_items() && !user.incapacitated())
var/obj/item/I = locate() in real_location()
if(!I)
return
A.add_fingerprint(user)
remove_from_storage(I, get_turf(user))
if(!user.put_in_hands(I))
to_chat(user, "<span class='notice'>You fumble for [I] and it falls on the floor.</span>")
return
user.visible_message("<span class='warning'>[user] fumbles with the [parent], letting [I] fall on the floor.</span>", \
"<span class='notice'>You fumble with [parent], letting [I] fall on the floor.</span>")
return TRUE
user.visible_message("<span class='warning'>[user] draws [I] from [parent]!</span>", "<span class='notice'>You draw [I] from [parent].</span>")
return
return TRUE
/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
gather_mode_switch(source.owner)
+2
View File
@@ -24,6 +24,7 @@
src.faction = faction
/datum/component/summoning/RegisterWithParent()
. = ..()
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
else if(isitem(parent))
@@ -32,6 +33,7 @@
RegisterSignal(parent, COMSIG_HOSTILE_ATTACKINGTARGET, .proc/hostile_attackingtarget)
/datum/component/summoning/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/summoning/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
+2
View File
@@ -9,10 +9,12 @@
src.allowed_slot = allowed_slot
/datum/component/tactical/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/modify)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/unmodify)
/datum/component/tactical/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED))
unmodify()
+205 -88
View File
@@ -1,128 +1,245 @@
/**
* The virtual reality turned component.
* Originally created to overcome issues of mob polymorphing locking the player inside virtual reality
* and allow for a more "immersive" virtual reality in a virtual reality experience.
* It relies on comically complex order of logic, expect things to break if procs such as mind/transfer_to() are revamped.
* In short, a barebone not so hardcoded VR framework.
* If you plan to add more devices that make use of this component, remember to isolate their code outta here where possible.
*/
/datum/component/virtual_reality
can_transfer = TRUE
var/datum/mind/mastermind // where is my mind t. pixies
//the player's mind (not the parent's), should something happen to them or to their mob.
var/datum/mind/mastermind
//the current mob's mind, which we need to keep track for mind transfer.
var/datum/mind/current_mind
var/obj/machinery/vr_sleeper/vr_sleeper
//the action datum used by the mob to quit the vr session.
var/datum/action/quit_vr/quit_action
//This one's name should be self explainatory, currently used for emags.
var/you_die_in_the_game_you_die_for_real = FALSE
var/datum/component/virtual_reality/inception //The component works on a very fragile link betwixt mind, ckey and death.
//Used to allow people to play recursively playing vr while playing vr without many issues.
var/datum/component/virtual_reality/level_below
var/datum/component/virtual_reality/level_above
//Used to stop the component from executing certain functions that'd cause us some issues otherwise.
//FALSE if there is a connected player, otherwise TRUE.
var/session_paused = TRUE
//Used to stop unwarranted behaviour from happening in cases where the master mind transference is unsupported. Set on Initialize().
var/allow_mastermind_transfer = FALSE
/datum/component/virtual_reality/Initialize(mob/M, obj/machinery/vr_sleeper/gaming_pod, yolo = FALSE, new_char = TRUE)
if(!ismob(parent) || !istype(M))
/datum/component/virtual_reality/Initialize(yolo = FALSE, _allow_mastermind_transfer = FALSE)
var/mob/M = parent
if(!istype(M) || !M.mind)
return COMPONENT_INCOMPATIBLE
var/mob/vr_M = parent
mastermind = M.mind
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/switch_player)
RegisterSignal(mastermind, COMSIG_MIND_TRANSFER, .proc/switch_player)
you_die_in_the_game_you_die_for_real = yolo
quit_action = new()
if(gaming_pod)
vr_sleeper = gaming_pod
RegisterSignal(vr_sleeper, COMSIG_ATOM_EMAG_ACT, .proc/you_only_live_once)
RegisterSignal(vr_sleeper, COMSIG_MACHINE_EJECT_OCCUPANT, .proc/revert_to_reality)
vr_M.ckey = M.ckey
var/datum/component/virtual_reality/clusterfk = M.GetComponent(/datum/component/virtual_reality)
if(clusterfk && !clusterfk.inception)
clusterfk.inception = src
SStgui.close_user_uis(M, src)
allow_mastermind_transfer = _allow_mastermind_transfer
quit_action = new
/datum/component/virtual_reality/Destroy()
QDEL_NULL(quit_action)
if(level_above)
level_above.level_below = null
level_above = null
if(level_below)
level_below.level_above = null
level_below = null
return ..()
/datum/component/virtual_reality/RegisterWithParent()
. = ..()
var/mob/M = parent
current_mind = M.mind
if(!quit_action)
quit_action = new
quit_action.Grant(M)
RegisterSignal(quit_action, COMSIG_ACTION_TRIGGER, .proc/revert_to_reality)
RegisterSignal(quit_action, COMSIG_ACTION_TRIGGER, .proc/action_trigger)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/be_a_quitter)
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/pass_me_the_remote)
RegisterSignal(current_mind, COMSIG_MIND_TRANSFER, .proc/pass_me_the_remote)
mastermind.current.audiovisual_redirect = M
if(vr_sleeper)
vr_sleeper.vr_mob = M
RegisterSignal(M, COMSIG_MOB_KEY_CHANGE, .proc/on_player_transfer)
RegisterSignal(current_mind, COMSIG_MIND_TRANSFER, .proc/on_player_transfer)
RegisterSignal(current_mind, COMSIG_PRE_MIND_TRANSFER, .proc/pre_player_transfer)
if(mastermind?.current)
mastermind.current.audiovisual_redirect = M
/datum/component/virtual_reality/UnregisterFromParent()
quit_action.Remove(parent)
. = ..()
if(quit_action)
quit_action.Remove(parent)
UnregisterSignal(quit_action, COMSIG_ACTION_TRIGGER)
UnregisterSignal(parent, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MOB_KEY_CHANGE, COMSIG_MOB_GHOSTIZE))
UnregisterSignal(current_mind, COMSIG_MIND_TRANSFER)
UnregisterSignal(quit_action, COMSIG_ACTION_TRIGGER)
UnregisterSignal(current_mind, list(COMSIG_MIND_TRANSFER, COMSIG_PRE_MIND_TRANSFER))
current_mind = null
mastermind.current.audiovisual_redirect = null
if(mastermind?.current)
mastermind.current.audiovisual_redirect = null
/datum/component/virtual_reality/proc/switch_player(datum/source, mob/new_mob, mob/old_mob)
if(vr_sleeper || !new_mob.mind)
// Machineries currently don't deal up with the occupant being polymorphed et similar... Or did something fuck up?
revert_to_reality()
return
old_mob.audiovisual_redirect = null
new_mob.audiovisual_redirect = parent
/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source)
if(source != quit_action)
return COMPONENT_ACTION_BLOCK_TRIGGER
revert_to_reality(signal_source)
/**
* Called when attempting to connect a mob to a virtual reality mob.
* This will return FALSE if the mob is without player or dead. TRUE otherwise
*/
/datum/component/virtual_reality/proc/connect(mob/M)
var/mob/vr_M = parent
if(!M.mind || M.stat == DEAD || !vr_M.mind || vr_M.stat == DEAD)
return FALSE
var/datum/component/virtual_reality/VR = M.GetComponent(/datum/component/virtual_reality)
if(VR)
VR.level_below = src
level_above = VR
M.transfer_ckey(vr_M, FALSE)
mastermind = M.mind
mastermind.current.audiovisual_redirect = parent
RegisterSignal(mastermind, COMSIG_PRE_MIND_TRANSFER, .proc/switch_player)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_PRE_PLAYER_CHANGE, .proc/player_hijacked)
SStgui.close_user_uis(vr_M, src)
session_paused = FALSE
return TRUE
/**
* emag_act() hook. Makes the game deadlier, killing the mastermind mob too should the parent die.
*/
/datum/component/virtual_reality/proc/you_only_live_once()
if(you_die_in_the_game_you_die_for_real || vr_sleeper?.only_current_user_can_interact)
if(you_die_in_the_game_you_die_for_real)
return FALSE
you_die_in_the_game_you_die_for_real = TRUE
return TRUE
/datum/component/virtual_reality/proc/pass_me_the_remote(datum/source, mob/new_mob)
if(new_mob == mastermind.current)
revert_to_reality(source)
return TRUE
new_mob.TakeComponent(src)
return TRUE
/**
* Called when the mastermind mind is transferred to another mob.
* This is pretty much just going to simply quit the session until machineries support polymorphed occupants etcetera.
*/
/datum/component/virtual_reality/proc/switch_player(datum/source, mob/new_mob, mob/old_mob)
if(session_paused)
return
if(!allow_mastermind_transfer)
quit()
return COMPONENT_STOP_MIND_TRANSFER
UnregisterSignal(old_mob, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MOB_PRE_PLAYER_CHANGE))
RegisterSignal(new_mob, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(new_mob, COMSIG_MOB_PRE_PLAYER_CHANGE, .proc/player_hijacked)
old_mob.audiovisual_redirect = null
new_mob.audiovisual_redirect = parent
/**
* Called to stop the player mind from being transferred should the new mob happen to be one of our masterminds'.
* Since the target's mind.current is going to be null'd in the mind transfer process,
* This has to be done in a different signal proc than on_player_transfer(), by then the mastermind.current will be null.
*/
/datum/component/virtual_reality/proc/pre_player_transfer(datum/source, mob/new_mob, mob/old_mob)
if(!mastermind || session_paused)
return
if(new_mob == mastermind.current)
quit()
return COMPONENT_STOP_MIND_TRANSFER
if(!level_above)
return
var/datum/component/virtual_reality/VR = level_above
while(VR)
if(VR.mastermind.current == new_mob)
VR.quit() //this will revert the ckey back to new_mob.
return COMPONENT_STOP_MIND_TRANSFER
VR = VR.level_above
/**
* Called when someone or something else is somewhat about to replace the mastermind's mob key somehow.
* And potentially lock the player in a broken virtual reality plot. Not really something to be proud of.
*/
/datum/component/virtual_reality/proc/player_hijacked(datum/source, mob/our_character, mob/their_character)
if(session_paused)
return
if(!their_character)
quit(cleanup = TRUE)
return
var/will_it_be_handled_in_their_pre_player_transfer = FALSE
var/datum/component/virtual_reality/VR = src
while(VR)
if(VR.parent == their_character)
will_it_be_handled_in_their_pre_player_transfer = TRUE
break
VR = VR.level_below
if(!will_it_be_handled_in_their_pre_player_transfer) //it's not the player playing shenanigeans, abandon all ships.
quit(cleanup = TRUE)
/**
* Takes care of moving the component from a mob to another when their mind or ckey is transferred.
* The very reason this component even exists (else one would be stuck playing as a monky if monkyified)
*/
/datum/component/virtual_reality/proc/on_player_transfer(datum/source, mob/new_mob, mob/old_mob)
new_mob.TakeComponent(src)
/**
* Required for the component to be transferable from mob to mob.
*/
/datum/component/virtual_reality/PostTransfer()
if(!ismob(parent))
return COMPONENT_INCOMPATIBLE
/**
*The following procs simply acts as hooks for quit(), since components do not use callbacks anymore
*/
/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source)
quit()
return COMPONENT_ACTION_BLOCK_TRIGGER
/datum/component/virtual_reality/proc/revert_to_reality(datum/source)
quit_it()
quit()
/datum/component/virtual_reality/proc/game_over(datum/source)
quit_it(TRUE, TRUE)
quit(you_die_in_the_game_you_die_for_real, TRUE)
return COMPONENT_BLOCK_DEATH_BROADCAST
/datum/component/virtual_reality/proc/be_a_quitter(datum/source, can_reenter_corpse)
quit_it()
return COMPONENT_BLOCK_GHOSTING
/datum/component/virtual_reality/proc/be_a_quitter(datum/source, can_reenter_corpse, special = FALSE, penalize = FALSE)
if(!special)
quit()
return COMPONENT_BLOCK_GHOSTING
/datum/component/virtual_reality/proc/virtual_reality_in_a_virtual_reality(mob/player, killme = FALSE, datum/component/virtual_reality/yo_dawg)
/datum/component/virtual_reality/proc/machine_destroyed(datum/source)
quit(cleanup = TRUE)
/**
* Takes care of deleting itself, moving the player back to the mastermind's current and queueing the parent for deletion.
* It supports nested virtual realities by recursively calling vr_in_a_vr(), which in turns calls quit(),
* up to the deepest level, where the ckey will be transferred back to our mastermind's mob instead.
* The above operation is skipped when session_paused is TRUE (ergo no player in control of the current mob).
* vars:
* * deathcheck is used to kill the master, you want this FALSE unless for stuff that doesn't involve emagging.
* * cleanup is used to queue the parent for the next vr_clean_master's run, where they'll be deleted should they be dead.
* * mob/override is used for the recursive virtual reality explained above and shouldn't be used outside of vr_in_a_vr().
*/
/datum/component/virtual_reality/proc/quit(deathcheck = FALSE, cleanup = FALSE, mob/override)
var/mob/M = parent
quit_it(FALSE, killme, player, yo_dawg)
yo_dawg.inception = null
if(killme)
M.death(FALSE)
/datum/component/virtual_reality/proc/quit_it(deathcheck = FALSE, cleanup = FALSE, mob/override)
var/mob/M = parent
var/mob/dreamer = override ? override : mastermind.current
if(!mastermind)
to_chat(M, "<span class='warning'>You feel a dreadful sensation, something terrible happened. You try to wake up, but you find yourself unable to...</span>")
else
var/key_transfer = FALSE
if(inception?.parent)
inception.virtual_reality_in_a_virtual_reality(dreamer, cleanup, src)
if(!session_paused)
session_paused = TRUE
var/mob/dreamer = override || mastermind.current
if(!dreamer) //This shouldn't happen.
stack_trace("virtual reality component quit() called without a mob to transfer the parent ckey to.")
to_chat(M, "<span class='warning'>You feel a dreadful sensation, something terrible happened. You try to wake up, but you find yourself unable to...</span>")
qdel(src)
return
if(level_below?.parent)
level_below.vr_in_a_vr(dreamer, deathcheck, (deathcheck && cleanup))
else
key_transfer = TRUE
if(key_transfer)
M.transfer_ckey(dreamer, FALSE)
dreamer.stop_sound_channel(CHANNEL_HEARTBEAT)
dreamer.audiovisual_redirect = null
if(deathcheck && you_die_in_the_game_you_die_for_real)
to_chat(mastermind, "<span class='warning'>You feel everything fading away...</span>")
dreamer.death(FALSE)
if(cleanup)
var/obj/effect/vr_clean_master/cleanbot = locate() in get_area(M)
if(cleanbot)
LAZYADD(cleanbot.corpse_party, M)
if(vr_sleeper)
vr_sleeper.vr_mob = null
vr_sleeper = null
qdel(src)
if(deathcheck)
to_chat(dreamer, "<span class='warning'>You feel everything fading away...</span>")
dreamer.death(FALSE)
mastermind.current.audiovisual_redirect = null
if(!cleanup)
if(level_above)
level_above.level_below = null
level_above = null
UnregisterSignal(mastermind.current, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MOB_PRE_PLAYER_CHANGE))
UnregisterSignal(mastermind, COMSIG_PRE_MIND_TRANSFER)
mastermind = null
if(cleanup)
var/obj/effect/vr_clean_master/cleanbot = locate() in get_area(M)
if(cleanbot)
LAZYOR(cleanbot.corpse_party, M)
qdel(src)
/datum/component/virtual_reality/Destroy()
var/datum/action/quit_vr/delet_me = quit_action
. = ..()
qdel(delet_me)
/**
* Used for recursive virtual realities shenanigeans and should be called only through the above proc.
*/
/datum/component/virtual_reality/proc/vr_in_a_vr(mob/player, deathcheck = FALSE, lethal_cleanup = FALSE)
var/mob/M = parent
quit(deathcheck, lethal_cleanup, player)
M.audiovisual_redirect = null
if(lethal_cleanup)
M.death(FALSE)
+2
View File
@@ -34,10 +34,12 @@
last_process = world.time
/datum/component/wet_floor/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
/datum/component/wet_floor/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
/datum/component/wet_floor/Destroy()
+1 -1
View File
@@ -255,7 +255,7 @@
M.fields["alg_d"] = "No allergies have been detected in this patient."
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = "No notes."
M.fields["notes"] = H.get_trait_string(medical)
medical += M
//Security Record
+26
View File
@@ -1398,3 +1398,29 @@
var/mob/living/carbon/human/H = locate(href_list["copyoutfit"]) in GLOB.carbon_list
if(istype(H))
H.copy_outfit()
else if(href_list["modquirks"])
if(!check_rights(R_SPAWN))
return
var/mob/living/carbon/human/H = locate(href_list["modquirks"]) in GLOB.mob_list
if(!istype(H))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon/human")
return
var/list/options = list("Clear"="Clear")
for(var/x in subtypesof(/datum/quirk))
var/datum/quirk/T = x
var/qname = initial(T.name)
options[H.has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T
var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in options
if(result)
if(result == "Clear")
for(var/datum/quirk/q in H.roundstart_quirks)
H.remove_quirk(q.type)
else
var/T = options[result]
if(H.has_quirk(T))
H.remove_quirk(T)
else
H.add_quirk(T,TRUE)
-1
View File
@@ -254,7 +254,6 @@
if(icon_update)
update_body()
update_hair()
update_body_parts()
update_mutations_overlay()// no lizard with human hulk overlay please.
+10
View File
@@ -174,3 +174,13 @@
/datum/dog_fashion/back/deathsquad
name = "Trooper REAL_NAME"
desc = "That's not red paint. That's real corgi blood."
/datum/dog_fashion/head/colour
name = "Stylish REAL_NAME"
desc = "From the tips of their paws to the top of their head, they look like a made bed."
emote_see = list("tries to tap dances.","looks sadly at others outfits...","barks at bad fashion!")
/datum/dog_fashion/head/telegram
name = "Messenger REAL_NAME"
desc = "Dont shoot the messenger..."
emote_see = list("licks an envelope.","looks ready to set off to send a letter...","works on barking!")
+4 -4
View File
@@ -38,12 +38,12 @@
//we want to delay the effect to be displayed after the mob is petted, not before.
switch(user.a_intent)
if(INTENT_HARM, INTENT_DISARM)
addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1)
if(INTENT_HELP)
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
if(INTENT_HELP)
addtimer(CALLBACK(src, .proc/pet_the_dog, source, user), 1)
/datum/element/wuv/proc/pet_the_dog(mob/target, mob/user)
if(!QDELETED(target) || !QDELETED(user) || target.stat == DEAD)
if(!QDELETED(target) || !QDELETED(user) || target.stat != CONSCIOUS)
return
new /obj/effect/temp_visual/heart(target.loc)
if(pet_emote)
@@ -52,7 +52,7 @@
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, target, pet_moodlet, target)
/datum/element/wuv/proc/kick_the_dog(mob/target, mob/user)
if(!QDELETED(target) || !QDELETED(user) || target.stat == DEAD)
if(!QDELETED(target) || !QDELETED(user) || target.stat != CONSCIOUS)
return
if(punt_emote)
target.emote("me", punt_type, punt_emote)
+2 -1
View File
@@ -136,9 +136,10 @@
/datum/emote/sound
var/sound //Sound to play when emote is called
var/vary = FALSE //used for the honk borg emote
var/volume = 50
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon)
/datum/emote/sound/run_emote(mob/user, params)
. = ..()
if(.)
playsound(user.loc, sound, 50, vary)
playsound(user.loc, sound, volume, vary)
+1 -1
View File
@@ -198,7 +198,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/list/items = list()
for(var/I in T)
var/atom/A = I
if (!A.prevent_content_explosion()) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
if (!(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
items += A.GetAllContents()
for(var/O in items)
var/atom/A = O
+1
View File
@@ -27,6 +27,7 @@ GLOBAL_LIST_INIT(huds, list(
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
))
/datum/atom_hud
+11 -2
View File
@@ -4,7 +4,7 @@
mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1)
mid_length = 10
end_sound = 'sound/machines/shower/shower_end.ogg'
volume = 20
volume = 10
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -32,7 +32,7 @@
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
mid_length = 2
end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg'
volume = 15
volume = 5
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -43,3 +43,12 @@
mid_length = 10
end_sound = 'sound/machines/microwave/microwave-end.ogg'
volume = 90
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/looping_sound/grill
mid_length = 2
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
volume = 10
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+7 -5
View File
@@ -8,9 +8,9 @@
var/deflection_chance = 0 //Chance to deflect projectiles
var/reroute_deflection = FALSE //Delete the bullet, or actually deflect it in some direction?
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
var/dodge_chance = 0
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/help_verb
var/no_guns = FALSE
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
@@ -28,14 +28,16 @@
/datum/martial_art/proc/add_to_streak(element,mob/living/carbon/human/D)
if(D != current_target)
current_target = D
streak = ""
restraining = 0
reset_streak(D)
streak = streak+element
if(length(streak) > max_streak_length)
streak = copytext(streak,2)
return
/datum/martial_art/proc/reset_streak(mob/living/carbon/human/new_target)
current_target = new_target
streak = ""
/datum/martial_art/proc/basic_hit(mob/living/carbon/human/A,mob/living/carbon/human/D)
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
@@ -81,7 +83,7 @@
D.forcesay(GLOB.hit_appends)
return 1
/datum/martial_art/proc/teach(mob/living/carbon/human/H,make_temporary=0)
/datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE)
if(!istype(H) || !H.mind)
return FALSE
if(H.mind.martial_art)
+34 -34
View File
@@ -9,24 +9,12 @@
id = MARTIALART_CQC
help_verb = /mob/living/carbon/human/proc/CQC_help
block_chance = 75
var/just_a_cook = FALSE
var/static/list/areas_under_siege = typecacheof(list(/area/crew_quarters/kitchen,
/area/crew_quarters/cafeteria,
/area/crew_quarters/bar))
var/old_grab_state = null
/datum/martial_art/cqc/under_siege
name = "Close Quarters Cooking"
just_a_cook = TRUE
/datum/martial_art/cqc/proc/drop_restraining()
/datum/martial_art/cqc/reset_streak(mob/living/carbon/human/new_target)
. = ..()
restraining = FALSE
/datum/martial_art/cqc/can_use(mob/living/carbon/human/H)
var/area/A = get_area(H)
if(just_a_cook && !(is_type_in_typecache(A, areas_under_siege)))
return FALSE
return ..()
/datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
@@ -75,6 +63,7 @@
D.apply_damage(10, BRUTE)
log_combat(A, D, "kicked (CQC)")
if(D.IsKnockdown() && !D.stat)
log_combat(A, D, "knocked out (Head kick)(CQC)")
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking [D.p_them()] out!</span>", \
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
@@ -85,7 +74,8 @@
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
D.visible_message("<span class='warning'>[A] forces their arm on [D]'s neck!</span>")
log_combat(A, D, "pressured (CQC)")
D.visible_message("<span class='warning'>[A] punches [D]'s neck!</span>")
D.adjustStaminaLoss(60)
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
return TRUE
@@ -96,18 +86,20 @@
if(!can_use(A))
return FALSE
if(!D.stat)
log_combat(A, D, "restrained (CQC)")
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
D.adjustStaminaLoss(20)
D.Stun(100)
restraining = TRUE
addtimer(CALLBACK(src, .proc/drop_restraining), 50, TIMER_UNIQUE)
addtimer(VARSET_CALLBACK(src, restraining, FALSE), 50, TIMER_UNIQUE)
return TRUE
/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
if(!D.stat)
log_combat(A, D, "consecutive CQC'd (CQC)")
D.visible_message("<span class='warning'>[A] strikes [D]'s abdomen, neck and back consecutively</span>", \
"<span class='userdanger'>[A] strikes your abdomen, neck and back consecutively!</span>")
playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
@@ -119,23 +111,20 @@
return TRUE
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
return FALSE
add_to_streak("G",D)
if(check_streak(A,D))
return TRUE
if(A == D) // no self grab.
return FALSE
if(A.grab_state >= GRAB_AGGRESSIVE)
if(A.a_intent == INTENT_GRAB && A!=D && can_use(A)) // A!=D prevents grabbing yourself
add_to_streak("G",D)
if(check_streak(A,D)) //if a combo is made no grab upgrade is done
return TRUE
old_grab_state = A.grab_state
D.grabbedby(A, 1)
else
A.start_pulling(D, 1)
if(A.pulling)
D.stop_pulling()
if(old_grab_state == GRAB_PASSIVE)
D.drop_all_held_items()
A.grab_state = GRAB_AGGRESSIVE //Instant agressive grab if on grab intent
log_combat(A, D, "grabbed", addition="aggressively")
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
return TRUE
D.visible_message("<span class='warning'>[A] violently grabs [D]!</span>", \
"<span class='userdanger'>[A] violently grabs you!</span>")
return TRUE
return FALSE
/datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!can_use(A))
@@ -190,6 +179,7 @@
playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
log_combat(A, D, "disarmed (CQC)", "[I ? " grabbing \the [I]" : ""]")
if(restraining && A.pulling == D)
log_combat(A, D, "knocked out (Chokehold)(CQC)")
D.visible_message("<span class='danger'>[A] puts [D] into a chokehold!</span>", \
"<span class='userdanger'>[A] puts you into a chokehold!</span>")
D.SetSleeping(400)
@@ -208,9 +198,19 @@
to_chat(usr, "<b><i>You try to remember some of the basics of CQC.</i></b>")
to_chat(usr, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, knocking them down.")
to_chat(usr, "<span class='notice'>CQC Kick</span>: Disarm Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.")
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.")
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.")
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a chokehold.")
to_chat(usr, "<span class='notice'>Pressure</span>: Disarm Grab. Decent stamina damage.")
to_chat(usr, "<span class='notice'>Consecutive CQC</span>: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
to_chat(usr, "<b><i>In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.</i></b>")
///Subtype of CQC. Only used for the chef.
/datum/martial_art/cqc/under_siege
name = "Close Quarters Cooking"
///Prevents use if the cook is not in the kitchen.
/datum/martial_art/cqc/under_siege/can_use(mob/living/carbon/human/H) //this is used to make chef CQC only work in kitchen
if(!istype(get_area(H), /area/crew_quarters/kitchen))
return FALSE
return ..()
+158
View File
@@ -0,0 +1,158 @@
#define SIDE_KICK_COMBO "DH"
#define SHOULDER_FLIP_COMBO "GHDGHH"
#define REPULSE_PUNCH_COMBO "GHGH"
#define FOOT_SMASH_COMBO "HH"
#define DEFT_SWITCH_COMBO "GDD"
/datum/martial_art/the_rising_bass
name = "The Rising Bass"
id = MARTIALART_RISINGBASS
dodge_chance = 100
allow_temp_override = FALSE
help_verb = /mob/living/carbon/human/proc/rising_bass_help
/datum/martial_art/the_rising_bass/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(findtext(streak,SIDE_KICK_COMBO))
streak = ""
sideKick(A,D)
return 1
if(findtext(streak,SHOULDER_FLIP_COMBO))
streak = ""
shoulderFlip(A,D)
return 1
if(findtext(streak,REPULSE_PUNCH_COMBO))
streak = ""
repulsePunch(A,D)
return 1
if(findtext(streak,FOOT_SMASH_COMBO))
streak = ""
footSmash(A,D)
return 1
if(findtext(streak,DEFT_SWITCH_COMBO))
streak = ""
deftSwitch(A,D)
return 1
return 0
/datum/martial_art/the_rising_bass/proc/sideKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.IsKnockdown() || D.lying == 0)
var/turf/H = get_step(D, A.dir & (NORTH | SOUTH) ? pick(EAST, WEST) : pick(NORTH, SOUTH))
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] kicks [D] in the side, sliding them over!</span>", \
"<span class='userdanger'>[A] kicks you in the side, forcing you to step away!</span>")
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
D.Knockdown(60)
var/L = H
for(var/obj/i in H.contents)
if(!istype(i,/mob) && i.density == 1)
L = D.loc
D.forceMove(L)
log_combat(A, D, "side kicked (Rising Bass)")
return 1
return basic_hit(A,D)
/datum/martial_art/the_rising_bass/proc/shoulderFlip(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.IsKnockdown() || !D.lying)
var/turf/H = get_step(A, get_dir(D,A))
var/L = H
for(var/obj/i in H.contents)
if(!istype(i,/mob) && i.density == 1)//(i.anchored == 1 && i.density == 1) || istype(i,/obj/structure) || istype(i,/turf/closed)
L = A.loc
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] flips [D] over their shoulder, slamming them into the ground!</span>", \
"<span class='userdanger'>[A] flips you over their shoulder, slamming you into the ground!</span>")
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
D.emote("scream")
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
D.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
D.Sleeping(60)
D.Knockdown(300)
D.forceMove(L)
log_combat(A, D, "shoulder flipped (Rising Bass)")
return 1
return basic_hit(A,D)
/datum/martial_art/the_rising_bass/proc/repulsePunch(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.IsKnockdown() || !D.lying)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] smashes [D] in the chest, throwing them away!</span>", \
"<span class='userdanger'>[A] smashes you in the chest, repelling you away!</span>")
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
var/atom/F = get_edge_target_turf(D, get_dir(A, get_step_away(D, A)))
D.throw_at(F, 10, 1)
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
D.Knockdown(90)
log_combat(A, D, "repulse punched (Rising Bass)")
return 1
return basic_hit(A,D)
/datum/martial_art/the_rising_bass/proc/footSmash(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.IsKnockdown() || !D.lying)
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] smashes their foot down on [D]'s foot!</span>", \
"<span class='userdanger'>[A] smashes your foot!</span>")
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
D.dropItemToGround(D.get_active_held_item())
log_combat(A, D, "foot smashed (Rising Bass)")
return 1
return basic_hit(A,D)
/datum/martial_art/the_rising_bass/proc/deftSwitch(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.IsKnockdown() || !D.lying)
if (D.get_active_held_item())
var/obj/item/G = D.get_active_held_item()
if (G && !(G.item_flags & (ABSTRACT|DROPDEL)) && D.temporarilyRemoveItemFromInventory(G))
A.put_in_hands(G)
D.visible_message("<span class='warning'>[A] slaps [D]'s hands, taking [G] from them!</span>", \
"<span class='userdanger'>[A] slaps you, taking [G] from you!</span>")
log_combat(A, D, "deft switched (Rising Bass)")
return 1
else
to_chat(A, "<i>[G] can't be taken out of [D]'s hands!</i>")
return 0
/datum/martial_art/the_rising_bass/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("D",D)
if(check_streak(A,D))
return 1
return ..()
/datum/martial_art/the_rising_bass/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("H",D)
if(check_streak(A,D))
return 1
return ..()
/datum/martial_art/the_rising_bass/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("G",D)
if(check_streak(A,D))
return 1
return ..()
/mob/living/carbon/human/proc/rising_bass_help()
set name = "Recall Teachings"
set desc = "Remember the martial techniques of the Rising Bass clan."
set category = "Rising Bass"
to_chat(usr, "<b><i>You retreat inward and recall the teachings of the Rising Bass...</i></b>")
to_chat(usr, "<span class='notice'>Side Kick</span>: Disarm Harm. Forces opponent to step to the side.")
to_chat(usr, "<span class='notice'>Shoulder Flip</span>: Grab Harm Disarm Grab Harm Harm. Flips opponent over your shoulder and stuns.")
to_chat(usr, "<span class='notice'>Repulse Punch</span>: Grab Harm Grab Harm. Slams the opponent far away from you.")
to_chat(usr, "<span class='notice'>Foot Smash</span>: Harm Harm. Stuns opponent, minor damage.")
to_chat(usr, "<span class='notice'>Deft Switch</span>: Grab Disarm Disarm. Switches the opponent's held item for your own. Most useful with nothing in your hand.")
/datum/martial_art/the_rising_bass/teach(mob/living/carbon/human/H, make_temporary = FALSE)
. = ..()
if(!.)
return
ADD_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
ADD_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
/datum/martial_art/the_rising_bass/on_remove(mob/living/carbon/human/H)
. = ..()
REMOVE_TRAIT(H, TRAIT_NOGUNS, RISING_BASS_TRAIT)
REMOVE_TRAIT(H, TRAIT_AUTO_CATCH_ITEM, RISING_BASS_TRAIT)
+56 -49
View File
@@ -9,35 +9,36 @@
id = MARTIALART_SLEEPINGCARP
deflection_chance = 100
reroute_deflection = TRUE
no_guns = TRUE
allow_temp_override = FALSE
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
var/old_grab_state = null
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(findtext(streak,WRIST_WRENCH_COMBO))
streak = ""
wristWrench(A,D)
return 1
return TRUE
if(findtext(streak,BACK_KICK_COMBO))
streak = ""
backKick(A,D)
return 1
return TRUE
if(findtext(streak,STOMACH_KNEE_COMBO))
streak = ""
kneeStomach(A,D)
return 1
return TRUE
if(findtext(streak,HEAD_KICK_COMBO))
streak = ""
headKick(A,D)
return 1
return TRUE
if(findtext(streak,ELBOW_DROP_COMBO))
streak = ""
elbowDrop(A,D)
return 1
return 0
return TRUE
return FALSE
/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.IsStun() && !D.IsKnockdown())
log_combat(A, D, "wrist wrenched (Sleeping Carp)")
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] grabs [D]'s wrist and wrenches it sideways!</span>", \
"<span class='userdanger'>[A] grabs your wrist and violently wrenches it to the side!</span>")
@@ -46,24 +47,29 @@
D.dropItemToGround(D.get_active_held_item())
D.apply_damage(5, BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
D.Knockdown(60)//CIT CHANGE - makes sleepingcarp use knockdown() for its stuns instead of stun()
return 1
log_combat(A, D, "wrist wrenched (Sleeping Carp)")
return TRUE
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(A.dir == D.dir && !D.stat && !D.IsKnockdown())
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] kicks [D] in the back!</span>", \
"<span class='userdanger'>[A] kicks you in the back, making you stumble and fall!</span>")
step_to(D,get_step(D,D.dir),1)
D.Knockdown(80)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
return 1
log_combat(A, D, "back-kicked (Sleeping Carp)")
if(!D.stat && !D.IsKnockdown())
if(A.dir == D.dir)
log_combat(A, D, "back-kicked (Sleeping Carp)")
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] kicks [D] in the back!</span>", \
"<span class='userdanger'>[A] kicks you in the back, making you stumble and fall!</span>")
step_to(D,get_step(D,D.dir),1)
D.Knockdown(80)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
return TRUE
else
log_combat(A, D, "missed a back-kick (Sleeping Carp) on")
D.visible_message("<span class='warning'>[A] tries to kick [D] in the back, but misses!</span>", \
"<span class='userdanger'>[A] tries to kick you in the back, but misses!</span>")
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.IsKnockdown())
log_combat(A, D, "stomach kneed (Sleeping Carp)")
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] knees [D] in the stomach!</span>", \
"<span class='userdanger'>[A] winds you with a knee in the stomach!</span>")
@@ -71,12 +77,12 @@
D.losebreath += 3
D.Knockdown(40)//CIT CHANGE - makes sleepingcarp use knockdown() for its stuns instead of stun()
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
return 1
log_combat(A, D, "stomach kneed (Sleeping Carp)")
return TRUE
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.IsKnockdown())
log_combat(A, D, "head kicked (Sleeping Carp)")
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
"<span class='userdanger'>[A] kicks you in the jaw!</span>")
@@ -84,12 +90,12 @@
D.drop_all_held_items()
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
D.Knockdown(80)//CIT CHANGE - makes sleepingcarp use knockdown() for its stuns instead of stun()
return 1
log_combat(A, D, "head kicked (Sleeping Carp)")
return TRUE
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(D.IsKnockdown() || D.resting || D.stat)
log_combat(A, D, "elbow dropped (Sleeping Carp)")
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] elbow drops [D]!</span>", \
"<span class='userdanger'>[A] piledrives you with their elbow!</span>")
@@ -97,37 +103,29 @@
D.death() //FINISH HIM!
D.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1)
return 1
log_combat(A, D, "elbow dropped (Sleeping Carp)")
return TRUE
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("G",D)
if(check_streak(A,D))
return 1
if(A == D) //no self grab stun
return FALSE
if(A.grab_state >= GRAB_AGGRESSIVE)
if(A.a_intent == INTENT_GRAB && A!=D) // A!=D prevents grabbing yourself
add_to_streak("G",D)
if(check_streak(A,D)) //if a combo is made no grab upgrade is done
return TRUE
old_grab_state = A.grab_state
D.grabbedby(A, 1)
else
A.start_pulling(D, 1)
if(A.pulling)
if(old_grab_state == GRAB_PASSIVE)
D.drop_all_held_items()
D.stop_pulling()
if(A.a_intent == INTENT_GRAB)
log_combat(A, D, "grabbed", addition="aggressively")
D.visible_message("<span class='warning'>[A] violently grabs [D]!</span>", \
"<span class='userdanger'>[A] violently grabs you!</span>")
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
else
log_combat(A, D, "grabbed", addition="passively")
A.grab_state = GRAB_PASSIVE
return 1
A.grab_state = GRAB_AGGRESSIVE //Instant agressive grab if on grab intent
log_combat(A, D, "grabbed", addition="aggressively")
D.visible_message("<span class='warning'>[A] violently grabs [D]!</span>", \
"<span class='userdanger'>[A] violently grabs you!</span>")
return TRUE
return FALSE
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("H",D)
if(check_streak(A,D))
return 1
return TRUE
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
var/atk_verb = pick("punches", "kicks", "chops", "hits", "slams")
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
@@ -138,15 +136,25 @@
D.visible_message("<span class='warning'>[D] stumbles and falls!</span>", "<span class='userdanger'>The blow sends you to the ground!</span>")
D.Knockdown(80)
log_combat(A, D, "[atk_verb] (Sleeping Carp)")
return 1
return TRUE
/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("D",D)
if(check_streak(A,D))
return 1
return TRUE
return ..()
/datum/martial_art/the_sleeping_carp/teach(mob/living/carbon/human/H, make_temporary = FALSE)
. = ..()
if(!.)
return
ADD_TRAIT(H, TRAIT_NOGUNS, SLEEPING_CARP_TRAIT)
/datum/martial_art/the_sleeping_carp/on_remove(mob/living/carbon/human/H)
. = ..()
REMOVE_TRAIT(H, TRAIT_NOGUNS, SLEEPING_CARP_TRAIT)
/mob/living/carbon/human/proc/sleeping_carp_help()
set name = "Recall Teachings"
set desc = "Remember the martial techniques of the Sleeping Carp clan."
@@ -177,9 +185,8 @@
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
block_chance = 50
/obj/item/twohanded/bostaff/update_icon()
/obj/item/twohanded/bostaff/update_icon_state()
icon_state = "bostaff[wielded]"
return
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
add_fingerprint(user)
@@ -233,4 +240,4 @@
/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
return ..()
return 0
return FALSE
+8 -1
View File
@@ -88,6 +88,9 @@
/datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0)
var/old_character = current
var/signals = SEND_SIGNAL(new_character, COMSIG_MOB_PRE_PLAYER_CHANGE, new_character, old_character) | SEND_SIGNAL(src, COMSIG_PRE_MIND_TRANSFER, new_character, old_character)
if(signals & COMPONENT_STOP_MIND_TRANSFER)
return
if(current) // remove ourself from our old body's mind variable
current.mind = null
SStgui.on_transfer(current, new_character)
@@ -125,7 +128,6 @@
transfer_martial_arts(new_character)
if(active || force_key_move)
new_character.key = key //now transfer the key to link the client to our new body
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
//CIT CHANGE - makes arousal update when transfering bodies
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
@@ -133,6 +135,11 @@
if(L.client && L.client.prefs)
L.canbearoused = L.client.prefs.arousable //Technically this should make taking over a character mean the body gain the new minds setting...
L.update_arousal_hud() //Removes the old icon
if (L.client.prefs.auto_ooc)
if (L.client.prefs.chat_toggles & CHAT_OOC)
L.client.prefs.chat_toggles ^= CHAT_OOC
SEND_SIGNAL(src, COMSIG_MIND_TRANSFER, new_character, old_character)
/datum/mind/proc/store_memory(new_text)
if((length(memory) + length(new_text)) <= MAX_MESSAGE_LEN)
+60
View File
@@ -53,3 +53,63 @@
mood_change = -20
timeout = 300
//special_screen_obj = "mood_happiness_bad" Originally in tg
/datum/mood_event/eigenstate
mood_change = -3
description = "<span class='warning'>Where the hell am I? Is this an alternative dimension ?</span>\n"
/datum/mood_event/enthrall
mood_change = 5
/datum/mood_event/enthrall/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallpraise
mood_change = 10
timeout = 1 MINUTES
/datum/mood_event/enthrallpraise/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallscold
mood_change = -10
timeout = 1 MINUTES
/datum/mood_event/enthrallscold/add_effects(message)
description = "<span class='warning'>[message]</span>\n"//aaa I'm not kinky enough for this
/datum/mood_event/enthrallmissing1
mood_change = -5
/datum/mood_event/enthrallmissing1/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing2
mood_change = -10
/datum/mood_event/enthrallmissing2/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing3
mood_change = -15
/datum/mood_event/enthrallmissing3/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing4
mood_change = -25
/datum/mood_event/enthrallmissing4/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/InLove
mood_change = 10
/datum/mood_event/InLove/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/MissingLove
mood_change = -10
/datum/mood_event/MissingLove/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
@@ -176,3 +176,70 @@
/datum/mood_event/revenant_blight/add_effects()
description = "<span class='umbra'>Just give up, [pick("no one will miss you", "there is nothing you can do to help", "even a clown would be more useful than you", "does it even matter in the end?")]...</span>\n"
/datum/mood_event/plushjack
description = "<span class='warning'>I have butchered a plush recently.</span>\n"
mood_change = -1
timeout = 2 MINUTES
/datum/mood_event/plush_nostuffing
description = "<span class='warning'>A plush I tried to pet had no stuffing...</span>\n"
mood_change = -1
timeout = 2 MINUTES
//Cursed stuff below
/datum/mood_event/emptypred
description = "<span class='nicegreen'>I had to let someone out.</span>\n"
mood_change = -2
timeout = 1 MINUTES
/datum/mood_event/emptyprey
description = "<span class='nicegreen'>It feels quite cold out here.</span>\n"
mood_change = -2
timeout = 1 MINUTES
/datum/mood_event/vampcandle
description = "<span class='umbra'>Something is making your mind feel... loose...</span>\n"
mood_change = -10
timeout = 1 MINUTES
/datum/mood_event/drankblood_bad
description = "<span class='boldwarning'>I drank the blood of a lesser creature. Disgusting.</span>\n"
mood_change = -4
timeout = 900
/datum/mood_event/drankblood_dead
description = "<span class='boldwarning'>I drank dead blood. I am better than this.</span>\n"
mood_change = -7
timeout = 900
/datum/mood_event/drankblood_synth
description = "<span class='boldwarning'>I drank synthetic blood. What is wrong with me?</span>\n"
mood_change = -7
timeout = 900
/datum/mood_event/drankkilled
description = "<span class='boldwarning'>I drank from my victim until they died. I feel...less human.</span>\n"
mood_change = -12
timeout = 6000
/datum/mood_event/madevamp
description = "<span class='boldwarning'>A soul has been cursed to undeath by my own hand.</span>\n"
mood_change = -10
timeout = 10000
/datum/mood_event/vampatefood
description = "<span class='boldwarning'>Mortal nourishment no longer sustains me. I feel unwell.</span>\n"
mood_change = -6
timeout = 1000
/datum/mood_event/daylight_1
description = "<span class='boldwarning'>I slept poorly in a makeshift coffin during the day.</span>\n"
mood_change = -3
timeout = 1000
/datum/mood_event/daylight_2
description = "<span class='boldwarning'>I have been scorched by the unforgiving rays of the sun.</span>\n"
mood_change = -6
timeout = 1200
@@ -116,3 +116,59 @@
/datum/mood_event/happy_empath/add_effects(var/mob/happytarget)
description = "<span class='nicegreen'>[happytarget.name]'s happiness is infectious!</span>\n"
/datum/mood_event/headpat
description = "<span class='nicegreen'>Headpats are nice.</span>\n"
mood_change = 2
timeout = 2 MINUTES
/datum/mood_event/hugbox
description = "<span class='nicegreen'>I hugged a box of hugs recently.</span>\n"
mood_change = 1
timeout = 2 MINUTES
/datum/mood_event/plushpet
description = "<span class='nicegreen'>I pet a plush recently.</span>\n"
mood_change = 1
timeout = 3000
/datum/mood_event/plushplay
description = "<span class='nicegreen'>I've played with plushes recently.</span>\n"
mood_change = 3
timeout = 3000
/datum/mood_event/breakfast
description = "<span class='nicegreen'>Nothing like a hearty breakfast to start the shift.</span>\n"
mood_change = 2
timeout = 15 MINUTES
//Power gamer stuff below
/datum/mood_event/drankblood
description = "<span class='nicegreen'>I have fed greedly from that which nourishes me.</span>\n"
mood_change = 10
timeout = 900
/datum/mood_event/coffinsleep
description = "<span class='nicegreen'>I slept in a coffin during the day. I feel whole again.</span>\n"
mood_change = 8
timeout = 1200
//Cursed stuff below.
/datum/mood_event/orgasm
description = "<span class='userlove'>I came!</span>\n" //funny meme haha
mood_change = 3
timeout = 100 SECONDS
/datum/mood_event/fedpred
description = "<span class='nicegreen'>I've devoured someone!</span>\n"
mood_change = 3
/datum/mood_event/fedprey
description = "<span class='nicegreen'>It feels quite cozy in here.</span>\n"
mood_change = 3
/datum/mood_event/hope_lavaland
description = "<span class='nicegreen'>What a peculiar emblem. It makes me feel hopeful for my future.</span>\n"
mood_change = 5
+3 -1
View File
@@ -5,7 +5,7 @@
get_chance = 15
lowest_value = 256 * 12
text_gain_indication = "<span class='notice'>Your muscles hurt!</span>"
species_allowed = list("human") //no skeleton/lizard hulk
species_allowed = list("fly") //no skeleton/lizard hulk
health_req = 25
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
@@ -13,6 +13,7 @@
return
ADD_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "hulk", /datum/mood_event/hulk)
RegisterSignal(owner, COMSIG_MOB_SAY, .proc/handle_speech)
@@ -31,6 +32,7 @@
return
REMOVE_TRAIT(owner, TRAIT_STUNIMMUNE, TRAIT_HULK)
REMOVE_TRAIT(owner, TRAIT_PUSHIMMUNE, TRAIT_HULK)
ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, TRAIT_HULK)
owner.update_body_parts()
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "hulk")
UnregisterSignal(owner, COMSIG_MOB_SAY)
+1
View File
@@ -95,6 +95,7 @@
message = replacetext(message," ugly "," beautiful ")
message = replacetext(message," douchbag "," nice guy ")
message = replacetext(message," whore "," lady ")
message = replacetext(message," gamer "," intellectual ")
message = replacetext(message," nerd "," smarty pants ")
message = replacetext(message," moron "," fun person ")
message = replacetext(message," IT'S LOOSE "," EVERYTHING IS FINE ")
+17 -7
View File
@@ -3,6 +3,7 @@
var/turf/master_turf //The center of the wave
var/steps=0 //How far we've moved
var/intensity //How strong it was originaly
var/remaining_contam //How much contaminated material it still has
var/range_modifier //Higher than 1 makes it drop off faster, 0.5 makes it drop off half etc
var/move_dir //The direction of movement
var/list/__dirs //The directions to the side of the wave, stored for easy looping
@@ -18,6 +19,7 @@
__dirs+=turn(dir, -90)
intensity = _intensity
remaining_contam = intensity
range_modifier = _range_modifier
can_contaminate = _can_contaminate
@@ -46,8 +48,9 @@
qdel(src)
return
radiate(atoms, FLOOR(strength, 1))
if(radiate(atoms, FLOOR(min(strength,remaining_contam), 1)))
//oof ow ouch
remaining_contam = max(0,remaining_contam-((min(strength,remaining_contam)-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT))
check_obstructions(atoms) // reduce our overall strength if there are radiation insulators
/datum/radiation_wave/proc/get_rad_atoms()
@@ -89,7 +92,8 @@
intensity *= (1-((1-thing.rad_insulation)/width))
/datum/radiation_wave/proc/radiate(list/atoms, strength)
var/contamination_chance = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_CHANCE_COEFFICIENT * min(1, 1/(steps*range_modifier))
var/can_contam = strength >= RAD_MINIMUM_CONTAMINATION
var/list/contam_atoms = list()
for(var/k in 1 to atoms.len)
var/atom/thing = atoms[k]
if(!thing)
@@ -109,8 +113,14 @@
))
if(!can_contaminate || blacklisted[thing.type])
continue
if(prob(contamination_chance)) // Only stronk rads get to have little baby rads
if(CHECK_BITFIELD(thing.rad_flags, RAD_NO_CONTAMINATE) || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
continue
var/rad_strength = (strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT
if(CHECK_BITFIELD(thing.rad_flags, RAD_NO_CONTAMINATE) || SEND_SIGNAL(thing, COMSIG_ATOM_RAD_CONTAMINATING, strength) & COMPONENT_BLOCK_CONTAMINATION)
continue
contam_atoms += thing
var/did_contam = 0
if(length(can_contam))
var/rad_strength = ((strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT)/contam_atoms.len
for(var/k in 1 to contam_atoms.len)
var/atom/thing = contam_atoms[k]
thing.AddComponent(/datum/component/radioactive, rad_strength, source)
did_contam = 1
return did_contam
+10 -1
View File
@@ -229,4 +229,13 @@
id = "puzzle"
description = "Mystery to be solved."
suffix = "lavaland_surface_puzzle.dmm"
cost = 5
cost = 5
/datum/map_template/ruin/lavaland/elite_tumor
name = "Pulsating Tumor"
id = "tumor"
description = "A strange tumor which houses a powerful beast..."
suffix = "lavaland_surface_elite_tumor.dmm"
cost = 5
always_place = TRUE
allow_duplicates = TRUE
+21
View File
@@ -0,0 +1,21 @@
/datum/map_template/ruin/station
prefix = "_maps/RandomRuins/StationRuins/"
cost = 0
// Boxstation
// Engine
/datum/map_template/ruin/station/box/engine
id = "engine_sm"
suffix = "Box/Engine/engine_sm.dmm"
name = "Engine SM"
/datum/map_template/ruin/station/box/engine/singulo
id = "engine_singulo"
suffix = "Box/Engine/engine_singulo.dmm"
name = "Engine Singulo"
/datum/map_template/ruin/station/box/engine/tesla
id = "engine_tesla"
suffix = "Box/Engine/engine_tesla.dmm"
name = "Engine Tesla"
+2
View File
@@ -292,6 +292,7 @@
var/mob/living/carbon/C = owner
for(var/X in C.bodyparts)
var/obj/item/bodypart/BP = X
BP.max_damage *= 10
BP.brute_dam *= 10
BP.burn_dam *= 10
owner.toxloss *= 10
@@ -377,6 +378,7 @@
var/obj/item/bodypart/BP = X
BP.brute_dam *= 0.1
BP.burn_dam *= 0.1
BP.max_damage /= 10
owner.toxloss *= 0.1
owner.oxyloss *= 0.1
owner.cloneloss *= 0.1
+81 -11
View File
@@ -80,34 +80,55 @@
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
//TASER
/datum/status_effect/electrode
id = "tased"
/datum/status_effect/no_combat_mode/
id = "no_combat_mode"
blocks_combatmode = TRUE
status_type = STATUS_EFFECT_REPLACE
alert_type = null
status_type = STATUS_EFFECT_REPLACE
/datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration)
/datum/status_effect/no_combat_mode/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration))
duration = set_duration
. = ..()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
if(C.combatmode)
C.toggle_combat_mode(TRUE)
/datum/status_effect/no_combat_mode/mesmerize
id = "Mesmerize"
alert_type = /obj/screen/alert/status_effect/mesmerized
/obj/screen/alert/status_effect/mesmerized
name = "Mesmerized"
desc = "You cant tear your sight from who is in front of you...Their gaze is simply too enthralling.."
icon = 'icons/mob/actions/bloodsucker.dmi'
icon_state = "power_mez"
/datum/status_effect/no_combat_mode/electrode
id = "tased"
/datum/status_effect/no_combat_mode/electrode/on_creation(mob/living/new_owner, set_duration)
if(isnum(set_duration)) //TODO, figure out how to grab from subtype
duration = set_duration
. = ..()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
if(C.combatmode)
C.toggle_combat_mode(TRUE)
C.add_movespeed_modifier(MOVESPEED_ID_TASED_STATUS, TRUE, override = TRUE, multiplicative_slowdown = 8)
/datum/status_effect/electrode/on_remove()
/datum/status_effect/no_combat_mode/electrode/on_remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.remove_movespeed_modifier(MOVESPEED_ID_TASED_STATUS)
. = ..()
/datum/status_effect/electrode/tick()
/datum/status_effect/no_combat_mode/electrode/tick()
if(owner)
owner.adjustStaminaLoss(5) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing.
/datum/status_effect/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
/datum/status_effect/no_combat_mode/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
return 2
//OTHER DEBUFFS
@@ -388,6 +409,19 @@
else
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/neck_slice
id = "neck_slice"
status_type = STATUS_EFFECT_UNIQUE
alert_type = null
duration = -1
/datum/status_effect/neck_slice/tick()
var/mob/living/carbon/human/H = owner
if(H.stat == DEAD || H.bleed_rate <= 8)
H.remove_status_effect(/datum/status_effect/neck_slice)
if(prob(10))
H.emote(pick("gasp", "gag", "choke"))
/mob/living/proc/apply_necropolis_curse(set_curse, duration = 10 MINUTES)
var/datum/status_effect/necropolis_curse/C = has_status_effect(STATUS_EFFECT_NECROPOLIS_CURSE)
if(!set_curse)
@@ -481,7 +515,7 @@
deltimer(timerid)
//Kindle: Used by servants of Ratvar. 10-second knockdown, reduced by 1 second per 5 damage taken while the effect is active.
//Kindle: Used by servants of Ratvar. 10-second knockdown, reduced by 1 second per 5 damage taken while the effect is active. Does not take into account Oxy-damage
/datum/status_effect/kindle
id = "kindle"
status_type = STATUS_EFFECT_UNIQUE
@@ -489,6 +523,7 @@
duration = 100
alert_type = /obj/screen/alert/status_effect/kindle
var/old_health
var/old_oxyloss
/datum/status_effect/kindle/tick()
owner.Knockdown(15, TRUE, FALSE, 15)
@@ -498,7 +533,9 @@
C.stuttering = max(5, C.stuttering)
if(!old_health)
old_health = owner.health
var/health_difference = old_health - owner.health
if(!old_oxyloss)
old_oxyloss = owner.getOxyLoss()
var/health_difference = old_health - owner.health - CLAMP(owner.getOxyLoss() - old_oxyloss,0, owner.getOxyLoss())
if(!health_difference)
return
owner.visible_message("<span class='warning'>The light in [owner]'s eyes dims as [owner.p_theyre()] harmed!</span>", \
@@ -506,6 +543,7 @@
health_difference *= 2 //so 10 health difference translates to 20 deciseconds of stun reduction
duration -= health_difference
old_health = owner.health
old_oxyloss = owner.getOxyLoss()
/datum/status_effect/kindle/on_remove()
owner.visible_message("<span class='warning'>The light in [owner]'s eyes fades!</span>", \
@@ -541,6 +579,38 @@
icon_state = "ichorial_stain"
alerttooltipstyle = "clockcult"
//GOLEM GANG
/datum/status_effect/strandling //get it, strand as in durathread strand + strangling = strandling hahahahahahahahahahhahahaha i want to die
id = "strandling"
status_type = STATUS_EFFECT_UNIQUE
alert_type = /obj/screen/alert/status_effect/strandling
/datum/status_effect/strandling/on_apply()
ADD_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron")
return ..()
/datum/status_effect/strandling/on_remove()
REMOVE_TRAIT(owner, TRAIT_MAGIC_CHOKE, "dumbmoron")
return ..()
/obj/screen/alert/status_effect/strandling
name = "Choking strand"
desc = "A magical strand of Durathread is wrapped around your neck, preventing you from breathing! Click this icon to remove the strand."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/obj/screen/alert/status_effect/strandling/Click(location, control, params)
. = ..()
to_chat(mob_viewer, "<span class='notice'>You attempt to remove the durathread strand from around your neck.</span>")
if(do_after(mob_viewer, 35, null, mob_viewer))
if(isliving(mob_viewer))
var/mob/living/L = mob_viewer
to_chat(mob_viewer, "<span class='notice'>You succesfuly remove the durathread strand.</span>")
L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
datum/status_effect/pacify
id = "pacify"
status_type = STATUS_EFFECT_REPLACE
@@ -666,4 +736,4 @@ datum/status_effect/pacify
if(LAZYLEN(targets) && I)
to_chat(owner, "<span class='warning'>Your arm spasms!</span>")
owner.log_message("threw [I] due to a Muscle Spasm", LOG_ATTACK)
owner.throw_item(pick(targets))
owner.throw_item(pick(targets))
+32 -15
View File
@@ -8,12 +8,14 @@
mob_trait = TRAIT_ALCOHOL_TOLERANCE
gain_text = "<span class='notice'>You feel like you could drink a whole keg!</span>"
lose_text = "<span class='danger'>You don't feel as resistant to alcohol anymore. Somehow.</span>"
medical_record_text = "Patient demonstrates a high tolerance for alcohol."
/datum/quirk/apathetic
name = "Apathetic"
desc = "You just don't care as much as other people. That's nice to have in a place like this, I guess."
value = 1
mood_quirk = TRUE
medical_record_text = "Patient was administered the Apathy Evaluation Scale but did not bother to complete it."
/datum/quirk/apathetic/add()
var/datum/component/mood/mood = quirk_holder.GetComponent(/datum/component/mood)
@@ -42,6 +44,7 @@
mob_trait = TRAIT_EMPATH
gain_text = "<span class='notice'>You feel in tune with those around you.</span>"
lose_text = "<span class='danger'>You feel isolated from others.</span>"
medical_record_text = "Patient is highly perceptive of and sensitive to social cues, or may possibly have ESP. Further testing needed."
/datum/quirk/freerunning
name = "Freerunning"
@@ -50,6 +53,7 @@
mob_trait = TRAIT_FREERUNNING
gain_text = "<span class='notice'>You feel lithe on your feet!</span>"
lose_text = "<span class='danger'>You feel clumsy again.</span>"
medical_record_text = "Patient scored highly on cardio tests."
/datum/quirk/friendly
name = "Friendly"
@@ -59,6 +63,7 @@
gain_text = "<span class='notice'>You want to hug someone.</span>"
lose_text = "<span class='danger'>You no longer feel compelled to hug others.</span>"
mood_quirk = TRUE
medical_record_text = "Patient demonstrates low-inhibitions for physical contact and well-developed arms. Requesting another doctor take over this case."
/datum/quirk/jolly
name = "Jolly"
@@ -66,6 +71,11 @@
value = 1
mob_trait = TRAIT_JOLLY
mood_quirk = TRUE
medical_record_text = "Patient demonstrates constant euthymia irregular for environment. It's a bit much, to be honest."
/datum/quirk/jolly/on_process()
if(prob(0.05))
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "jolly", /datum/mood_event/jolly)
/datum/quirk/light_step
name = "Light Step"
@@ -74,6 +84,7 @@
mob_trait = TRAIT_LIGHT_STEP
gain_text = "<span class='notice'>You walk with a little more litheness.</span>"
lose_text = "<span class='danger'>You start tromping around like a barbarian.</span>"
medical_record_text = "Patient's dexterity belies a strong capacity for stealth."
/datum/quirk/quick_step
name = "Quick Step"
@@ -82,6 +93,7 @@
mob_trait = TRAIT_SPEEDY_STEP
gain_text = "<span class='notice'>You feel determined. No time to lose.</span>"
lose_text = "<span class='danger'>You feel less determined. What's the rush, man?</span>"
medical_record_text = "Patient scored highly on racewalking tests."
/datum/quirk/musician
name = "Musician"
@@ -90,6 +102,7 @@
mob_trait = TRAIT_MUSICIAN
gain_text = "<span class='notice'>You know everything about musical instruments.</span>"
lose_text = "<span class='danger'>You forget how musical instruments work.</span>"
medical_record_text = "Patient brain scans show a highly-developed auditory pathway."
/datum/quirk/musician/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
@@ -101,21 +114,6 @@
H.equip_to_slot(musicaltuner, SLOT_IN_BACKPACK)
H.regenerate_icons()
/datum/quirk/night_vision
name = "Night Vision"
desc = "You can see slightly more clearly in full darkness than most people."
value = 1
mob_trait = TRAIT_NIGHT_VISION
gain_text = "<span class='notice'>The shadows seem a little less dark.</span>"
lose_text = "<span class='danger'>Everything seems a little darker.</span>"
/datum/quirk/night_vision/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
var/obj/item/organ/eyes/eyes = H.getorgan(/obj/item/organ/eyes)
if(!eyes || eyes.lighting_alpha)
return
eyes.Insert(H) //refresh their eyesight and vision
/datum/quirk/photographer
name = "Photographer"
desc = "You know how to handle a camera, shortening the delay between each shot."
@@ -123,6 +121,7 @@
mob_trait = TRAIT_PHOTOGRAPHER
gain_text = "<span class='notice'>You know everything about photography.</span>"
lose_text = "<span class='danger'>You forget how photo cameras work.</span>"
medical_record_text = "Patient mentions photography as a stress-relieving hobby."
/datum/quirk/photographer/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
@@ -136,12 +135,14 @@
desc = "You know your body well, and can accurately assess the extent of your wounds."
value = 2
mob_trait = TRAIT_SELF_AWARE
medical_record_text = "Patient demonstrates an uncanny knack for self-diagnosis."
/datum/quirk/skittish
name = "Skittish"
desc = "You can conceal yourself in danger. Ctrl-shift-click a closed locker to jump into it, as long as you have access."
value = 2
mob_trait = TRAIT_SKITTISH
medical_record_text = "Patient demonstrates a high aversion to danger and has described hiding in containers out of fear."
/datum/quirk/spiritual
name = "Spiritual"
@@ -150,6 +151,7 @@
mob_trait = TRAIT_SPIRITUAL
gain_text = "<span class='notice'>You feel a little more faithful to the gods today.</span>"
lose_text = "<span class='danger'>You feel less faithful in the gods.</span>"
medical_record_text = "Patient reports a belief in a higher power."
/datum/quirk/tagger
name = "Tagger"
@@ -158,6 +160,7 @@
mob_trait = TRAIT_TAGGER
gain_text = "<span class='notice'>You know how to tag walls efficiently.</span>"
lose_text = "<span class='danger'>You forget how to tag walls properly.</span>"
medical_record_text = "Patient was recently seen for possible paint huffing incident."
/datum/quirk/tagger/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
@@ -173,6 +176,7 @@
mob_trait = TRAIT_VORACIOUS
gain_text = "<span class='notice'>You feel HONGRY.</span>"
lose_text = "<span class='danger'>You no longer feel HONGRY.</span>"
medical_record_text = "Patient demonstrates a disturbing capacity for eating."
/datum/quirk/trandening
name = "High Luminosity Eyes"
@@ -194,6 +198,7 @@
mob_trait = TRAIT_HIGH_BLOOD
gain_text = "<span class='notice'>You feel full of blood!</span>"
lose_text = "<span class='notice'>You feel like your blood pressure went down.</span>"
medical_record_text = "Patient's blood tests report an abnormal concentration of red blood cells in their bloodstream."
/datum/quirk/bloodpressure/add()
var/mob/living/M = quirk_holder
@@ -203,3 +208,15 @@
/datum/quirk/bloodpressure/remove()
var/mob/living/M = quirk_holder
M.blood_ratio = 1
/datum/quirk/night_vision
name = "Night Vision"
desc = "You can see slightly more clearly in full darkness than most people."
value = 1
mob_trait = TRAIT_NIGHT_VISION
gain_text = "<span class='notice'>The shadows seem a little less dark.</span>"
lose_text = "<span class='danger'>Everything seems a little darker.</span>"
/datum/quirk/night_vision/on_spawn()
var/mob/living/carbon/human/H = quirk_holder
H.update_sight()
+24 -8
View File
@@ -22,14 +22,19 @@
value = -1
gain_text = "<span class='danger'>You start feeling depressed.</span>"
lose_text = "<span class='notice'>You no longer feel depressed.</span>" //if only it were that easy!
medical_record_text = "Patient has a severe mood disorder causing them to experience sudden moments of sadness."
medical_record_text = "Patient has a severe mood disorder, causing them to experience acute episodes of depression."
mood_quirk = TRUE
/datum/quirk/depression/on_process()
if(prob(0.05))
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "depression", /datum/mood_event/depression)
/datum/quirk/family_heirloom
name = "Family Heirloom"
desc = "You are the current owner of an heirloom, passed down for generations. You have to keep it safe!"
value = -1
mood_quirk = TRUE
medical_record_text = "Patient demonstrates an unnatural attachment to a family heirloom."
var/obj/item/heirloom
var/where
@@ -143,6 +148,7 @@
name = "Nyctophobia"
desc = "As far as you can remember, you've always been afraid of the dark. While in the dark without a light source, you instinctually act careful, and constantly feel a sense of dread."
value = -1
medical_record_text = "Patient demonstrates a fear of the dark. (Seriously?)"
/datum/quirk/nyctophobia/on_process()
var/mob/living/carbon/human/H = quirk_holder
@@ -163,7 +169,8 @@
desc = "Bright lights irritate you. Your eyes start to water, your skin feels itchy against the photon radiation, and your hair gets dry and frizzy. Maybe it's a medical condition. If only Nanotrasen was more considerate of your needs..."
value = -1
gain_text = "<span class='danger'>The safty of light feels off...</span>"
lose_text = "<span class='notice'>Enlighing.</span>"
lose_text = "<span class='notice'>Enlightening.</span>"
medical_record_text = "Despite my warnings, the patient refuses turn on the lights, only to end up rolling down a full flight of stairs and into the cellar."
/datum/quirk/lightless/on_process()
var/turf/T = get_turf(quirk_holder)
@@ -332,16 +339,19 @@
medical_record_text = "Patient has an extreme or irrational fear and aversion to an undefined stimuli."
var/datum/brain_trauma/mild/phobia/phobia
/datum/quirk/phobia/add()
/datum/quirk/phobia/post_add()
var/mob/living/carbon/human/H = quirk_holder
phobia = new
H.gain_trauma(phobia, TRAUMA_RESILIENCE_SURGERY)
H.gain_trauma(phobia, TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/phobia/remove()
var/mob/living/carbon/human/H = quirk_holder
H?.cure_trauma_type(phobia, TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/mute
name = "Mute"
desc = "Due to some accident, medical condition, or simply by choice, you are completely unable to speak."
value = -2 //HALP MAINTS
mob_trait = TRAIT_MUTE
gain_text = "<span class='danger'>You find yourself unable to speak!</span>"
lose_text = "<span class='notice'>You feel a growing strength in your vocal chords.</span>"
medical_record_text = "Functionally mute, patient is unable to use their voice in any capacity."
@@ -350,14 +360,17 @@
/datum/quirk/mute/add()
var/mob/living/carbon/human/H = quirk_holder
mute = new
H.gain_trauma(mute, TRAUMA_RESILIENCE_SURGERY)
H.gain_trauma(mute, TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/mute/remove()
var/mob/living/carbon/human/H = quirk_holder
H?.cure_trauma_type(mute, TRAUMA_RESILIENCE_ABSOLUTE)
/datum/quirk/mute/on_process()
if(quirk_holder.mind && LAZYLEN(quirk_holder.mind.antag_datums))
to_chat(quirk_holder, "<span class='boldannounce'>Your antagonistic nature has caused your voice to be heard.</span>")
qdel(src)
/datum/quirk/unstable
name = "Unstable"
desc = "Due to past troubles, you are unable to recover your sanity if you lose it. Be very careful managing your mood!"
@@ -373,7 +386,7 @@
value = -4
gain_text = "<span class='danger'>You can't see anything.</span>"
lose_text = "<span class='notice'>You miraculously gain back your vision.</span>"
medical_record_text = "Subject has permanent blindness."
medical_record_text = "Patient has permanent blindness."
/datum/quirk/blindness/add()
quirk_holder.become_blind(ROUNDSTART_TRAIT)
@@ -384,3 +397,6 @@
if(!H.equip_to_slot_if_possible(glasses, SLOT_GLASSES, bypass_equip_delay_self = TRUE)) //if you can't put it on the user's eyes, put it in their hands, otherwise put it on their eyes eyes
H.put_in_hands(glasses)
H.regenerate_icons()
/datum/quirk/blindness/remove()
quirk_holder?.cure_blind(ROUNDSTART_TRAIT)
+18 -25
View File
@@ -16,6 +16,7 @@
value = 0
gain_text = "<span class='notice'>You feel an intense craving for pineapple.</span>"
lose_text = "<span class='notice'>Your feelings towards pineapples seem to return to a lukewarm state.</span>"
medical_record_text = "Patient demonstrates a pathological love of pineapple."
/datum/quirk/pineapple_liker/add()
var/mob/living/carbon/human/H = quirk_holder
@@ -34,6 +35,7 @@
value = 0
gain_text = "<span class='notice'>You find yourself pondering what kind of idiot actually enjoys pineapples...</span>"
lose_text = "<span class='notice'>Your feelings towards pineapples seem to return to a lukewarm state.</span>"
medical_record_text = "Patient is correct to think that pineapple is disgusting."
/datum/quirk/pineapple_hater/add()
var/mob/living/carbon/human/H = quirk_holder
@@ -52,6 +54,7 @@
value = 0
gain_text = "<span class='notice'>You start craving something that tastes strange.</span>"
lose_text = "<span class='notice'>You feel like eating normal food again.</span>"
medical_record_text = "Patient demonstrates irregular nutrition preferences."
/datum/quirk/deviant_tastes/add()
var/mob/living/carbon/human/H = quirk_holder
@@ -85,15 +88,6 @@
if(quirk_holder)
quirk_holder.remove_client_colour(/datum/client_colour/monochrome)
/datum/quirk/crocrin_immunity
name = "Crocin Immunity"
desc = "You're one of the few people in the galaxy who are genetically immune to Crocin and Hexacrocin products and their addictive properties! However, you can still get brain damage from Hexacrocin addiction."
mob_trait = TRAIT_CROCRIN_IMMUNE
value = 0
gain_text = "<span class='notice'>You feel more prudish.</span>"
lose_text = "<span class='notice'>You don't feel as prudish as before.</span>"
medical_record_text = "Patient exhibits a special gene that makes them immune to Crocin and Hexacrocin."
/datum/quirk/libido
name = "Nymphomania"
desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual."
@@ -128,21 +122,20 @@
gain_text = "<span class='notice'>You feel like exposing yourself to the world.</span>"
lose_text = "<span class='notice'>Indecent exposure doesn't sound as charming to you anymore.</span>"
/datum/quirk/pharmacokinesis //Prevents unwanted organ additions.
name = "Acute hepatic pharmacokinesis"
desc = "You've a rare genetic disorder that causes Incubus draft and Sucubus milk to be absorbed by your liver instead."
/datum/quirk/alcohol_intolerance
name = "Alcohol Intolerance"
desc = "You take toxin damage from alcohol rather than getting drunk."
value = 0
mob_trait = TRAIT_PHARMA
lose_text = "<span class='notice'>Your liver feels different.</span>"
var/active = FALSE
var/power = 0
var/cachedmoveCalc = 1
mob_trait = TRAIT_NO_ALCOHOL
medical_record_text = "Patient's body does not react properly to ethyl alcohol."
/datum/quirk/assblastusa
name = "Buns of Steel"
desc = "You've never skipped ass day. With this trait, you are completely immune to all forms of ass slapping and anyone who tries to slap your rock hard ass usually gets a broken hand."
mob_trait = TRAIT_ASSBLASTUSA
value = 0
medical_record_text = "Patient never skipped ass day."
gain_text = "<span class='notice'>Your ass rivals those of golems.</span>"
lose_text = "<span class='notice'>Your butt feels more squishy and slappable.</span>"
/datum/quirk/alcohol_intolerance/add()
var/mob/living/carbon/human/H = quirk_holder
var/datum/species/species = H.dna.species
species.disliked_food |= ALCOHOL
/datum/quirk/alcohol_intolerance/remove()
var/mob/living/carbon/human/H = quirk_holder
if(H)
var/datum/species/species = H.dna.species
species.disliked_food &= ~ALCOHOL
@@ -22,27 +22,17 @@
target_trait = ZTRAIT_STATION
immunity_type = "rad"
var/radiation_intensity = 100
/datum/weather/rad_storm/telegraph()
..()
status_alarm(TRUE)
/datum/weather/rad_storm/weather_act(mob/living/L)
var/resist = L.getarmor(null, "rad")
if(prob(40))
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.dna && !HAS_TRAIT(H, TRAIT_RADIMMUNE))
if(prob(max(0,100-resist)))
H.randmuti()
if(prob(50))
if(prob(90))
H.randmutb()
else
H.randmutg()
H.domutcheck()
L.rad_act(20)
var/ratio = 1 - (min(resist, 100) / 100)
L.rad_act(radiation_intensity * ratio)
/datum/weather/rad_storm/end()
if(..())