Merge remote-tracking branch 'citadel/master' into clickcd_experimental

This commit is contained in:
silicons
2020-07-25 23:46:27 -07:00
68 changed files with 1463 additions and 815 deletions
@@ -163,8 +163,8 @@
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
else
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
for(var/datum/wound/W in BP.wounds)
msg += "[W.get_examine_description(user)]\n"
for(var/datum/wound/W in BP.wounds)
msg += "[W.get_examine_description(user)]\n"
for(var/X in disabled)
var/obj/item/bodypart/BP = X
@@ -7,7 +7,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/id // if the game needs to manually check your race to do something not included in a proc here, it will use this
var/limbs_id //this is used if you want to use a different species limb sprites. Mainly used for angels as they look like humans.
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/default_color = "#FFFFFF" // 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/has_field_of_vision = TRUE
@@ -854,10 +854,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
var/list/colorlist = list()
var/husk = HAS_TRAIT(H, TRAIT_HUSK)
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor"]]0")
colorlist += husk ? ReadRGB("#a3a3a3") :ReadRGB("[H.dna.features["mcolor2"]]0")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]0")
colorlist += list(0,0,0, hair_alpha)
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor"]]00")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor2"]]00")
colorlist += husk ? ReadRGB("#a3a3a3") : ReadRGB("[H.dna.features["mcolor3"]]00")
colorlist += husk ? list(0, 0, 0) : list(0, 0, 0, hair_alpha)
for(var/index in 1 to colorlist.len)
colorlist[index] /= 255
@@ -1031,7 +1031,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
H.apply_overlay(BODY_FRONT_LAYER)
H.apply_overlay(HORNS_LAYER)
/*
* Equip the outfit required for life. Replaces items currently worn.
*/
@@ -5,7 +5,7 @@
default_color = "00FF00"
species_traits = list(LIPS,EYECOLOR,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR,CAN_SCAR)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None",
"insect_wings" = "None", "insect_fluff" = "None", "mam_snouts" = "None", "taur" = "None", "insect_markings" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
@@ -5,7 +5,7 @@
icon_limbs = DEFAULT_BODYPART_ICON_CITADEL
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR,CAN_SCAR)
inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BEAST
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
"mam_body_markings" = "Husky", "taur" = "None", "horns" = "None", "legs" = "Plantigrade", "meat_type" = "Mammalian")
attack_verb = "claw"
attack_sound = 'sound/weapons/slash.ogg'
@@ -4,7 +4,7 @@
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR,CAN_SCAR)
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF","tail_human" = "None", "ears" = "None", "taur" = "None", "deco_wings" = "None")
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
skinned_type = /obj/item/stack/sheet/animalhide/human
disliked_food = GROSS | RAW
@@ -7,7 +7,7 @@
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
mutantlungs = /obj/item/organ/lungs/slime
mutant_heart = /obj/item/organ/heart/slime
mutant_bodyparts = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
mutant_bodyparts = list("mcolor" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None")
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
@@ -443,7 +443,7 @@
default_color = "00FFFF"
species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
inherent_traits = list(TRAIT_TOXINLOVER)
mutant_bodyparts = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
mutant_bodyparts = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_tail" = "None", "mam_ears" = "None", "mam_body_markings" = "Plain", "mam_snouts" = "None", "taur" = "None")
say_mod = "says"
hair_color = "mutcolor"
hair_alpha = 160 //a notch brighter so it blends better.
@@ -64,7 +64,7 @@
name = "Anthromorphic Plant"
id = "podweak"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS)
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
mutant_bodyparts = list("mcolor" = "FFFFFF","mcolor2" = "FFFFFF","mcolor3" = "FFFFFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
limbs_id = "pod"
light_nutrition_gain_factor = 3
light_bruteheal = -0.2
@@ -5,7 +5,7 @@
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutant_bodyparts = list("mcolor" = "FFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
mutant_bodyparts = list("mcolor" = "FFFFFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
exotic_bloodtype = "U"
use_skintones = USE_SKINTONES_GRAYSCALE_CUSTOM
mutant_heart = /obj/item/organ/heart/vampire
+2 -2
View File
@@ -3,7 +3,7 @@
* Splits off into PhysicalLife() and BiologicalLife(). Override those instead of this.
*/
/mob/living/proc/Life(seconds, times_fired)
set waitfor = FALSE // yeah hey we're kind of on a subsystem, no sleeping will be tolerated here!
SHOULD_NOT_SLEEP(TRUE)
if(mob_transforming)
return
@@ -82,7 +82,7 @@
handle_diginvis() //AI becomes unable to see mob
if((movement_type & FLYING) && !(movement_type & FLOATING)) //TODO: Better floating
float(on = TRUE)
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
if(!loc)
return FALSE
+1 -1
View File
@@ -803,7 +803,7 @@
else
throw_alert("gravity", /obj/screen/alert/weightless)
if(!override && !is_flying())
float(!has_gravity)
INVOKE_ASYNC(src, /atom/movable.proc/float, !has_gravity)
/mob/living/float(on)
if(throwing)
@@ -102,6 +102,10 @@
var/can_salute = TRUE
var/salute_delay = 60 SECONDS
//emotes/speech stuff
var/patrol_emote = "Engaging patrol mode."
var/patrol_fail_emote = "Unable to start patrol."
/mob/living/simple_animal/bot/proc/get_mode()
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.
if(paicard)
@@ -611,7 +615,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
auto_patrol = 0
tries = 0
speak("Unable to start patrol.")
speak(patrol_fail_emote)
return
@@ -627,7 +631,7 @@ Pass a positive integer as an argument to override a bot's default speed.
return
mode = BOT_PATROL
else // no patrol target, so need a new one
speak("Engaging patrol mode.")
speak(patrol_emote)
find_patrol_target()
tries++
return
@@ -33,6 +33,20 @@
var/check_records = TRUE //Does it check security records?
var/arrest_type = FALSE //If true, don't handcuff
var/obj/item/clothing/head/bot_accessory
var/datum/beepsky_fashion/stored_fashion
//emotes (BOT is replaced with bot name, CRIMINAL with criminal name, THREAT_LEVEL with threat level)
var/death_emote = "BOT blows apart!"
var/capture_one = "BOT is trying to put zipties on CRIMINAL!"
var/capture_two = "BOT is trying to put zipties on you!"
var/infraction = "Level THREAT_LEVEL infraction alert!"
var/taunt = "<b>BOT</b> points at CRIMINAL!"
var/attack_one = "BOT has stunned CRIMINAL!"
var/attack_two = "BOT has stunned you!"
var/list/arrest_texts = list("Detaining", "Arresting")
var/arrest_emote = "ARREST_TYPE level THREAT_LEVEL scumbag CRIMINAL in LOCATION."
/mob/living/simple_animal/bot/secbot/beepsky
name = "Officer Beep O'sky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
@@ -49,6 +63,103 @@
resize = 0.8
update_transform()
/mob/living/simple_animal/bot/secbot/proc/process_emote(var/emote_type, var/atom/criminal, var/threat, var/arrest = -1, var/location)
var/emote = "The continuity of space itself collapses around [src]. You should probably report that to someone higher up."
switch(emote_type)
if("DEATH")
emote = death_emote
if("CAPTURE_ONE")
emote = capture_one
if("CAPTURE_TWO")
emote = capture_two
if("INFRACTION")
emote = infraction
if("TAUNT")
emote = taunt
if("ATTACK_ONE")
emote = attack_one
if("ATTACK_TWO")
emote = attack_two
if("ARREST")
emote = arrest_emote
//now replace pieces of the text with the information we have
if(emote_type != "TAUNT" && emote_type != "ARREST")
emote = replacetext(emote, "BOT", name)
else
emote = replacetext(emote, "BOT", "<b>[name]</b>") //needs to be bold if its a taunt or an arrest text
if(criminal)
emote = replacetext(emote, "CRIMINAL", criminal.name)
if(num2text(threat)) //because a threat of 0 will be false
emote = replacetext(emote, "THREAT_LEVEL", threat)
if(arrest > -1)
emote = replacetext(emote, "ARREST_TYPE", arrest_texts[arrest + 1])
if(location)
emote = replacetext(emote, "LOCATION", location)
return emote
/mob/living/simple_animal/bot/secbot/proc/apply_fashion(var/datum/beepsky_fashion/fashion)
stored_fashion = new fashion
if(stored_fashion.name)
name = stored_fashion.name
if(stored_fashion.desc)
desc = stored_fashion.desc
if(stored_fashion.death_emote)
death_emote = stored_fashion.death_emote
if(stored_fashion.capture_one)
capture_one = stored_fashion.capture_one
if(stored_fashion.capture_two)
capture_two = stored_fashion.capture_two
if(stored_fashion.infraction)
infraction = stored_fashion.infraction
if(stored_fashion.taunt)
taunt = stored_fashion.taunt
if(stored_fashion.attack_one)
attack_one = stored_fashion.attack_one
if(stored_fashion.attack_two)
attack_two = stored_fashion.attack_two
if(stored_fashion.patrol_emote)
patrol_emote = stored_fashion.patrol_emote
if(stored_fashion.patrol_fail_emote)
patrol_fail_emote = stored_fashion.patrol_fail_emote
if(stored_fashion.arrest_texts)
arrest_texts = stored_fashion.arrest_texts
if(stored_fashion.arrest_emote)
arrest_emote = stored_fashion.arrest_emote
regenerate_icons()
/mob/living/simple_animal/bot/secbot/proc/reset_fashion()
bot_accessory.forceMove(get_turf(src))
//reset all emotes/sounds and name/desc
name = initial(name)
desc = initial(desc)
death_emote = initial(death_emote)
capture_one = initial(capture_one)
capture_two = initial(capture_two)
infraction = initial(infraction)
taunt = initial(taunt)
attack_one = initial(attack_one)
attack_two = initial(attack_two)
arrest_texts = initial(arrest_texts)
arrest_emote = initial(arrest_emote)
patrol_emote = initial(patrol_emote)
arrest_texts = initial(arrest_texts)
arrest_emote = initial(arrest_emote)
bot_accessory = null
regenerate_icons()
/mob/living/simple_animal/bot/secbot/beepsky/explode()
var/atom/Tsec = drop_location()
@@ -178,6 +289,11 @@ Auto Patrol: []"},
retaliate(H)
if(special_retaliate_after_attack(H))
return
if(H.a_intent == INTENT_HELP && bot_accessory)
to_chat(H, "<span class='warning'>You knock [bot_accessory] off of [src]'s head!</span>")
reset_fashion()
return
return ..()
@@ -185,11 +301,48 @@ Auto Patrol: []"},
..()
if(istype(W, /obj/item/weldingtool) && 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.
retaliate(user)
if(special_retaliate_after_attack(user))
return
/mob/living/simple_animal/bot/secbot/proc/attempt_place_on_head(mob/user, obj/item/clothing/head/H)
if(user && !user.temporarilyRemoveItemFromInventory(H))
to_chat(user, "<span class='warning'>\The [H] is stuck to your hand, you cannot put it on [src]'s head!</span>")
return
if(bot_accessory)
to_chat("<span class='warning'>\[src] already has an accessory, and the laws of physics disallow him from wearing a second!</span>")
return
if(H.beepsky_fashion)
to_chat(user, "<span class='warning'>You set [H] on [src].</span>")
bot_accessory = H
H.forceMove(src)
apply_fashion(H.beepsky_fashion)
else
to_chat(user, "<span class='warning'>You set [H] on [src]'s head, but it falls off!</span>")
H.forceMove(drop_location())
/mob/living/simple_animal/bot/secbot/regenerate_icons()
..()
if(bot_accessory)
if(!stored_fashion)
stored_fashion = new bot_accessory.beepsky_fashion
if(!stored_fashion.obj_icon_state)
stored_fashion.obj_icon_state = bot_accessory.icon_state
if(!stored_fashion.obj_alpha)
stored_fashion.obj_alpha = bot_accessory.alpha
if(!stored_fashion.obj_color)
stored_fashion.obj_color = bot_accessory.color
add_overlay(stored_fashion.get_overlay())
else
if(stored_fashion)
cut_overlay(stored_fashion.get_overlay())
stored_fashion = null
/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
. = ..()
if(emagged == 2)
@@ -233,8 +386,8 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
mode = BOT_ARREST
playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
C.visible_message("<span class='danger'>[src] is trying to put zipties on [C]!</span>",\
"<span class='userdanger'>[src] is trying to put zipties on you!</span>")
C.visible_message("<span class='danger'>[process_emote("CAPTURE_ONE", C)]</span>",\
"<span class='userdanger'>[process_emote("CAPTURE_TWO", C)]</span>")
if(do_after(src, 60, FALSE, C))
attempt_handcuff(C)
@@ -249,16 +402,22 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
var/judgement_criteria = judgement_criteria()
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
icon_state = "secbot-c"
addtimer(CALLBACK(src, /atom/.proc/update_icon), 2)
var/threat = 5
if(ishuman(C))
if(stored_fashion)
stored_fashion.stun_attack(C)
if(stored_fashion.stun_sounds && !stored_fashion.ignore_sound)
playsound(src, pick(stored_fashion.stun_sounds), 50, TRUE, -1)
else
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.stuttering = 5
C.DefaultCombatKnockdown(100)
var/mob/living/carbon/human/H = C
threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
else
playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
C.DefaultCombatKnockdown(100)
C.stuttering = 5
threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
@@ -266,9 +425,9 @@ Auto Patrol: []"},
log_combat(src,C,"stunned")
if(declare_arrests)
var/area/location = get_area(src)
speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag <b>[C]</b> in [location].", radio_channel)
C.visible_message("<span class='danger'>[src] has stunned [C]!</span>",\
"<span class='userdanger'>[src] has stunned you!</span>")
speak(process_emote("ARREST", C, threat, arrest_type, location), radio_channel)
C.visible_message("<span class='danger'>[process_emote("ATTACK_ONE", C)]</span>",\
"<span class='userdanger'>[process_emote("ATTACK_TWO", C)]</span>")
/mob/living/simple_animal/bot/secbot/handle_automated_action()
if(!..())
@@ -355,7 +514,6 @@ Auto Patrol: []"},
look_for_perp()
bot_patrol()
return
/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
@@ -391,9 +549,9 @@ Auto Patrol: []"},
else if(threatlevel >= 4)
target = C
oldtarget_name = C.name
speak("Level [threatlevel] infraction alert!")
speak(process_emote("INFRACTION", target, threatlevel))
playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
visible_message("<b>[src]</b> points at [C.name]!")
visible_message(process_emote("TAUNT", target, threatlevel))
mode = BOT_HUNT
INVOKE_ASYNC(src, .proc/handle_automated_action)
break
@@ -408,7 +566,7 @@ Auto Patrol: []"},
/mob/living/simple_animal/bot/secbot/explode()
walk_to(src,0)
visible_message("<span class='boldannounce'>[src] blows apart!</span>")
visible_message("<span class='boldannounce'>[process_emote("DEATH")]</span>")
var/atom/Tsec = drop_location()
var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
@@ -81,7 +81,7 @@
/obj/structure/leaper_bubble/Initialize()
. = ..()
float(on = TRUE)
INVOKE_ASYNC(src, /atom/movable.proc/float, TRUE)
QDEL_IN(src, 100)
/obj/structure/leaper_bubble/Destroy()