This commit is contained in:
Putnam
2021-03-02 01:44:58 -08:00
477 changed files with 6805 additions and 1201 deletions
+50 -2
View File
@@ -128,10 +128,58 @@
if(dbflags & DB_FLAG_AGE_CONFIRMATION_INCOMPLETE) //they have not completed age gate
var/age_verification = age_gate()
if(age_verification != 1)
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process")
client.add_system_note("Automated-Age-Gate", "Failed automatic age gate process.")
//ban them and kick them
AddBan(client.ckey, client.computer_id, "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification.", "SYSTEM", FALSE, null, client.address)
//parameters used by sql line, easier to read:
var/bantype_str = "ADMIN_PERMABAN"
var/reason = "SYSTEM BAN - Inputted date during join verification was under 18 years of age. Contact administration on discord for verification."
var/duration = -1
var/sql_ckey = sanitizeSQL(client.ckey)
var/computerid = client.computer_id
if(!computerid)
computerid = "0"
var/sql_computerid = sanitizeSQL(computerid)
var/ip = client.address
if(!ip)
ip = "0.0.0.0"
var/sql_ip = sanitizeSQL(ip)
//parameter not used as there's no job but i want to fill out all parameters for the insert line
var/sql_job
// these are typically the banning admin's, but it's the system so we leave them null, but they're still here for the sake of a full set of values
var/sql_a_ckey
var/sql_a_computerid
var/sql_a_ip
// record all admins and non-admins online at the time
var/who
for(var/client/C in GLOB.clients)
if(!who)
who = "[C]"
else
who += ", [C]"
var/adminwho
for(var/client/C in GLOB.admins)
if(!adminwho)
adminwho = "[C]"
else
adminwho += ", [C]"
var/sql = "INSERT INTO [format_table_name("ban")] (`bantime`,`server_ip`,`server_port`,`round_id`,`bantype`,`reason`,`job`,`duration`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`) VALUES (Now(), INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', '[GLOB.round_id]', '[bantype_str]', '[reason]', '[sql_job]', [(duration)?"[duration]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[sql_ckey]', '[sql_computerid]', INET_ATON('[sql_ip]'), '[sql_a_ckey]', '[sql_a_computerid]', INET_ATON('[sql_a_ip]'), '[who]', '[adminwho]')"
var/datum/DBQuery/query_add_ban = SSdbcore.NewQuery(sql)
qdel(query_add_ban)
// announce this
message_admins("[html_encode(client.ckey)] has been banned for failing the automatic age gate.")
send2irc("[html_encode(client.ckey)] has been banned for failing the automatic age gate.")
// removing the client disconnects them
qdel(client)
return FALSE
else
//they claim to be of age, so allow them to continue and update their flags
+4 -2
View File
@@ -556,7 +556,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/list/dest = list() //List of possible destinations (mobs)
var/target = null //Chosen target.
dest += getpois(mobs_only=1) //Fill list, prompt user with list
dest += getpois(mobs_only = TRUE) //Fill list, prompt user with list
target = input("Please, select a player!", "Jump to Mob", null, null) as null|anything in dest
if (!target)//Make sure we actually have a target
@@ -893,7 +893,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if (!eye_name)
return
var/mob/mob_eye = creatures[eye_name]
do_observe(creatures[eye_name])
/mob/dead/observer/proc/do_observe(mob/mob_eye)
//Istype so we filter out points of interest that are not mobs
if(client && mob_eye && istype(mob_eye))
client.eye = mob_eye
+28 -6
View File
@@ -1,5 +1,6 @@
/datum/orbit_menu
var/mob/dead/observer/owner
var/auto_observe = FALSE
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
@@ -10,6 +11,7 @@
return GLOB.observer_state
/datum/orbit_menu/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, "Orbit")
ui.open()
@@ -18,15 +20,35 @@
if (..())
return
if (action == "orbit")
var/ref = params["ref"]
var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list)
if (poi != null)
switch(action)
if ("orbit")
var/ref = params["ref"]
var/atom/movable/poi = (locate(ref) in GLOB.mob_list) || (locate(ref) in GLOB.poi_list)
if (poi == null)
. = TRUE
return
owner.ManualFollow(poi)
owner.reset_perspective(null)
if (auto_observe)
owner.do_observe(poi)
. = TRUE
if ("refresh")
update_static_data(owner, ui)
. = TRUE
if ("toggle_observe")
auto_observe = !auto_observe
if (auto_observe && owner.orbit_target)
owner.do_observe(owner.orbit_target)
else
owner.reset_perspective(null)
/datum/orbit_menu/ui_data(mob/user)
var/list/data = list()
data["auto_observe"] = auto_observe
return data
/datum/orbit_menu/ui_static_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
@@ -34,7 +56,7 @@
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(skip_mindless = 1)
var/list/pois = getpois(skip_mindless = TRUE, specify_dead_role = FALSE)
for (var/name in pois)
var/list/serialized = list()
serialized["name"] = name
@@ -80,7 +102,7 @@
data["npcs"] = npcs
return data
/datum/orbit_menu/ui_assets()
. = ..() || list()
. += get_asset_datum(/datum/asset/simple/orbit)
@@ -11,6 +11,10 @@
bubble_icon = "alien"
type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/xeno
/// Whether they can ventcrawl; this is set individually for 'humanoid' and 'royal' types
/// 'royal' types (Praetorian, Queen) cannot ventcrawl
var/can_ventcrawl
/// How much brute damage without armor piercing they do against mobs in melee
var/meleeSlashHumanPower = 20
/// How much power they have for DefaultCombatKnockdown when attacking humans
@@ -38,7 +42,8 @@
create_internal_organs()
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
if(can_ventcrawl)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
. = ..()
@@ -20,6 +20,8 @@
bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien,
/obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien)
can_ventcrawl = TRUE
//This is fine right now, if we're adding organ specific damage this needs to be updated
/mob/living/carbon/alien/humanoid/Initialize()
@@ -9,6 +9,7 @@
layer = LARGE_MOB_LAYER //above most mobs, but below speechbubbles
pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper.
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/xeno = 20, /obj/item/stack/sheet/animalhide/xeno = 3)
can_ventcrawl = FALSE
meleeKnockdownPower = 125
meleeSlashHumanPower = 30
@@ -11,6 +11,8 @@
maxHealth = 25
health = 25
can_ventcrawl = TRUE
var/amount_grown = 0
var/max_grown = 100
var/time_of_birth
+3
View File
@@ -434,6 +434,9 @@
legcuffed.forceMove(drop_location())
legcuffed = null
I.dropped(src)
if(istype(I, /obj/item/restraints/legcuffs))
var/obj/item/restraints/legcuffs/lgcf = I
lgcf.on_removed()
update_inv_legcuffed()
return
else
+19 -13
View File
@@ -281,11 +281,13 @@
dropItemToGround(pocket_item)
if(!usr.can_hold_items() || !usr.put_in_hands(pocket_item))
pocket_item.forceMove(drop_location())
log_combat(usr, src, "pickpocketed of item: [pocket_item]")
else
if(place_item)
if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE))
usr.temporarilyRemoveItemFromInventory(place_item, TRUE)
equip_to_slot(place_item, pocket_id, TRUE)
log_combat(usr, src, "placed item [place_item] onto")
//do nothing otherwise
// Update strip window
@@ -293,8 +295,9 @@
show_inv(usr)
else
// Display a warning if the user mocks up
if (!strip_silence)
if(!strip_silence)
to_chat(src, "<span class='warning'>You feel your [pocket_side] pocket being fumbled with!</span>")
log_combat(usr, src, "failed to [pocket_item ? "pickpocket item [pocket_item] from" : "place item [place_item] onto "]")
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY, null, FALSE))
// separate from first canusetopic
@@ -938,43 +941,43 @@
admin_ticket_log(src, msg)
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
var/GS_needed = istype(target, /mob/living/silicon/pai)? GRAB_PASSIVE : GRAB_AGGRESSIVE
if(pulling == target && grab_state >= GS_needed && stat == CONSCIOUS)
//If they dragged themselves and we're currently aggressively grabbing them try to piggyback
if(user == target && can_piggyback(target))
piggyback(target)
return
//If you dragged them to you and you're aggressively grabbing try to fireman carry them
else if(user != target)
else if(user == src)
if(user.a_intent == INTENT_GRAB)
fireman_carry(target)
return
. = ..()
//src is the user that will be carrying, target is the mob to be carried
/mob/living/carbon/human/proc/can_piggyback(mob/living/carbon/target)
return (istype(target) && target.stat == CONSCIOUS)
/mob/living/carbon/human/proc/can_piggyback(mob/living/target)
return (iscarbon(target) || ispAI(target)) && target.stat == CONSCIOUS
/mob/living/carbon/human/proc/can_be_firemanned(mob/living/carbon/target)
return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND))
return (ishuman(target) && !CHECK_MOBILITY(target, MOBILITY_STAND)) || ispAI(target)
/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
var/carrydelay = 50 //if you have latex you are faster at grabbing
var/skills_space = "" //cobby told me to do this
if(HAS_TRAIT(src, TRAIT_QUICKER_CARRY))
carrydelay = 30
skills_space = "expertly"
skills_space = "expertly "
else if(HAS_TRAIT(src, TRAIT_QUICK_CARRY))
carrydelay = 40
skills_space = "quickly"
skills_space = "quickly "
if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
visible_message("<span class='notice'>[src] starts [skills_space] lifting [target] onto their back..</span>",
visible_message("<span class='notice'>[src] starts [skills_space]lifting [target] onto their back..</span>",
//Joe Medic starts quickly/expertly lifting Grey Tider onto their back..
"<span class='notice'>[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space] start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]</span>")
"<span class='notice'>[carrydelay < 35 ? "Using your gloves' nanochips, you" : "You"] [skills_space]start to lift [target] onto your back[carrydelay == 40 ? ", while assisted by the nanochips in your gloves.." : "..."]</span>")
//(Using your gloves' nanochips, you/You) ( /quickly/expertly) start to lift Grey Tider onto your back(, while assisted by the nanochips in your gloves../...)
if(do_after(src, carrydelay, TRUE, target))
//Second check to make sure they're still valid to be carried
if(can_be_firemanned(target) && !incapacitated(FALSE, TRUE))
target.set_resting(FALSE, TRUE)
buckle_mob(target, TRUE, TRUE, 90, 1, 0, TRUE)
return
visible_message("<span class='warning'>[src] fails to fireman carry [target]!")
@@ -992,13 +995,13 @@
if(target.incapacitated(FALSE, TRUE) || incapacitated(FALSE, TRUE))
target.visible_message("<span class='warning'>[target] can't hang onto [src]!</span>")
return
buckle_mob(target, TRUE, TRUE, FALSE, 1, 2, FALSE)
buckle_mob(target, TRUE, TRUE, 0, 1, 2, FALSE)
else
visible_message("<span class='warning'>[target] fails to climb onto [src]!</span>")
else
to_chat(target, "<span class='warning'>You can't piggyback ride [src] right now!</span>")
/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = FALSE, hands_needed = 0, target_hands_needed = 0, fireman = FALSE)
/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, lying_buckle = 0, hands_needed = 0, target_hands_needed = 0, fireman = FALSE)
if(!force)//humans are only meant to be ridden through piggybacking and special cases
return
if(!is_type_in_typecache(target, can_ride_typecache))
@@ -1010,6 +1013,9 @@
riding_datum.ride_check_rider_restrained = TRUE
if(buckled_mobs && ((target in buckled_mobs) || (buckled_mobs.len >= max_buckled_mobs)) || buckled)
return
if(istype(target, /mob/living/silicon/pai))
hands_needed = 1
target_hands_needed = 0
var/equipped_hands_self
var/equipped_hands_target
if(hands_needed)
@@ -71,7 +71,7 @@
var/list/datum/bioware = list()
var/creamed = FALSE //to use with creampie overlays
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot))
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot, /mob/living/silicon/pai))
var/lastpuke = 0
var/account_id
var/last_fire_update
@@ -95,9 +95,10 @@
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_cooldown = 3 SECONDS
parry_failed_cooldown_duration = 1.5 SECONDS
parry_failed_stagger_duration = 1 SECONDS
parry_failed_clickcd_duration = 0.4 SECONDS
parry_data = list( // yeah it's snowflake
"UNARMED_PARRY_STAGGER" = 3 SECONDS,
@@ -135,14 +136,14 @@
parry_imperfect_falloff_percent = 20
parry_efficiency_perfect = 100
parry_efficiency_perfect_override = list(
ATTACK_TYPE_PROJECTILE_TEXT = 60,
TEXT_ATTACK_TYPE_PROJECTILE = 60,
)
parry_efficiency_considered_successful = 0.01
parry_efficiency_to_counterattack = 0.01
parry_max_attacks = INFINITY
parry_failed_cooldown_duration = 1.5 SECONDS
parry_failed_stagger_duration = 0
parry_failed_stagger_duration = 1 SECONDS
parry_cooldown = 0
parry_failed_clickcd_duration = 0.8
+36 -25
View File
@@ -80,6 +80,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/list/inherent_traits = list()
var/inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID
var/list/blacklisted_quirks = list() // Quirks that will be removed upon gaining this species, to be defined by species
var/list/removed_quirks = list() // Quirks that got removed due to being blacklisted, and will be restored when on_species_loss() is called
var/attack_verb = "punch" // punch-specific attack verb
var/sound/attack_sound = 'sound/weapons/punch1.ogg'
var/sound/miss_sound = 'sound/weapons/punchmiss.ogg'
@@ -342,6 +345,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/X in inherent_traits)
ADD_TRAIT(C, X, SPECIES_TRAIT)
//lets remove those conflicting quirks
remove_blacklisted_quirks(C)
if(TRAIT_VIRUSIMMUNE in inherent_traits)
for(var/datum/disease/A in C.diseases)
A.cure(FALSE)
@@ -395,6 +401,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/X in inherent_traits)
REMOVE_TRAIT(C, X, SPECIES_TRAIT)
// lets restore the quirks that got removed when gaining this species
restore_quirks(C)
C.remove_movespeed_modifier(/datum/movespeed_modifier/species)
if(mutant_bodyparts["meat_type"])
@@ -424,6 +433,26 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src)
// shamelessly inspired by antag_datum.remove_blacklisted_quirks()
/datum/species/proc/remove_blacklisted_quirks(mob/living/carbon/C)
var/mob/living/L = C.mind?.current
if(istype(L))
var/list/my_quirks = L.client?.prefs.all_quirks.Copy()
SSquirks.filter_quirks(my_quirks, blacklisted_quirks)
for(var/q in L.roundstart_quirks)
var/datum/quirk/Q = q
if(!(SSquirks.quirk_name_by_path(Q.type) in my_quirks))
L.remove_quirk(Q.type)
removed_quirks += Q.type
// restore any quirks that we removed
/datum/species/proc/restore_quirks(mob/living/carbon/C)
var/mob/living/L = C.mind?.current
if(istype(L))
for(var/q in removed_quirks)
L.add_quirk(q)
/datum/species/proc/handle_hair(mob/living/carbon/human/H, forced_colour)
H.remove_overlay(HAIR_LAYER)
var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
@@ -1425,8 +1454,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
var/punchwoundbonus = user.dna.species.punchwoundbonus
var/puncherstam = user.getStaminaLoss()
var/puncherbrute = user.getBruteLoss()
var/punchedstam = target.getStaminaLoss()
var/punchedbrute = target.getBruteLoss()
@@ -1434,7 +1461,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!SEND_SIGNAL(target, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
damage *= 1.2
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
damage *= 0.8
damage *= 0.65
if(SEND_SIGNAL(user, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
damage *= 0.8
//END OF CITADEL CHANGES
@@ -1446,19 +1473,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!affecting) //Maybe the bodypart is missing? Or things just went wrong..
affecting = target.get_bodypart(BODY_ZONE_CHEST) //target chest instead, as failsafe. Or hugbox? You decide.
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(attackchain_flags & ATTACK_IS_PARRY_COUNTERATTACK)
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, being good at Punching People, also never miss
miss_chance = 0
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
if(!damage || !affecting)//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)
target.visible_message("<span class='danger'>[user]'s [atk_verb] misses [target]!</span>", \
"<span class='danger'>You avoid [user]'s [atk_verb]!</span>", "<span class='hear'>You hear a swoosh!</span>", null, COMBAT_MESSAGE_RANGE, null, \
@@ -1468,9 +1483,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/armor_block = target.run_armor_check(affecting, "melee")
if(HAS_TRAIT(user, TRAIT_MAULER)) // maulers get 15 armorpierce because if you're going to punch someone you might as well do a good job of it
armor_block = target.run_armor_check(affecting, "melee", armour_penetration = 15) // lot of good that sec jumpsuit did you
playsound(target.loc, user.dna.species.attack_sound, 25, 1, -1)
target.visible_message("<span class='danger'>[user] [atk_verb]ed [target]!</span>", \
"<span class='userdanger'>[user] [atk_verb]ed you!</span>", null, COMBAT_MESSAGE_RANGE, null, \
@@ -1487,9 +1499,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
target.apply_damage(damage*1.5, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*0.5, STAMINA, affecting, armor_block)
log_combat(user, target, "kicked")
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.1x raw damage + 1.3x stam damage, and have some armor pierce
target.apply_damage(damage*1.1, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
target.apply_damage(damage*1.3, STAMINA, affecting, armor_block)
else if(HAS_TRAIT(user, TRAIT_MAULER)) // mauler punches deal 1.2x raw damage but nstam
target.apply_damage(damage*1.2, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
log_combat(user, target, "punched (mauler)")
else //other attacks deal full raw damage + 2x in stamina damage
target.apply_damage(damage, attack_type, affecting, armor_block, wound_bonus = punchwoundbonus)
@@ -1561,9 +1572,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!user.UseStaminaBuffer(3, warn = TRUE))
return FALSE
user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP)
target.adjust_arousal(20,maso = TRUE)
target.adjust_arousal(20,"masochism", maso = TRUE)
if (ishuman(target) && HAS_TRAIT(target, TRAIT_MASO) && target.has_dna() && prob(10))
target.mob_climax(forced_climax=TRUE)
target.mob_climax(forced_climax=TRUE, cause = "masochism")
if (!HAS_TRAIT(target, TRAIT_PERMABONER))
stop_wagging_tail(target)
playsound(target.loc, 'sound/weapons/slap.ogg', 50, 1, -1)
@@ -1945,7 +1956,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(BP.receive_damage(damage_amount, 0, wound_bonus = wound_bonus, bare_wound_bonus = bare_wound_bonus, sharpness = sharpness))
H.update_damage_overlays()
if(HAS_TRAIT(H, TRAIT_MASO) && prob(damage_amount))
H.mob_climax(forced_climax=TRUE)
H.mob_climax(forced_climax=TRUE, cause = "masochism")
else//no bodypart, we deal damage with a more general method.
H.adjustBruteLoss(damage_amount)
@@ -30,10 +30,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
/datum/species/dwarf/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
var/dwarf_hair = pick("Beard (Dwarf)", "Beard (Very Long)", "Beard (Long)") //beard roullette
var/mob/living/carbon/human/H = C
H.facial_hair_style = dwarf_hair
H.update_hair()
H.AddElement(/datum/element/dwarfism, COMSIG_SPECIES_LOSS, src)
RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech) //We register handle_speech is being used.
@@ -58,7 +58,7 @@
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
C.dust()
var/area/A = get_area(C)
if(istype(A, /area/chapel))
if(istype(A, /area/chapel) && C.mind?.assigned_role != "Chaplain")
to_chat(C, "<span class='danger'>You don't belong here!</span>")
C.adjustFireLoss(5)
C.adjust_fire_stacks(6)
@@ -37,6 +37,7 @@
armor = 20 // 120 damage to KO a zombie, which kills it
speedmod = 1.6 // they're very slow
mutanteyes = /obj/item/organ/eyes/night_vision/zombie
blacklisted_quirks = list(/datum/quirk/nonviolent)
var/heal_rate = 1
var/regen_cooldown = 0
+2
View File
@@ -10,6 +10,8 @@
/mob/living/carbon/can_speak_vocal(message)
if(silent)
return 0
if(get_selected_language() == /datum/language/signlanguage && handcuffed)
return 0
return ..()
/mob/living/carbon/could_speak_language(datum/language/language)
+1 -1
View File
@@ -866,7 +866,7 @@
if(istype(G))
strip_mod = G.strip_mod
strip_silence = G.strip_silence
if (!strip_silence)
if(!strip_silence)
who.visible_message("<span class='danger'>[src] tries to remove [who]'s [what.name].</span>", \
"<span class='userdanger'>[src] tries to remove your [what.name].</span>", target = src,
target_message = "<span class='danger'>You try to remove [who]'s [what.name].</span>")
+31 -5
View File
@@ -2,7 +2,7 @@
/**
* Determines if we can actively parry.
*/
/obj/item/proc/can_active_parry()
/obj/item/proc/can_active_parry(mob/user)
return block_parry_data && (item_flags & ITEM_CAN_PARRY)
/**
@@ -23,13 +23,16 @@
if(!(combat_flags & COMBAT_FLAG_PARRY_CAPABLE))
to_chat(src, "<span class='warning'>You are not something that can parry attacks.</span>")
return
if(!(mobility_flags & MOBILITY_STAND))
to_chat(src, "<span class='warning'>You aren't able to parry without solid footing!</span>")
return
// Prioritize item, then martial art, then unarmed.
// yanderedev else if time
var/obj/item/using_item = get_active_held_item()
var/datum/block_parry_data/data
var/datum/tool
var/method
if(using_item?.can_active_parry())
if(using_item?.can_active_parry(src))
data = using_item.block_parry_data
method = ITEM_PARRY
tool = using_item
@@ -50,9 +53,20 @@
using_item = backup
method = ITEM_PARRY
var/list/other_items = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items) & COMPONENT_PREVENT_PARRY_START)
var/list/override = list()
if(SEND_SIGNAL(src, COMSIG_LIVING_ACTIVE_PARRY_START, method, tool, other_items, override) & COMPONENT_PREVENT_PARRY_START)
to_chat(src, "<span class='warning'>Something is preventing you from parrying!</span>")
return
if(length(override))
var/datum/thing = override[1]
var/_method = override[thing]
if(_method == ITEM_PARRY)
using_item = thing
method = ITEM_PARRY
data = using_item.block_parry_data
else if(_method == UNARMED_PARRY)
method = UNARMED_PARRY
data = thing
if(!using_item && !method && length(other_items))
using_item = other_items[1]
method = ITEM_PARRY
@@ -94,7 +108,7 @@
*/
/mob/living/proc/find_backup_parry_item()
for(var/obj/item/I in held_items - get_active_held_item())
if(I.can_active_parry())
if(I.can_active_parry(src))
return I
/**
@@ -231,7 +245,7 @@
var/efficiency = data.get_parry_efficiency(attack_type, get_parry_time())
switch(parrying)
if(ITEM_PARRY)
if(!active_parry_item.can_active_parry())
if(!active_parry_item.can_active_parry(src))
return BLOCK_NONE
. = active_parry_item.on_active_parry(src, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, return_list, efficiency, get_parry_time())
if(UNARMED_PARRY)
@@ -243,6 +257,18 @@
if(efficiency <= 0) // Do not allow automatically handled/standardized parries that increase damage for now.
return
. |= BLOCK_SHOULD_PARTIAL_MITIGATE
if(efficiency >= data.parry_efficiency_perfect)
. |= data.perfect_parry_block_return_flags
if(data.perfect_parry_block_return_list)
return_list |= data.perfect_parry_block_return_list
else if(efficiency >= data.parry_efficiency_considered_successful)
. |= data.imperfect_parry_block_return_flags
if(data.imperfect_parry_block_return_list)
return_list |= data.imperfect_parry_block_return_list
else
. |= data.failed_parry_block_return_flags
if(data.failed_parry_block_return_list)
return_list |= data.failed_parry_block_return_list
if(isnull(return_list[BLOCK_RETURN_MITIGATION_PERCENT])) // if one of the on_active_parry procs overrode. We don't have to worry about interference since parries are the first thing checked in the [do_run_block()] sequence.
return_list[BLOCK_RETURN_MITIGATION_PERCENT] = clamp(efficiency, 0, 100) // do not allow > 100% or < 0% for now.
if((return_list[BLOCK_RETURN_MITIGATION_PERCENT] >= 100) || (damage <= 0))
@@ -157,6 +157,16 @@ GLOBAL_LIST_EMPTY(block_parry_data)
/// Parry cooldown post-parry if failed. This is ADDED to parry_cooldown!!!
var/parry_failed_cooldown_duration = 0 SECONDS
// Advanced
/// Flags added to return value
var/perfect_parry_block_return_flags = NONE
var/imperfect_parry_block_return_flags = NONE
var/failed_parry_block_return_flags = NONE
/// List appended to block return
var/perfect_parry_block_return_list
var/imperfect_parry_block_return_list
var/failed_parry_block_return_list
/**
* Quirky proc to get average of flags in list that are in attack_type because why is attack_type a flag.
*/
+4
View File
@@ -26,6 +26,8 @@
update_sprint_icon()
/mob/living/proc/enable_sprint_mode(update_icon = TRUE)
if(!CONFIG_GET(flag/sprint_enabled))
return
if(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
return
ENABLE_BITFIELD(combat_flags, COMBAT_FLAG_SPRINT_ACTIVE)
@@ -61,6 +63,8 @@
update_sprint_icon()
/mob/living/proc/user_toggle_intentional_sprint_mode()
if(!CONFIG_GET(flag/sprint_enabled))
return
var/old = (combat_flags & COMBAT_FLAG_SPRINT_TOGGLED)
if(old)
if(combat_flags & COMBAT_FLAG_SPRINT_FORCED)
+19 -1
View File
@@ -329,8 +329,26 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
if(HAS_TRAIT(src, TRAIT_MUTE))
var/obj/item/bodypart/leftarm = get_bodypart(BODY_ZONE_L_ARM)
var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM)
if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage)
return 0
if (get_selected_language() == /datum/language/signlanguage)
var/left_disabled = FALSE
var/right_disabled = FALSE
if (istype(leftarm)) // Need to check if the arms exist first before checking if they are disabled or else it will runtime
if (leftarm.is_disabled())
left_disabled = TRUE
else
left_disabled = TRUE
if (istype(rightarm))
if (rightarm.is_disabled())
right_disabled = TRUE
else
right_disabled = TRUE
if (left_disabled && right_disabled) // We want this to only return false if both arms are either missing or disabled since you could technically sign one-handed.
return 0
if(is_muzzled())
return 0
+5 -1
View File
@@ -11,7 +11,7 @@
maxHealth = 500
layer = BELOW_MOB_LAYER
var/obj/item/instrument/piano_synth/internal_instrument
silicon_privileges = PRIVILEDGES_PAI
silicon_privileges = PRIVILEGES_PAI
var/network = "ss13"
var/obj/machinery/camera/current = null
@@ -143,6 +143,10 @@
custom_holoform.Grant(src)
emitter_next_use = world.time + 10 SECONDS
/mob/living/silicon/pai/deployed/Initialize()
. = ..()
fold_out(TRUE)
/mob/living/silicon/pai/ComponentInitialize()
. = ..()
if(possible_chassis[chassis])
+10 -8
View File
@@ -289,11 +289,13 @@
return FALSE
return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range)
/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/weldingtool/W, mob/user)
if (!getBruteLoss())
/mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/W, mob/user)
if(!W.tool_behaviour == TOOL_WELDER)
return
if(!getBruteLoss())
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
if (!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
if(!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away.
return
user.DelayNextAction(CLICK_CD_MELEE)
if(src == user)
@@ -333,7 +335,7 @@
to_chat(user, "The wires seem fine, there's no need to fix them.")
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
if(W.tool_behaviour == TOOL_WELDER && (user.a_intent != INTENT_HARM || user == src))
INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user)
return
@@ -341,7 +343,7 @@
INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user)
return
else if(istype(W, /obj/item/crowbar)) // crowbar means open or close the cover
else if(W.tool_behaviour == TOOL_CROWBAR) // crowbar means open or close the cover
if(opened)
to_chat(user, "<span class='notice'>You close the cover.</span>")
opened = 0
@@ -373,12 +375,12 @@
else
to_chat(user, "<span class='warning'>You can't reach the wiring!</span>")
else if(istype(W, /obj/item/screwdriver) && opened && !cell) // haxing
else if(W.tool_behaviour == TOOL_SCREWDRIVER && opened && !cell) // haxing
wiresexposed = !wiresexposed
to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]")
update_icons()
else if(istype(W, /obj/item/screwdriver) && opened && cell) // radio
else if((W.tool_behaviour == TOOL_SCREWDRIVER) && opened && cell) // radio
if(shell)
to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
else if(radio)
@@ -387,7 +389,7 @@
to_chat(user, "<span class='warning'>Unable to locate a radio!</span>")
update_icons()
else if(istype(W, /obj/item/wrench) && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module.
else if(W.tool_behaviour == TOOL_WRENCH && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module.
if(!locked_down)
to_chat(user, "<span class='boldannounce'>[src]'s bolts spark! Maybe you should lock them down first!</span>")
spark_system.start()
@@ -1,4 +1,7 @@
/mob/living/silicon/robot/default_toggle_sprint(shutdown = FALSE)
if(!CONFIG_GET(flag/sprint_enabled))
disable_intentional_sprint_mode()
return
var/current = (combat_flags & COMBAT_FLAG_SPRINT_ACTIVE)
if(current || shutdown || !cell || (cell.charge < 25) || !cansprint)
disable_intentional_sprint_mode()
+1 -1
View File
@@ -1,6 +1,6 @@
/mob/living/silicon
gender = NEUTER
silicon_privileges = PRIVILEDGES_SILICON
silicon_privileges = PRIVILEGES_SILICON
verb_say = "states"
verb_ask = "queries"
verb_exclaim = "declares"
@@ -15,7 +15,7 @@
maxbodytemp = INFINITY
minbodytemp = 0
blood_volume = 0
silicon_privileges = PRIVILEDGES_BOT
silicon_privileges = PRIVILEGES_BOT
sentience_type = SENTIENCE_ARTIFICIAL
status_flags = NONE //no default canpush
verb_say = "states"
@@ -306,7 +306,7 @@
show_controls(user)
/mob/living/simple_animal/bot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/screwdriver))
if(W.tool_behaviour == TOOL_SCREWDRIVER)
if(!locked)
open = !open
to_chat(user, "<span class='notice'>The maintenance panel is now [open ? "opened" : "closed"].</span>")
@@ -335,7 +335,7 @@
user.visible_message("<span class='notice'>[user] uses [W] to pull [paicard] out of [bot_name]!</span>","<span class='notice'>You pull [paicard] out of [bot_name] with [W].</span>")
ejectpai(user)
else
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM)
if(health >= maxHealth)
to_chat(user, "<span class='warning'>[src] does not need a repair!</span>")
return
@@ -100,7 +100,7 @@
build_step++
if(ASSEMBLY_FOURTH_STEP)
if(istype(W, /obj/item/weldingtool))
if(W.tool_behaviour == TOOL_WELDER)
if(W.use_tool(src, user, 0, volume=40) && build_step == ASSEMBLY_FOURTH_STEP)
name = "shielded frame assembly"
to_chat(user, "<span class='notice'>You weld the vest to [src].</span>")
@@ -180,7 +180,7 @@
build_step++
if(8)
if(istype(W, /obj/item/screwdriver))
if(W.tool_behaviour == TOOL_SCREWDRIVER)
to_chat(user, "<span class='notice'>You start attaching the gun to the frame...</span>")
if(W.use_tool(src, user, 40, volume=100) && build_step == 8)
name = "armed [name]"
@@ -386,13 +386,13 @@
var/atom/Tsec = drop_location()
switch(build_step)
if(ASSEMBLY_FIRST_STEP)
if(istype(I, /obj/item/weldingtool))
if(I.tool_behaviour == TOOL_WELDER)
if(I.use_tool(src, user, 0, volume=40))
add_overlay("hs_hole")
to_chat(user, "<span class='notice'>You weld a hole in [src]!</span>")
build_step++
else if(istype(I, /obj/item/screwdriver)) //deconstruct
else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct
new /obj/item/assembly/signaler(Tsec)
new /obj/item/clothing/head/helmet/sec(Tsec)
to_chat(user, "<span class='notice'>You disconnect the signaler from the helmet.</span>")
@@ -408,7 +408,7 @@
qdel(I)
build_step++
else if(istype(I, /obj/item/weldingtool)) //deconstruct
else if(I.tool_behaviour == TOOL_WELDER) //deconstruct
if(I.use_tool(src, user, 0, volume=40))
cut_overlay("hs_hole")
to_chat(user, "<span class='notice'>You weld the hole in [src] shut!</span>")
@@ -425,7 +425,7 @@
qdel(I)
build_step++
else if(istype(I, /obj/item/screwdriver)) //deconstruct
else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct
cut_overlay("hs_eye")
new /obj/item/assembly/prox_sensor(Tsec)
to_chat(user, "<span class='notice'>You detach the proximity sensor from [src].</span>")
@@ -442,7 +442,7 @@
S.robot_arm = robot_arm
qdel(I)
qdel(src)
if(istype(I, /obj/item/wrench))
if(I.tool_behaviour == TOOL_WRENCH)
to_chat(user, "You adjust [src]'s arm slots to mount extra weapons")
build_step ++
return
@@ -466,7 +466,7 @@
qdel(I)
qdel(src)
else if(istype(I, /obj/item/screwdriver)) //deconstruct
else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct
cut_overlay("hs_arm")
var/obj/item/bodypart/dropped_arm = new robot_arm(Tsec)
robot_arm = null
@@ -499,7 +499,7 @@
S.robot_arm = robot_arm
qdel(I)
qdel(src)
else if(istype(I, /obj/item/screwdriver)) //deconstruct
else if(I.tool_behaviour == TOOL_SCREWDRIVER) //deconstruct
build_step--
icon_state = initial(icon_state)
to_chat(user, "<span class='notice'>You unbolt [src]'s energy swords</span>")
@@ -184,9 +184,9 @@ Auto Patrol[]"},
/mob/living/simple_animal/bot/ed209/attackby(obj/item/W, mob/user, params)
..()
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
if(!istype(W, /obj/item/screwdriver) && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
if(!W.tool_behaviour == TOOL_SCREWDRIVER && (!target)) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
if(W.force && W.damtype != STAMINA)//If force is non-zero and damage type isn't stamina.
retaliate(user)
if(lasercolor)//To make up for the fact that lasertag bots don't hunt
@@ -120,9 +120,9 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
/mob/living/simple_animal/bot/honkbot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM)
if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM)
return
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Check for welding tool to fix #2432.
if(!W.tool_behaviour == TOOL_SCREWDRIVER && (W.force) && (!target) && (W.damtype != STAMINA) ) // Check for welding tool to fix #2432.
retaliate(user)
addtimer(CALLBACK(src, .proc/react_buzz), 5)
..()
@@ -299,12 +299,12 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params)
..()
if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
if(W.tool_behaviour == TOOL_WELDER && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
return
if(istype(W, /obj/item/clothing/head))
attempt_place_on_head(user, W)
return
if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
if(!W.tool_behaviour == TOOL_SCREWDRIVER && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
retaliate(user)
if(special_retaliate_after_attack(user))
return
@@ -40,7 +40,7 @@
bubble_icon = "machine"
initial_language_holder = /datum/language_holder/drone
mob_size = MOB_SIZE_SMALL
silicon_privileges = PRIVILEDGES_DRONE
silicon_privileges = PRIVILEGES_DRONE
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
unique_name = TRUE
@@ -160,7 +160,7 @@
..()
/mob/living/simple_animal/drone/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/screwdriver) && stat == DEAD)
if(I.tool_behaviour == TOOL_SCREWDRIVER && stat == DEAD)
try_reactivate(user)
else
..()
@@ -55,7 +55,7 @@
/mob/living/simple_animal/drone/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/screwdriver) && stat != DEAD)
if(I.tool_behaviour == TOOL_SCREWDRIVER && stat != DEAD)
if(health < maxHealth)
to_chat(user, "<span class='notice'>You start to tighten loose screws on [src]...</span>")
if(I.use_tool(src, user, 80))
@@ -66,7 +66,7 @@
else
to_chat(user, "<span class='warning'>[src]'s screws can't get any tighter!</span>")
return //This used to not exist and drones who repaired themselves also stabbed the shit out of themselves.
else if(istype(I, /obj/item/wrench) && user != src) //They aren't required to be hacked, because laws can change in other ways (i.e. admins)
else if(I.tool_behaviour == TOOL_WRENCH && user != src) //They aren't required to be hacked, because laws can change in other ways (i.e. admins)
user.visible_message("<span class='notice'>[user] starts resetting [src]...</span>", \
"<span class='notice'>You press down on [src]'s factory reset control...</span>")
if(I.use_tool(src, user, 50, volume=50))
@@ -78,6 +78,15 @@
projectiletype = /obj/item/projectile/neurotox
projectilesound = 'sound/weapons/pierce.ogg'
/mob/living/simple_animal/hostile/alien/sentinel/cube
gold_core_spawnable = NO_SPAWN
health = 220
maxHealth = 220
melee_damage_lower = 20
melee_damage_upper = 20
del_on_death = TRUE
loot = list(/obj/effect/mob_spawn/alien/corpse/humanoid/sentinel)
/mob/living/simple_animal/hostile/alien/queen
name = "alien queen"
@@ -424,7 +424,7 @@ Difficulty: Very Hard
/obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing
observer_desc = "This crystal strips and equips its targets as clowns."
possible_methods = list(ACTIVATE_MOB_BUMP, ACTIVATE_SPEECH)
possible_methods = list(ACTIVATE_TOUCH) //Because We love AOE transformations!
activation_sound = 'sound/items/bikehorn.ogg'
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
@@ -398,6 +398,14 @@ Difficulty: Medium
crusher_loot = list()
butcher_results = list(/obj/item/stack/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/bone = 30)
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/transformed //ash drake balanced around player control
name = "transformed ash drake"
desc = "A sentient being transformed into an ash drake"
mob_size = MOB_SIZE_HUMAN //prevents crusher vulnerability
move_force = MOVE_FORCE_NORMAL //stops them from destroying and unanchoring shit by walking into it
environment_smash = ENVIRONMENT_SMASH_STRUCTURES //no we dont want sentient megafauna be able to delete the entire station in a minute flat
damage_coeff = list(BRUTE = 0.7, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) //200 health but not locked to standard movespeed, needs armor befitting of a dragon
/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype)
return
@@ -413,7 +421,8 @@ Difficulty: Medium
if(L in hit_list || L == source)
continue
hit_list += L
L.adjustFireLoss(20)
L.adjustFireLoss(5)
L.adjust_fire_stacks(6)
to_chat(L, "<span class='userdanger'>You're hit by [source]'s fire breath!</span>")
// deals damage to mechs
@@ -42,6 +42,8 @@
A.GiveTarget(target)
A.friends = friends
A.faction = faction.Copy()
if(!A == /mob/living/simple_animal/hostile/poison/bees/toxin)
A.my_creator = type
ranged_cooldown = world.time + ranged_cooldown_time
/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget()
@@ -88,6 +90,7 @@
density = FALSE
del_on_death = 1
var/swarming = FALSE
var/my_creator = null
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/Initialize()
. = ..()
@@ -205,11 +208,7 @@
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H)
visible_message("<span class='warning'>[name] burrows into the flesh of [H]!</span>")
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L
if(HAS_TRAIT(H, TRAIT_DWARF)) //dwarf legions aren't just fluff!
L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(H.loc)
else
L = new(H.loc)
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = check_infest_type(H)
visible_message("<span class='warning'>[L] staggers to [L.p_their()] feet!</span>")
H.death()
H.adjustBruteLoss(1000)
@@ -217,6 +216,20 @@
H.forceMove(L)
qdel(src)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/check_infest_type(mob/living/carbon/human/human)
var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L
var/list/blacklisted_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf)
if(HAS_TRAIT(human, TRAIT_DWARF)) //dwarf legions aren't just fluff!
L = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/dwarf(human.loc)
else if(my_creator)
if(my_creator in blacklisted_types)
L = new(human.loc)
else
L = new my_creator(human.loc)
else
L = new(human.loc)
return L
//Advanced Legion is slightly tougher to kill and can raise corpses (revive other legions)
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/advanced
stat_attack = DEAD
+3 -3
View File
@@ -408,7 +408,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return
return TRUE
/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEDGES_SILICON)
/atom/proc/hasSiliconAccessInArea(mob/user, flags = PRIVILEGES_SILICON)
return user.silicon_privileges & (flags) || (user.siliconaccesstoggle && (get_area(src) in user.siliconaccessareas))
/mob/proc/toggleSiliconAccessArea(area/area)
@@ -496,7 +496,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
colored_message = "<font color=[color]>[message]</font>"
else
colored_message = "<font color='[color]'>[message]</font>"
//This makes readability a bit better for admins.
switch(message_type)
if(LOG_WHISPER)
@@ -507,7 +507,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
colored_message = "(ASAY) [colored_message]"
if(LOG_EMOTE)
colored_message = "(EMOTE) [colored_message]"
var/list/timestamped_message = list("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(src)] [loc_name(src)] (Event #[LAZYLEN(logging[smessage_type])])" = colored_message)
logging[smessage_type] += timestamped_message
+1 -4
View File
@@ -178,10 +178,7 @@
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
sleep(TRANSFORMATION_DURATION) //This entire proc CANNOT be split into two
var/list/stored_implants = list()
var/list/int_organs = list()