|
|
|
@@ -1,7 +1,6 @@
|
|
|
|
|
// This code handles different species in the game.
|
|
|
|
|
|
|
|
|
|
GLOBAL_LIST_EMPTY(roundstart_races)
|
|
|
|
|
GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
|
|
|
|
|
/datum/species
|
|
|
|
|
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
|
|
|
|
@@ -9,35 +8,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
var/name // this is the fluff name. these will be left generic (such as 'Lizardperson' for the lizard race) so servers can change them to whatever
|
|
|
|
|
var/default_color = "#FFF" // if alien colors are disabled, this is the color that will be used by that race
|
|
|
|
|
|
|
|
|
|
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
|
|
|
|
|
var/sexes = 1 // whether or not the race has sexual characteristics. at the moment this is only 0 for skeletons and shadows
|
|
|
|
|
|
|
|
|
|
//Species Icon Drawing Offsets - Pixel X, Pixel Y, Aka X = Horizontal and Y = Vertical, from bottom left corner
|
|
|
|
|
var/list/offset_features = list(
|
|
|
|
|
OFFSET_UNIFORM = list(0,0),
|
|
|
|
|
OFFSET_ID = list(0,0),
|
|
|
|
|
OFFSET_GLOVES = list(0,0),
|
|
|
|
|
OFFSET_GLASSES = list(0,0),
|
|
|
|
|
OFFSET_EARS = list(0,0),
|
|
|
|
|
OFFSET_SHOES = list(0,0),
|
|
|
|
|
OFFSET_S_STORE = list(0,0),
|
|
|
|
|
OFFSET_FACEMASK = list(0,0),
|
|
|
|
|
OFFSET_HEAD = list(0,0),
|
|
|
|
|
OFFSET_EYES = list(0,0),
|
|
|
|
|
OFFSET_LIPS = list(0,0),
|
|
|
|
|
OFFSET_BELT = list(0,0),
|
|
|
|
|
OFFSET_BACK = list(0,0),
|
|
|
|
|
OFFSET_HAIR = list(0,0),
|
|
|
|
|
OFFSET_FHAIR = list(0,0),
|
|
|
|
|
OFFSET_SUIT = list(0,0),
|
|
|
|
|
OFFSET_NECK = list(0,0),
|
|
|
|
|
OFFSET_MUTPARTS = list(0,0)
|
|
|
|
|
)
|
|
|
|
|
var/list/offset_features = list(OFFSET_UNIFORM = list(0,0), OFFSET_ID = list(0,0), OFFSET_GLOVES = list(0,0), OFFSET_GLASSES = list(0,0), OFFSET_EARS = list(0,0), OFFSET_SHOES = list(0,0), OFFSET_S_STORE = list(0,0), OFFSET_FACEMASK = list(0,0), OFFSET_HEAD = list(0,0), OFFSET_FACE = list(0,0), OFFSET_BELT = list(0,0), OFFSET_BACK = list(0,0), OFFSET_SUIT = list(0,0), OFFSET_NECK = list(0,0))
|
|
|
|
|
|
|
|
|
|
var/hair_color // this allows races to have specific hair colors... if null, it uses the H's hair/facial hair colors. if "mutcolor", it uses the H's mutant_color
|
|
|
|
|
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
|
|
|
|
|
|
|
|
|
|
var/horn_color //specific horn colors, because why not?
|
|
|
|
|
|
|
|
|
|
var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans)
|
|
|
|
|
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
|
|
|
|
|
var/exotic_bloodtype = "" //If your race uses a non standard bloodtype (A+, O-, AB-, etc)
|
|
|
|
@@ -102,7 +79,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
var/fixed_mut_color3 = ""
|
|
|
|
|
var/whitelisted = 0 //Is this species restricted to certain players?
|
|
|
|
|
var/whitelist = list() //List the ckeys that can use this species, if it's whitelisted.: list("John Doe", "poopface666", "SeeALiggerPullTheTrigger") Spaces & capitalization can be included or ignored entirely for each key as it checks for both.
|
|
|
|
|
var/should_draw_citadel = FALSE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////
|
|
|
|
|
// PROCS //
|
|
|
|
@@ -121,7 +98,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
var/datum/species/S = new I
|
|
|
|
|
if(S.check_roundstart_eligible())
|
|
|
|
|
GLOB.roundstart_races += S.id
|
|
|
|
|
GLOB.roundstart_race_names["[S.name]"] = S.id
|
|
|
|
|
qdel(S)
|
|
|
|
|
if(!GLOB.roundstart_races.len)
|
|
|
|
|
GLOB.roundstart_races += "human"
|
|
|
|
@@ -153,10 +129,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
//Please override this locally if you want to define when what species qualifies for what rank if human authority is enforced.
|
|
|
|
|
/datum/species/proc/qualifies_for_rank(rank, list/features) //SPECIES JOB RESTRICTIONS
|
|
|
|
|
//if(rank in GLOB.command_positions) Left as an example: The format qualifies for rank takes.
|
|
|
|
|
// return 0 //It returns false when it runs the proc so they don't get jobs from the global list.
|
|
|
|
|
return 1 //It returns 1 to say they are a-okay to continue.
|
|
|
|
|
/datum/species/proc/qualifies_for_rank(rank, list/features)
|
|
|
|
|
if(rank in GLOB.command_positions)
|
|
|
|
|
return 0
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
//Will regenerate missing organs
|
|
|
|
|
/datum/species/proc/regenerate_organs(mob/living/carbon/C,datum/species/old_species,replace_current=TRUE)
|
|
|
|
@@ -284,7 +260,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
C.hud_used.update_locked_slots()
|
|
|
|
|
|
|
|
|
|
// this needs to be FIRST because qdel calls update_body which checks if we have DIGITIGRADE legs or not and if not then removes DIGITIGRADE from species_traits
|
|
|
|
|
if(("legs" in C.dna.species.mutant_bodyparts) && (C.dna.features["legs"] == "Digitigrade" || C.dna.features["legs"] == "Avian"))
|
|
|
|
|
if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs")
|
|
|
|
|
species_traits += DIGITIGRADE
|
|
|
|
|
if(DIGITIGRADE in species_traits)
|
|
|
|
|
C.Digitigrade_Leg_Swap(FALSE)
|
|
|
|
@@ -318,6 +294,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
for(var/datum/disease/A in C.diseases)
|
|
|
|
|
A.cure(FALSE)
|
|
|
|
|
|
|
|
|
|
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
|
|
|
|
|
|
|
|
|
|
//CITADEL EDIT
|
|
|
|
|
if(NOAROUSAL in species_traits)
|
|
|
|
|
C.canbearoused = FALSE
|
|
|
|
@@ -328,11 +306,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
var/mob/living/carbon/human/H = C
|
|
|
|
|
if(NOGENITALS in H.dna.species.species_traits)
|
|
|
|
|
H.give_genitals(TRUE) //call the clean up proc to delete anything on the mob then return.
|
|
|
|
|
if("meat_type" in default_features) //I can't believe it's come to the meat
|
|
|
|
|
H.type_of_meat = GLOB.meat_types[H.dna.features["meat_type"]]
|
|
|
|
|
|
|
|
|
|
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// EDIT ENDS
|
|
|
|
|
|
|
|
|
@@ -344,11 +317,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
for(var/X in inherent_traits)
|
|
|
|
|
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
|
|
|
|
|
|
|
|
|
|
if("meat_type" in default_features)
|
|
|
|
|
C.type_of_meat = GLOB.meat_types[C.dna.features["meat_type"]]
|
|
|
|
|
else
|
|
|
|
|
C.type_of_meat = initial(meat)
|
|
|
|
|
|
|
|
|
|
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
|
|
|
|
|
|
|
|
|
|
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
|
|
|
|
@@ -421,10 +389,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
|
|
|
|
|
facial_overlay.alpha = hair_alpha
|
|
|
|
|
|
|
|
|
|
if(OFFSET_FHAIR in H.dna.species.offset_features)
|
|
|
|
|
facial_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FHAIR][1]
|
|
|
|
|
facial_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FHAIR][2]
|
|
|
|
|
|
|
|
|
|
standing += facial_overlay
|
|
|
|
|
|
|
|
|
|
if(H.head)
|
|
|
|
@@ -482,11 +446,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
else
|
|
|
|
|
hair_overlay.color = forced_colour
|
|
|
|
|
hair_overlay.alpha = hair_alpha
|
|
|
|
|
|
|
|
|
|
if(OFFSET_HAIR in H.dna.species.offset_features)
|
|
|
|
|
hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_HAIR][1]
|
|
|
|
|
hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_HAIR][2]
|
|
|
|
|
|
|
|
|
|
if(OFFSET_FACE in H.dna.species.offset_features)
|
|
|
|
|
hair_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
|
|
|
|
|
hair_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
|
|
|
|
|
if(hair_overlay.icon)
|
|
|
|
|
standing += hair_overlay
|
|
|
|
|
|
|
|
|
@@ -507,11 +469,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
if(H.lip_style && (LIPS in species_traits))
|
|
|
|
|
var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[H.lip_style]", -BODY_LAYER)
|
|
|
|
|
lip_overlay.color = H.lip_color
|
|
|
|
|
|
|
|
|
|
if(OFFSET_LIPS in H.dna.species.offset_features)
|
|
|
|
|
lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_LIPS][1]
|
|
|
|
|
lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_LIPS][2]
|
|
|
|
|
|
|
|
|
|
if(OFFSET_FACE in H.dna.species.offset_features)
|
|
|
|
|
lip_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
|
|
|
|
|
lip_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
|
|
|
|
|
standing += lip_overlay
|
|
|
|
|
|
|
|
|
|
// eyes
|
|
|
|
@@ -524,11 +484,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER)
|
|
|
|
|
if((EYECOLOR in species_traits) && has_eyes)
|
|
|
|
|
eye_overlay.color = "#" + H.eye_color
|
|
|
|
|
|
|
|
|
|
if(OFFSET_EYES in H.dna.species.offset_features)
|
|
|
|
|
eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_EYES][1]
|
|
|
|
|
eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_EYES][2]
|
|
|
|
|
|
|
|
|
|
if(OFFSET_FACE in H.dna.species.offset_features)
|
|
|
|
|
eye_overlay.pixel_x += H.dna.species.offset_features[OFFSET_FACE][1]
|
|
|
|
|
eye_overlay.pixel_y += H.dna.species.offset_features[OFFSET_FACE][2]
|
|
|
|
|
standing += eye_overlay
|
|
|
|
|
|
|
|
|
|
//Underwear, Undershirts & Socks
|
|
|
|
@@ -571,7 +529,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : ""
|
|
|
|
|
var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
|
|
|
|
|
if(UNDIE_COLORABLE(S))
|
|
|
|
|
MA.color = "#[H.socks_color]"
|
|
|
|
|
MA.color = "[H.socks_color]"
|
|
|
|
|
standing += MA
|
|
|
|
|
|
|
|
|
|
if(standing.len)
|
|
|
|
@@ -654,10 +612,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
else if ("wings" in mutant_bodyparts)
|
|
|
|
|
bodyparts_to_add -= "wings_open"
|
|
|
|
|
|
|
|
|
|
if("insect_fluff" in mutant_bodyparts)
|
|
|
|
|
if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
|
|
|
|
|
bodyparts_to_add -= "insect_fluff"
|
|
|
|
|
|
|
|
|
|
//CITADEL EDIT
|
|
|
|
|
//Race specific bodyparts:
|
|
|
|
|
//Xenos
|
|
|
|
@@ -761,14 +715,12 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
S = GLOB.wings_list[H.dna.features["wings"]]
|
|
|
|
|
if("wingsopen")
|
|
|
|
|
S = GLOB.wings_open_list[H.dna.features["wings"]]
|
|
|
|
|
if("deco_wings")
|
|
|
|
|
S = GLOB.deco_wings_list[H.dna.features["deco_wings"]]
|
|
|
|
|
if("legs")
|
|
|
|
|
S = GLOB.legs_list[H.dna.features["legs"]]
|
|
|
|
|
if("insect_wings")
|
|
|
|
|
S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
|
|
|
|
|
if("insect_fluff")
|
|
|
|
|
S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
|
|
|
|
|
if("moth_wings")
|
|
|
|
|
S = GLOB.moth_wings_list[H.dna.features["moth_wings"]]
|
|
|
|
|
if("moth_markings")
|
|
|
|
|
S = GLOB.moth_markings_list[H.dna.features["moth_markings"]]
|
|
|
|
|
if("caps")
|
|
|
|
|
S = GLOB.caps_list[H.dna.features["caps"]]
|
|
|
|
|
if("ipc_screen")
|
|
|
|
@@ -865,8 +817,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
accessory_overlay.color = "#[H.facial_hair_color]"
|
|
|
|
|
if(EYECOLOR)
|
|
|
|
|
accessory_overlay.color = "#[H.eye_color]"
|
|
|
|
|
if(HORNCOLOR)
|
|
|
|
|
accessory_overlay.color = "#[H.horn_color]"
|
|
|
|
|
else
|
|
|
|
|
accessory_overlay.color = forced_colour
|
|
|
|
|
else
|
|
|
|
@@ -883,11 +833,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
for(var/index=1, index<=husklist.len, index++)
|
|
|
|
|
husklist[index] = husklist[index]/255
|
|
|
|
|
accessory_overlay.color = husklist
|
|
|
|
|
|
|
|
|
|
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
|
|
|
|
|
accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
|
|
|
|
|
accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
|
|
|
|
|
|
|
|
|
|
standing += accessory_overlay
|
|
|
|
|
|
|
|
|
|
if(S.hasinner)
|
|
|
|
@@ -900,10 +845,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
if(S.center)
|
|
|
|
|
inner_accessory_overlay = center_image(inner_accessory_overlay, S.dimension_x, S.dimension_y)
|
|
|
|
|
|
|
|
|
|
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
|
|
|
|
|
inner_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
|
|
|
|
|
inner_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
|
|
|
|
|
|
|
|
|
|
standing += inner_accessory_overlay
|
|
|
|
|
|
|
|
|
|
if(S.extra) //apply the extra overlay, if there is one
|
|
|
|
@@ -941,14 +882,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
extra_accessory_overlay.color = "#[H.facial_hair_color]"
|
|
|
|
|
if(EYECOLOR)
|
|
|
|
|
extra_accessory_overlay.color = "#[H.eye_color]"
|
|
|
|
|
|
|
|
|
|
if(HORNCOLOR)
|
|
|
|
|
extra_accessory_overlay.color = "#[H.horn_color]"
|
|
|
|
|
|
|
|
|
|
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
|
|
|
|
|
extra_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
|
|
|
|
|
extra_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
|
|
|
|
|
|
|
|
|
|
standing += extra_accessory_overlay
|
|
|
|
|
|
|
|
|
|
if(S.extra2) //apply the extra overlay, if there is one
|
|
|
|
@@ -981,13 +914,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
extra2_accessory_overlay.color = "#[H.dna.features["mcolor"]]"
|
|
|
|
|
else
|
|
|
|
|
extra2_accessory_overlay.color = "#[H.hair_color]"
|
|
|
|
|
if(HORNCOLOR)
|
|
|
|
|
extra2_accessory_overlay.color = "#[H.horn_color]"
|
|
|
|
|
|
|
|
|
|
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
|
|
|
|
|
extra2_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
|
|
|
|
|
extra2_accessory_overlay.pixel_y += H.dna.species.offset_features[OFFSET_MUTPARTS][2]
|
|
|
|
|
|
|
|
|
|
standing += extra2_accessory_overlay
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1395,9 +1321,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
if(!istype(J) && istype(C))
|
|
|
|
|
J = C.jetpack
|
|
|
|
|
if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking
|
|
|
|
|
. -= 0.4
|
|
|
|
|
. -= 2
|
|
|
|
|
else if(istype(T) && T.allow_thrust(0.01, H))
|
|
|
|
|
. -= 0.4
|
|
|
|
|
. -= 2
|
|
|
|
|
|
|
|
|
|
if(!ignoreslow && gravity)
|
|
|
|
|
if(H.wear_suit)
|
|
|
|
@@ -1777,7 +1703,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
|
|
|
|
|
if(H.stat == CONSCIOUS && H != user && prob(I.force + ((100 - H.health) * 0.5))) // rev deconversion through blunt trauma.
|
|
|
|
|
var/datum/antagonist/rev/rev = H.mind.has_antag_datum(/datum/antagonist/rev)
|
|
|
|
|
var/datum/antagonist/gang/gang = H.mind.has_antag_datum(/datum/antagonist/gang && !/datum/antagonist/gang/boss)
|
|
|
|
|
var/datum/antagonist/gang/gang = H.mind.has_antag_datum(/datum/antagonist/gang/)
|
|
|
|
|
if(rev)
|
|
|
|
|
rev.remove_revolutionary(FALSE, user)
|
|
|
|
|
if(gang)
|
|
|
|
@@ -1813,130 +1739,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
|
|
|
|
H.forcesay(GLOB.hit_appends) //forcesay checks stat already.
|
|
|
|
|
return TRUE
|
|
|
|
|
|
|
|
|
|
/datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
|
|
|
|
if(!istype(M))
|
|
|
|
|
return TRUE
|
|
|
|
|
CHECK_DNA_AND_SPECIES(M)
|
|
|
|
|
CHECK_DNA_AND_SPECIES(H)
|
|
|
|
|
|
|
|
|
|
if(!istype(M)) //sanity check for drones.
|
|
|
|
|
return TRUE
|
|
|
|
|
if(M.mind)
|
|
|
|
|
attacker_style = M.mind.martial_art
|
|
|
|
|
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(M, 0, M.name, attack_type = UNARMED_ATTACK))
|
|
|
|
|
log_combat(M, H, "attempted to touch")
|
|
|
|
|
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
|
|
|
|
|
return TRUE
|
|
|
|
|
switch(M.a_intent)
|
|
|
|
|
if(INTENT_HELP)
|
|
|
|
|
if(M == H)
|
|
|
|
|
althelp(M, H, attacker_style)
|
|
|
|
|
return TRUE
|
|
|
|
|
return FALSE
|
|
|
|
|
if(INTENT_DISARM)
|
|
|
|
|
altdisarm(M, H, attacker_style)
|
|
|
|
|
return TRUE
|
|
|
|
|
return FALSE
|
|
|
|
|
|
|
|
|
|
/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
|
|
|
|
if(user == target && istype(user))
|
|
|
|
|
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
|
|
|
|
|
to_chat(user, "<span class='warning'>You're too exhausted for that.</span>")
|
|
|
|
|
return
|
|
|
|
|
if(!user.resting)
|
|
|
|
|
to_chat(user, "<span class='notice'>You can only force yourself up if you're on the ground.</span>")
|
|
|
|
|
return
|
|
|
|
|
user.visible_message("<span class='notice'>[user] forces [p_them()]self up to [p_their()] feet!</span>", "<span class='notice'>You force yourself up to your feet!</span>")
|
|
|
|
|
user.resting = 0
|
|
|
|
|
user.update_canmove()
|
|
|
|
|
user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting
|
|
|
|
|
playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
|
|
|
|
|
|
|
|
|
/datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
|
|
|
|
|
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
|
|
|
|
|
to_chat(user, "<span class='warning'>You're too exhausted.</span>")
|
|
|
|
|
return FALSE
|
|
|
|
|
if(target.check_block())
|
|
|
|
|
target.visible_message("<span class='warning'>[target] blocks [user]'s shoving attempt!</span>")
|
|
|
|
|
return FALSE
|
|
|
|
|
if(attacker_style && attacker_style.disarm_act(user,target))
|
|
|
|
|
return TRUE
|
|
|
|
|
if(user.resting)
|
|
|
|
|
return FALSE
|
|
|
|
|
else
|
|
|
|
|
if(user == target)
|
|
|
|
|
return
|
|
|
|
|
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
|
|
|
|
|
user.adjustStaminaLossBuffered(4)
|
|
|
|
|
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
|
|
|
|
|
|
|
|
|
|
if(target.w_uniform)
|
|
|
|
|
target.w_uniform.add_fingerprint(user)
|
|
|
|
|
SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
|
|
|
|
|
|
|
|
|
|
if(!target.resting)
|
|
|
|
|
target.adjustStaminaLoss(5)
|
|
|
|
|
|
|
|
|
|
if(target.is_shove_knockdown_blocked())
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var/turf/target_oldturf = target.loc
|
|
|
|
|
var/shove_dir = get_dir(user.loc, target_oldturf)
|
|
|
|
|
var/turf/target_shove_turf = get_step(target.loc, shove_dir)
|
|
|
|
|
var/mob/living/carbon/human/target_collateral_human
|
|
|
|
|
var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
|
|
|
|
|
|
|
|
|
|
//Thank you based whoneedsspace
|
|
|
|
|
target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
|
|
|
|
|
if(target_collateral_human && !target_collateral_human.resting)
|
|
|
|
|
shove_blocked = TRUE
|
|
|
|
|
else
|
|
|
|
|
target_collateral_human = null
|
|
|
|
|
target.Move(target_shove_turf, shove_dir)
|
|
|
|
|
if(get_turf(target) == target_oldturf)
|
|
|
|
|
shove_blocked = TRUE
|
|
|
|
|
|
|
|
|
|
if(shove_blocked && !target.buckled)
|
|
|
|
|
var/directional_blocked = !target.Adjacent(target_shove_turf)
|
|
|
|
|
var/targetatrest = target.resting
|
|
|
|
|
if((directional_blocked || !(target_collateral_human || target_shove_turf.shove_act(target, user))) && !targetatrest)
|
|
|
|
|
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
|
|
|
|
|
user.visible_message("<span class='danger'>[user.name] shoves [target.name], knocking them down!</span>",
|
|
|
|
|
"<span class='danger'>You shove [target.name], knocking them down!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
|
|
|
log_combat(user, target, "shoved", "knocking them down")
|
|
|
|
|
else if(target_collateral_human && !targetatrest)
|
|
|
|
|
target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
|
|
|
|
|
target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
|
|
|
|
|
user.visible_message("<span class='danger'>[user.name] shoves [target.name] into [target_collateral_human.name]!</span>",
|
|
|
|
|
"<span class='danger'>You shove [target.name] into [target_collateral_human.name]!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
|
|
|
log_combat(user, target, "shoved", "into [target_collateral_human.name]")
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
user.visible_message("<span class='danger'>[user.name] shoves [target.name]!</span>",
|
|
|
|
|
"<span class='danger'>You shove [target.name]!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
|
|
|
var/target_held_item = target.get_active_held_item()
|
|
|
|
|
var/knocked_item = FALSE
|
|
|
|
|
if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
|
|
|
|
|
target_held_item = null
|
|
|
|
|
if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID))
|
|
|
|
|
target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
|
|
|
|
|
if(target_held_item)
|
|
|
|
|
target.visible_message("<span class='danger'>[target.name]'s grip on \the [target_held_item] loosens!</span>",
|
|
|
|
|
"<span class='danger'>Your grip on \the [target_held_item] loosens!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
|
|
|
addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
|
|
|
|
|
else if(target_held_item)
|
|
|
|
|
target.dropItemToGround(target_held_item)
|
|
|
|
|
knocked_item = TRUE
|
|
|
|
|
target.visible_message("<span class='danger'>[target.name] drops \the [target_held_item]!!</span>",
|
|
|
|
|
"<span class='danger'>You drop \the [target_held_item]!!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
|
|
|
var/append_message = ""
|
|
|
|
|
if(target_held_item)
|
|
|
|
|
if(knocked_item)
|
|
|
|
|
append_message = "causing them to drop [target_held_item]"
|
|
|
|
|
else
|
|
|
|
|
append_message = "loosening their grip on [target_held_item]"
|
|
|
|
|
log_combat(user, target, "shoved", append_message)
|
|
|
|
|
|
|
|
|
|
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
|
|
|
|
|
var/hit_percent = (100-(blocked+armor))/100
|
|
|
|
|
hit_percent = (hit_percent * (100-H.physiology.damage_resistance))/100
|
|
|
|
|