merge from master

This commit is contained in:
silicons
2020-07-20 10:18:44 -07:00
1206 changed files with 35732 additions and 41410 deletions
@@ -398,7 +398,7 @@
humanc = character //Let's retypecast the var to be human,
if(humanc) //These procs all expect humans
GLOB.data_core.manifest_inject(humanc)
GLOB.data_core.manifest_inject(humanc, humanc.client, humanc.client.prefs)
if(SSshuttle.arrivals)
SSshuttle.arrivals.QueueAnnounce(humanc, rank)
else
@@ -24,7 +24,7 @@
/datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 270, 360, master_ui, state)
ui = new(user, src, ui_key, "NotificationPreferences", "Notification Preferences", 270, 360, master_ui, state)
ui.open()
/datum/notificationpanel/ui_data(mob/user)
+10 -8
View File
@@ -54,6 +54,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
// Used for displaying in ghost chat, without changing the actual name
// of the mob
var/deadchat_name
var/datum/orbit_menu/orbit_menu
var/datum/spawners_menu/spawners_menu
/mob/dead/observer/Initialize(mapload, mob/body)
@@ -161,6 +162,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
updateallghostimages()
QDEL_NULL(orbit_menu)
QDEL_NULL(spawners_menu)
return ..()
@@ -490,10 +492,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Orbit" // "Haunt"
set desc = "Follow and orbit a mob."
var/list/mobs = getpois(skip_mindless=1)
var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
var/mob/target = mobs[input]
ManualFollow(target)
if(!orbit_menu)
orbit_menu = new(src)
orbit_menu.ui_interact(src)
// This is the ghost's follow verb with an argument
/mob/dead/observer/proc/ManualFollow(atom/movable/target)
@@ -837,13 +839,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/vv_edit_var(var_name, var_value)
. = ..()
switch(var_name)
if("icon")
if(NAMEOF(src, icon))
ghostimage_default.icon = icon
ghostimage_simple.icon = icon
if("icon_state")
if(NAMEOF(src, icon_state))
ghostimage_default.icon_state = icon_state
ghostimage_simple.icon_state = icon_state
if("fun_verbs")
if(NAMEOF(src, fun_verbs))
if(fun_verbs)
verbs += /mob/dead/observer/verb/boo
verbs += /mob/dead/observer/verb/possess
@@ -925,7 +927,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/vv_edit_var(var_name, var_value)
. = ..()
if(var_name == "invisibility")
if(var_name == NAMEOF(src, invisibility))
set_invisibility(invisibility) // updates light
/proc/set_observer_default_invisibility(amount, message=null)
+78
View File
@@ -0,0 +1,78 @@
/datum/orbit_menu
var/mob/dead/observer/owner
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
if (!ui)
ui = new(user, src, ui_key, "Orbit", "Orbit", 350, 700, master_ui, state)
ui.open()
/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if (..())
return
if (action == "orbit")
var/list/pois = getpois(skip_mindless = 1)
var/atom/movable/poi = pois[params["name"]]
if (poi != null)
owner.ManualFollow(poi)
ui.close()
/datum/orbit_menu/ui_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
var/list/ghosts = list()
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(skip_mindless = 1)
for (var/name in pois)
var/list/serialized = list()
serialized["name"] = name
var/poi = pois[name]
var/mob/M = poi
if (istype(M))
if (isobserver(M))
ghosts += list(serialized)
else if (M.stat == DEAD)
dead += list(serialized)
else if (M.mind == null)
npcs += list(serialized)
else
var/number_of_orbiters = M.orbiters?.orbiters?.len
if (number_of_orbiters)
serialized["orbiters"] = number_of_orbiters
var/datum/mind/mind = M.mind
var/was_antagonist = FALSE
for (var/_A in mind.antag_datums)
var/datum/antagonist/A = _A
if (A.show_to_ghosts)
was_antagonist = TRUE
serialized["antag"] = A.name
antagonists += list(serialized)
break
if (!was_antagonist)
alive += list(serialized)
else
misc += list(serialized)
data["alive"] = alive
data["antagonists"] = antagonists
data["dead"] = dead
data["ghosts"] = ghosts
data["misc"] = misc
data["npcs"] = npcs
return data
@@ -25,7 +25,7 @@
status_flags = CANUNCONSCIOUS|CANPUSH
var/heat_protection = 0.5
heat_protection = 0.5
var/leaping = 0
gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
unique_name = 1
@@ -59,7 +59,7 @@
return attack_hand(user)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
/obj/item/clothing/mask/facehugger/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if((stat == CONSCIOUS && !sterile) && !isalien(user))
if(Leap(user))
return
@@ -0,0 +1,2 @@
/mob/living/carbon/check_unarmed_parry_activation_special()
return ..() && length(get_empty_held_indexes())
@@ -112,7 +112,7 @@
return //so we don't call the carbon's attack_hand().
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
/mob/living/carbon/attack_hand(mob/living/carbon/human/user, act_intent, unarmed_attack_flags)
. = ..()
if(.) //was the attack blocked?
return
@@ -127,9 +127,9 @@
ContactContractDisease(D)
if(lying && surgeries.len)
if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
if(act_intent == INTENT_HELP || act_intent == INTENT_DISARM)
for(var/datum/surgery/S in surgeries)
if(S.next_step(user, user.a_intent))
if(S.next_step(user, act_intent))
return TRUE
@@ -64,3 +64,11 @@
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons
/// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection
var/heat_protection = 0 // No heat protection
/// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection
var/cold_protection = 0 // No cold protection
/// Timer id of any transformation
var/transformation_timer
@@ -33,6 +33,7 @@
enable_intentional_sprint_mode()
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
GLOB.human_list += src
/mob/living/carbon/human/ComponentInitialize()
@@ -47,6 +48,7 @@
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
GLOB.human_list -= src
return ..()
/mob/living/carbon/human/prepare_data_huds()
@@ -93,29 +93,28 @@
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src, attackchain_flags, damage_multiplier)
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
if(user.a_intent == INTENT_HARM)
. = ..(user, TRUE)
if(.)
return
var/hulk_verb_continous = "smashes"
var/hulk_verb_simple = "smash"
if(prob(50))
hulk_verb_continous = "pummels"
hulk_verb_simple = "pummel"
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
visible_message("<span class='danger'>[user] [hulk_verb_continous] [src]!</span>", \
"<span class='userdanger'>[user] [hulk_verb_continous] you!</span>", null, COMBAT_MESSAGE_RANGE, null, user,
"<span class='danger'>You [hulk_verb_simple] [src]!</span>")
adjustBruteLoss(15)
return 1
. = ..(user, TRUE)
if(.)
return
var/hulk_verb_continous = "smashes"
var/hulk_verb_simple = "smash"
if(prob(50))
hulk_verb_continous = "pummels"
hulk_verb_simple = "pummel"
playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
visible_message("<span class='danger'>[user] [hulk_verb_continous] [src]!</span>", \
"<span class='userdanger'>[user] [hulk_verb_continous] you!</span>", null, COMBAT_MESSAGE_RANGE, null, user,
"<span class='danger'>You [hulk_verb_simple] [src]!</span>")
adjustBruteLoss(15)
return 1
/mob/living/carbon/human/attack_hand(mob/user)
/mob/living/carbon/human/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.) //To allow surgery to return properly.
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
dna.species.spec_attack_hand(H, src)
dna.species.spec_attack_hand(H, src, null, act_intent, unarmed_attack_flags)
/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
var/dam_zone = pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
@@ -7,12 +7,14 @@
buckle_lying = FALSE
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
/// Enable stamina combat
combat_flags = COMBAT_FLAGS_DEFAULT
combat_flags = COMBAT_FLAGS_DEFAULT | COMBAT_FLAG_UNARMED_PARRY
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
has_field_of_vision = FALSE //Handled by species.
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
block_parry_data = /datum/block_parry_data/unarmed/human
//Hair colour and style
var/hair_color = "000"
var/hair_style = "Bald"
@@ -71,3 +73,45 @@
var/lastpuke = 0
var/account_id
var/last_fire_update
/// Unarmed parry data for human
/datum/block_parry_data/unarmed/human
parry_respect_clickdelay = TRUE
parry_stamina_cost = 4
parry_attack_types = ATTACK_TYPE_UNARMED
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING
parry_time_windup = 0
parry_time_spindown = 1
parry_time_active = 5
parry_time_perfect = 1
parry_time_perfect_leeway = 1
parry_imperfect_falloff_percent = 20
parry_efficiency_perfect = 100
parry_efficiency_considered_successful = 0.01
parry_efficiency_to_counterattack = 0.01
parry_max_attacks = 3
parry_cooldown = 30
parry_failed_stagger_duration = 0
parry_failed_clickcd_duration = 0.4
parry_data = list( // yeah it's snowflake
"HUMAN_PARRY_STAGGER" = 3 SECONDS,
"HUMAN_PARRY_PUNCH" = TRUE,
"HUMAN_PARRY_MININUM_EFFICIENCY" = 0.9
)
/mob/living/carbon/human/on_active_parry(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, parry_efficiency, parry_time)
var/datum/block_parry_data/D = return_block_parry_datum(block_parry_data)
if(!owner.Adjacent(attacker))
return ..()
if(parry_efficiency < D.parry_data["HUMAN_PARRY_MINIMUM_EFFICIENCY"])
return ..()
visible_message("<span class='warning'>[src] strikes back perfectly at [attacker], staggering them!</span>")
if(D.parry_data["HUMAN_PARRY_PUNCH"])
UnarmedAttack(attacker, TRUE, INTENT_HARM, UNARMED_ATTACK_PARRY)
var/mob/living/L = attacker
if(istype(L))
L.Stagger(D.parry_data["HUMAN_PARRY_STAGGER"])
@@ -59,7 +59,7 @@
. = ..()
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_move(NewLoc)
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby)
if(. && (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) && !(movement_type & FLYING) && CHECK_ALL_MOBILITY(src, MOBILITY_MOVE|MOBILITY_STAND) && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && (!pulledby || (pulledby.pulledby == src)))
if(!HAS_TRAIT(src, TRAIT_FREESPRINT))
doSprintLossTiles(1)
if((oldpseudoheight - pseudo_z_axis) >= 8)
+21 -15
View File
@@ -382,7 +382,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//keep it at the right spot, so we can't have people taking shortcuts
var/location = C.dna.mutation_index.Find(inert_mutation)
C.dna.mutation_index[location] = new_species.inert_mutation
C.dna.default_mutation_genes[location] = C.dna.mutation_index[location]
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision))
var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision)
@@ -1444,7 +1446,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.grabbedby(user)
return 1
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
/datum/species/proc/harm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style, unarmed_attack_flags = NONE)
if(!attacker_style && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm [target]!</span>")
return FALSE
@@ -1456,10 +1458,11 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target_message = "<span class='warning'>[target] blocks your attack!</span>")
return FALSE
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
user.adjustStaminaLossBuffered(1.5)
else
user.adjustStaminaLossBuffered(3.5)
if(!(unarmed_attack_flags & UNARMED_ATTACK_PARRY))
if(HAS_TRAIT(user, TRAIT_PUGILIST))//CITADEL CHANGE - makes punching cause staminaloss but funny martial artist types get a discount
user.adjustStaminaLossBuffered(1.5)
else
user.adjustStaminaLossBuffered(3.5)
if(attacker_style && attacker_style.harm_act(user,target))
return TRUE
@@ -1497,13 +1500,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected))
var/miss_chance = 100//calculate the odds that a punch misses entirely. considers stamina and brute damage of the puncher. punches miss by default to prevent weird cases
if(user.dna.species.punchdamagelow)
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
miss_chance = 10
else
miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
if(unarmed_attack_flags & UNARMED_ATTACK_PARRY)
miss_chance = 0
else
if(user.dna.species.punchdamagelow)
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else if(HAS_TRAIT(user, TRAIT_PUGILIST)) //pugilists have a flat 10% miss chance
miss_chance = 10
else
miss_chance = min(10 + max(puncherstam * 0.5, puncherbrute * 0.5), 100) //probability of miss has a base of 10, and modified based on half brute total. Capped at max 100 to prevent weirdness in prob()
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1)
@@ -1681,7 +1687,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
return
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
if(!istype(M))
return
CHECK_DNA_AND_SPECIES(M)
@@ -1693,7 +1699,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
attacker_style = M.mind.martial_art
if(attacker_style?.pacifism_check && HAS_TRAIT(M, TRAIT_PACIFISM)) // most martial arts are quite harmful, alas.
attacker_style = null
switch(M.a_intent)
switch(act_intent)
if("help")
help(M, H, attacker_style)
@@ -1701,7 +1707,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
grab(M, H, attacker_style)
if("harm")
harm(M, H, attacker_style)
harm(M, H, attacker_style, unarmed_attack_flags)
if("disarm")
disarm(M, H, attacker_style)
@@ -422,9 +422,9 @@
else
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
if(world.time > last_teleport + teleport_cooldown && M != H && act_intent != INTENT_HELP)
reactive_teleport(H)
/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
@@ -519,9 +519,9 @@
var/golem_name = "[uppertext(clown_name)]"
return golem_name
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
if(world.time > last_banana + banana_cooldown && M != H && act_intent != INTENT_HELP)
new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
last_banana = world.time
@@ -830,9 +830,9 @@
if(world.time > last_gong_time + gong_cooldown)
gong(H)
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style, act_intent, unarmed_attack_flags)
..()
if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP)
if(world.time > last_gong_time + gong_cooldown && act_intent != INTENT_HELP)
gong(H)
/datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
@@ -314,7 +314,7 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state)
ui.open()
/datum/action/innate/swap_body/ui_data(mob/user)
+2 -2
View File
@@ -1,4 +1,6 @@
/mob/living/carbon/BiologicalLife(seconds, times_fired)
//Updates the number of stored chemicals for powers
handle_changeling()
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
. = ..() // if . is false, we are dead.
@@ -25,8 +27,6 @@
if(stat != DEAD)
handle_liver()
//Updates the number of stored chemicals for powers
handle_changeling()
/mob/living/carbon/PhysicalLife(seconds, times_fired)
if(!(. = ..()))
+9 -10
View File
@@ -1197,30 +1197,29 @@
/mob/living/vv_edit_var(var_name, var_value)
switch(var_name)
if ("maxHealth")
if (NAMEOF(src, maxHealth))
if (!isnum(var_value) || var_value <= 0)
return FALSE
if("stat")
if(NAMEOF(src, stat))
if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life
GLOB.dead_mob_list -= src
GLOB.alive_mob_list += src
if((stat < DEAD) && (var_value == DEAD))//Kill he
GLOB.alive_mob_list -= src
GLOB.dead_mob_list += src
if(NAMEOF(src, health)) //this doesn't work. gotta use procs instead.
return FALSE
. = ..()
switch(var_name)
if("eye_blind")
if(NAMEOF(src, eye_blind))
set_blindness(var_value)
if("eye_damage")
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
E?.setOrganDamage(var_value)
if("eye_blurry")
if(NAMEOF(src, eye_blurry))
set_blurriness(var_value)
if("maxHealth")
if(NAMEOF(src, maxHealth))
updatehealth()
if("resize")
if(NAMEOF(src, resize))
update_transform()
if("lighting_alpha")
if(NAMEOF(src, lighting_alpha))
sync_lighting_plane_alpha()
/mob/living/proc/do_adrenaline(
@@ -34,7 +34,7 @@
data = mind.martial_art.block_parry_data
method = MARTIAL_PARRY
tool = mind.martial_art
else if(combat_flags & COMBAT_FLAG_UNARMED_PARRY)
else if((combat_flags & COMBAT_FLAG_UNARMED_PARRY) && check_unarmed_parry_activation_special())
data = block_parry_data
method = UNARMED_PARRY
tool = src
@@ -93,6 +93,12 @@
if(I.can_active_parry())
return I
/**
* Check if we can unarmed parry
*/
/mob/living/proc/check_unarmed_parry_activation_special()
return TRUE
/**
* Called via timer when the parry sequence ends.
*/
+2 -2
View File
@@ -270,10 +270,10 @@
user.set_pull_offsets(src, grab_state)
return 1
/mob/living/attack_hand(mob/user)
/mob/living/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
..() //Ignoring parent return value here.
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
if((user != src) && user.a_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE, null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
if((user != src) && act_intent != INTENT_HELP && (mob_run_block(user, 0, user.name, ATTACK_TYPE_UNARMED | ATTACK_TYPE_MELEE | ((unarmed_attack_flags & UNARMED_ATTACK_PARRY)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE), null, user, check_zone(user.zone_selected), null) & BLOCK_SUCCESS))
log_combat(user, src, "attempted to touch")
visible_message("<span class='warning'>[user] attempted to touch [src]!</span>",
"<span class='warning'>[user] attempted to touch you!</span>", target = user,
@@ -0,0 +1,74 @@
/datum/robot_control
var/mob/living/silicon/ai/owner
/datum/robot_control/New(mob/living/silicon/ai/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/robot_control/proc/is_interactable(mob/user)
if(user != owner || owner.incapacitated())
return FALSE
if(owner.control_disabled)
to_chat(user, "<span class='warning'>Wireless control is disabled.</span>")
return FALSE
return TRUE
/datum/robot_control/ui_status(mob/user)
if(is_interactable(user))
return ..()
return UI_CLOSE
/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state)
ui.open()
/datum/robot_control/ui_data(mob/user)
if(!owner || user != owner)
return
var/list/data = list()
var/turf/ai_current_turf = get_turf(owner)
var/ai_zlevel = ai_current_turf.z
data["robots"] = list()
for(var/mob/living/simple_animal/bot/B in GLOB.bots_list)
if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
continue
var/list/robot_data = list(
name = B.name,
model = B.model,
mode = B.get_mode(),
hacked = B.hacked,
location = get_area_name(B, TRUE),
ref = REF(B)
)
data["robots"] += list(robot_data)
return data
/datum/robot_control/ui_act(action, params)
if(..())
return
if(!is_interactable(usr))
return
switch(action)
if("callbot") //Command a bot to move to a selected location.
if(owner.call_bot_cooldown > world.time)
to_chat(usr, "<span class='danger'>Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.</span>")
return
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.waypoint_mode = TRUE
to_chat(usr, "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>")
. = TRUE
if("interface") //Remotely connect to a bot!
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.Bot.attack_ai(usr)
. = TRUE
@@ -2,7 +2,18 @@
//as they handle all relevant stuff like adding it to the player's screen and such
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
//This proc has been butchered into a proc that overrides borg item holding for the sake of making grippers work.
//I'd be immensely thankful if anyone can figure out a less obtuse way of making grippers work without breaking functionality.
/mob/living/silicon/robot/get_active_held_item()
var/item = module_active
if(istype(item, /obj/item/weapon/gripper))
var/obj/item/weapon/gripper/G = item
if(G.wrapped)
if(G.wrapped.loc != G)
G.wrapped = null
return module_active
item = G.wrapped
return item
return module_active
@@ -444,7 +444,7 @@
/obj/item/t_scanner,
/obj/item/analyzer,
/obj/item/storage/part_replacer/cyborg,
/obj/item/holosign_creator/atmos,
/obj/item/holosign_creator/combifan,
/obj/item/weapon/gripper,
/obj/item/lightreplacer/cyborg,
/obj/item/geiger_counter/cyborg,
@@ -115,6 +115,19 @@
else
return "<span class='average'>[mode_name[mode]]</span>"
/**
* Returns a status string about the bot's current status, if it's moving, manually controlled, or idle.
*/
/mob/living/simple_animal/bot/proc/get_mode_ui()
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
return paicard ? "pAI Controlled" : "Autonomous"
else if(!on)
return "Inactive"
else if(!mode)
return "Idle"
else
return "[mode_name[mode]]"
/mob/living/simple_animal/bot/proc/turn_on()
if(stat)
return FALSE
@@ -341,7 +341,7 @@
target_types = typecacheof(target_types)
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/cleanbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(istype(A, /obj/effect/decal/cleanable))
anchored = TRUE
icon_state = "cleanbot-c"
@@ -518,7 +518,7 @@ Auto Patrol[]"},
/mob/living/simple_animal/bot/ed209/redtag
lasercolor = "r"
/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/ed209/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!on)
return
if(iscarbon(A))
@@ -58,7 +58,7 @@
internal_ext.max_water = INFINITY
internal_ext.refill()
/mob/living/simple_animal/bot/firebot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/firebot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!on)
return
if(internal_ext)
@@ -413,7 +413,7 @@
/obj/machinery/bot_core/floorbot
req_one_access = list(ACCESS_CONSTRUCTION, ACCESS_ROBOTICS)
/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/floorbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(isturf(A))
repair(A)
else
@@ -141,7 +141,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
retaliate(Proj.firer)
return ..()
/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!on)
return
if(iscarbon(A))
@@ -367,4 +367,4 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
..()
/obj/machinery/bot_core/honkbot
req_one_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS)
req_one_access = list(ACCESS_THEATRE, ACCESS_ROBOTICS)
@@ -625,7 +625,7 @@
else
..()
/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(iscarbon(A))
var/mob/living/carbon/C = A
patient = C
@@ -790,4 +790,4 @@
#undef MEDBOT_PANIC_HIGH
#undef MEDBOT_PANIC_FUCK
#undef MEDBOT_PANIC_ENDING
#undef MEDBOT_PANIC_END
#undef MEDBOT_PANIC_END
@@ -174,7 +174,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "mulebot", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "Mule", name, ui_x, ui_y, master_ui, state)
ui.open()
/mob/living/simple_animal/bot/mulebot/ui_data(mob/user)
@@ -752,7 +752,7 @@
if(load)
unload()
/mob/living/simple_animal/bot/mulebot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/mulebot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(isturf(A) && isturf(loc) && loc.Adjacent(A) && load)
unload(get_dir(loc, A))
else
@@ -208,7 +208,7 @@ Auto Patrol: []"},
return ..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A, proximity, intent = a_intent, flags = NONE)
if(!on)
return
if(iscarbon(A))
@@ -30,6 +30,7 @@
verb_yell = "buzzes intensely"
emote_see = list("buzzes.", "makes a loud buzz.", "rolls several times.", "buzzes happily.")
speak_chance = 1
unique_name = TRUE
/mob/living/simple_animal/pet/bumbles/Initialize()
. = ..()
@@ -192,6 +192,15 @@
else
..()
//a cow that produces a random reagent in its udder
/mob/living/simple_animal/cow/random
name = "strange cow"
desc = "Something seems off about the milk this cow is producing."
/mob/living/simple_animal/cow/random/Initialize()
milk_reagent = get_random_reagent_id() //this has a blacklist so don't worry about romerol cows, etc
..()
//Wisdom cow, speaks and bestows great wisdoms
/mob/living/simple_animal/cow/wisdom
name = "wisdom cow"
@@ -87,7 +87,7 @@
detonate(user)
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/guardian_bomb/attack_hand(mob/living/user)
/obj/guardian_bomb/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
detonate(user)
/obj/guardian_bomb/examine(mob/user)
@@ -385,7 +385,7 @@ Difficulty: Very Hard
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
/obj/machinery/anomalous_crystal/attack_hand(mob/user)
/obj/machinery/anomalous_crystal/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(.)
return
@@ -148,7 +148,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
desc = "You're not quite sure how a signal can be menacing."
invisibility = 100
/obj/structure/elite_tumor/attack_hand(mob/user)
/obj/structure/elite_tumor/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
. = ..()
if(ishuman(user))
switch(activity)
@@ -86,7 +86,7 @@
.=..()
START_PROCESSING(SSprocessing, src)
/obj/structure/spawner/nether/attack_hand(mob/user)
/obj/structure/spawner/nether/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
user.visible_message("<span class='warning'>[user] is violently pulled into the link!</span>", \
"<span class='userdanger'>Touching the portal, you are quickly pulled through into a world of unimaginable horror!</span>")
contents.Add(user)
@@ -0,0 +1,32 @@
//funniest shit i've ever seen
/mob/living/simple_animal/pickle
name = "pickle"
desc = "It's a pickle. It might just be the funniest thing you have ever seen."
health = 100
maxHealth = 100
icon = 'icons/mob/32x64.dmi'
icon_state = "pickle"
deathmessage = "The pickle implodes into its own existential dread and disappears!"
friendly_verb_continuous = "tickles"
friendly_verb_simple = "tickle"
del_on_death = TRUE
var/mob/living/original_body
/mob/living/simple_animal/pickle/UnarmedAttack(atom/A)
..() //we want the tickle emote to go before the laugh
if(ismob(A))
var/mob/laugher = A
laugher.emote("laugh")
/mob/living/simple_animal/pickle/death()
..()
if(original_body)
original_body.adjustOrganLoss(ORGAN_SLOT_BRAIN, 200) //to be fair, you have to have a very high iq to understand-
original_body.forceMove(get_turf(src))
if(mind)
mind.transfer_to(original_body)
/mob/living/simple_animal/pickle/wabbajack_act() //restore users name before its used on the new mob
if(original_body)
real_name = original_body.real_name
+14
View File
@@ -558,3 +558,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
//Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
return stat == DEAD || silicon_privileges //Dead guys and silicons can always see reagents
/mob/proc/is_blind()
SHOULD_BE_PURE(TRUE)
return eye_blind ? TRUE : HAS_TRAIT(src, TRAIT_BLIND)
/mob/proc/can_read(obj/O)
if(is_blind())
to_chat(src, "<span class='warning'>As you are trying to read [O], you suddenly feel very stupid!</span>")
return
if(!is_literate())
to_chat(src, "<span class='notice'>You try to read [O], but can't comprehend any of it.</span>")
return
return TRUE
+122 -48
View File
@@ -1,26 +1,8 @@
/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG))
if (mob_transforming)
#define TRANSFORMATION_DURATION 22
/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG))
if(mob_transforming || transformation_timer)
return
//Handle items on mob
//first implants & organs
var/list/stored_implants = list()
var/list/int_organs = list()
if (tr_flags & TR_KEEPIMPLANTS)
for(var/X in implants)
var/obj/item/implant/IMP = X
stored_implants += IMP
IMP.removed(src, 1, 1)
var/list/missing_bodyparts_zones = get_missing_limbs()
var/obj/item/cavity_object
var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST)
if(CH.cavity_item)
cavity_object = CH.cavity_item
CH.cavity_item = null
if(tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
@@ -30,13 +12,36 @@
//Make mob invisible and spawn animation
mob_transforming = TRUE
Stun(INFINITY, ignore_canstun = TRUE)
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify(loc)
sleep(22)
transformation_timer = addtimer(CALLBACK(src, .proc/finish_monkeyize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_monkeyize(tr_flags)
transformation_timer = null
var/list/missing_bodyparts_zones = get_missing_limbs()
var/list/stored_implants = list()
if (tr_flags & TR_KEEPIMPLANTS)
for(var/X in implants)
var/obj/item/implant/IMP = X
stored_implants += IMP
IMP.removed(src, 1, 1)
var/list/int_organs = list()
var/obj/item/cavity_object
var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST)
if(CH.cavity_item)
cavity_object = CH.cavity_item
CH.cavity_item = null
var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc )
// hash the original name?
@@ -50,6 +55,7 @@
if(tr_flags & TR_KEEPSE)
O.dna.mutation_index = dna.mutation_index
O.dna.default_mutation_genes = dna.default_mutation_genes
O.dna.set_se(1, GET_INITIALIZED_MUTATION(RACEMUT))
if(suiciding)
@@ -149,12 +155,33 @@
////////////////////////// Humanize //////////////////////////////
//Could probably be merged with monkeyize but other transformations got their own procs, too
/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG))
if (mob_transforming)
/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG))
if (mob_transforming || transformation_timer)
return
//Handle items on mob
//first implants & organs
//now the rest
if (tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
Itemlist += held_items
for(var/obj/item/W in Itemlist)
dropItemToGround(W, TRUE)
if (client)
client.screen -= W
//Make mob invisible and spawn animation
mob_transforming = TRUE
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify/humanify(loc)
transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_humanize(tr_flags)
transformation_timer = null
var/list/stored_implants = list()
var/list/int_organs = list()
@@ -173,25 +200,6 @@
cavity_object = CH.cavity_item
CH.cavity_item = null
//now the rest
if (tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
Itemlist += held_items
for(var/obj/item/W in Itemlist)
dropItemToGround(W, TRUE)
if (client)
client.screen -= W
//Make mob invisible and spawn animation
mob_transforming = TRUE
Stun(22, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify/humanify(loc)
sleep(22)
var/mob/living/carbon/human/O = new( loc )
for(var/obj/item/C in O.loc)
O.equip_to_appropriate_slot(C)
@@ -208,6 +216,7 @@
if(tr_flags & TR_KEEPSE)
O.dna.mutation_index = dna.mutation_index
O.dna.default_mutation_genes = dna.default_mutation_genes
O.dna.set_se(0, GET_INITIALIZED_MUTATION(RACEMUT))
O.domutcheck()
@@ -353,7 +362,7 @@
qdel(src)
/mob/living/carbon/human/proc/Robotize(delete_items = 0, transfer_after = TRUE)
if (mob_transforming)
if(mob_transforming)
return
for(var/obj/item/W in src)
if(delete_items)
@@ -581,3 +590,68 @@
. = new_mob
qdel(src)
/* Certain mob types have problems and should not be allowed to be controlled by players.
*
* This proc is here to force coders to manually place their mob in this list, hopefully tested.
* This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them.
*/
/mob/proc/safe_animal(MP)
//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
if(!MP)
return 0 //Sanity, this should never happen.
if(ispath(MP, /mob/living/simple_animal/hostile/construct))
return 0 //Verbs do not appear for players.
//Good mobs!
if(ispath(MP, /mob/living/simple_animal/pet/cat))
return 1
if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi))
return 1
if(ispath(MP, /mob/living/simple_animal/crab))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/carp))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
return 1
if(ispath(MP, /mob/living/simple_animal/shade))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/killertomato))
return 1
if(ispath(MP, /mob/living/simple_animal/mouse))
return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
if(ispath(MP, /mob/living/simple_animal/hostile/bear))
return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak)
if(ispath(MP, /mob/living/simple_animal/parrot))
return 1 //Parrots are no longer unfinished! -Nodrak
//Not in here? Must be untested!
return 0
#undef TRANSFORMATION_DURATION
/mob/living/proc/turn_into_pickle()
//if they're already a pickle, turn them back instead
if(istype(src, /mob/living/simple_animal/pickle))
//turn them back from being a pickle, but release them alive
var/mob/living/simple_animal/pickle/existing_pickle = src
if(existing_pickle.original_body)
existing_pickle.original_body.forceMove(get_turf(src))
if(mind)
mind.transfer_to(existing_pickle.original_body)
qdel(src)
else
//make a new pickle on the tile and move their mind into it if possible
var/mob/living/simple_animal/pickle/new_pickle = new /mob/living/simple_animal/pickle(get_turf(src))
new_pickle.original_body = src
if(mind)
mind.transfer_to(new_pickle)
//give them their old access if any
var/obj/item/card/id/mob_access_card = get_idcard()
if(mob_access_card)
new_pickle.access_card = mob_access_card
//move old body inside the pickle for safekeeping (when they die, we'll return the corpse because we're nice)
src.forceMove(new_pickle)