mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-18 19:44:58 +01:00
21b4095dfd
Upstream 04/17/2026 fixes https://github.com/Bubberstation/Bubberstation/issues/5549 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com> Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com> Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com> Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com> Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com> Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com> Co-authored-by: loganuk <fakeemail123@aol.com> Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com> Co-authored-by: Lucy <lucy@absolucy.moe> Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com> Co-authored-by: Isratosh <Isratosh@hotmail.com> Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com> Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com> Co-authored-by: Alexander V. <volas@ya.ru> Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com> Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com> Co-authored-by: Tim <timothymtorres@gmail.com> Co-authored-by: Iamgoofball <iamgoofball@gmail.com> Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com> Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com> Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com> Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com> Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com> Co-authored-by: Josh <josh.adam.powell@gmail.com> Co-authored-by: Josh Powell <josh.powell@softwire.com> Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com> Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com> Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com> Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
460 lines
16 KiB
Plaintext
460 lines
16 KiB
Plaintext
#define FORCED_SPEECH_COOLDOWN_DURATION 5 SECONDS
|
|
|
|
GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list(
|
|
/datum/strippable_item/parrot_headset,
|
|
)))
|
|
|
|
|
|
/// Parrots! Klepto bastards that imitate your speech and hoard your shit.
|
|
/mob/living/basic/parrot
|
|
name = "parrot"
|
|
desc = "The parrot squawks, \"They're a Parrot! BAWWK!\""
|
|
icon = 'icons/mob/simple/animal.dmi'
|
|
icon_state = "parrot_fly"
|
|
icon_living = "parrot_fly"
|
|
icon_dead = "parrot_dead"
|
|
density = FALSE
|
|
health = 80
|
|
maxHealth = 80
|
|
pass_flags = PASSTABLE | PASSMOB
|
|
|
|
guaranteed_butcher_results = list(/obj/item/food/cracker = 1)
|
|
melee_damage_upper = 10
|
|
melee_damage_lower = 5
|
|
|
|
response_help_continuous = "pets"
|
|
response_help_simple = "pet"
|
|
response_disarm_continuous = "gently moves aside"
|
|
response_disarm_simple = "gently move aside"
|
|
response_harm_continuous = "swats"
|
|
response_harm_simple = "swat"
|
|
combat_mode = TRUE //parrots now start "aggressive" since only player parrots will nuzzle.
|
|
attack_verb_continuous = "chomps"
|
|
attack_verb_simple = "chomp"
|
|
attack_vis_effect = ATTACK_EFFECT_BITE
|
|
friendly_verb_continuous = "grooms"
|
|
friendly_verb_simple = "groom"
|
|
mob_size = MOB_SIZE_SMALL
|
|
gold_core_spawnable = FRIENDLY_SPAWN
|
|
|
|
ai_controller = /datum/ai_controller/basic_controller/parrot
|
|
|
|
/// Icon we use while sitting
|
|
var/icon_sit = "parrot_sit"
|
|
|
|
///Headset for Poly to yell at engineers :)
|
|
var/obj/item/radio/headset/ears = null
|
|
|
|
///Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding.
|
|
var/obj/item/held_item = null
|
|
|
|
/// The blackboard key we use to store the string we're repeating
|
|
var/speech_blackboard_key = BB_PARROT_REPEAT_STRING
|
|
/// The generic probability odds we have to do a speech-related action
|
|
var/speech_probability_rate = 5
|
|
/// The generic probability odds we have to switch out our speech string
|
|
var/speech_shuffle_rate = 30
|
|
|
|
/// Contains all of the perches that parrots will generally sit on until something catches their eye.
|
|
var/static/list/desired_perches = typecacheof(list(
|
|
/obj/machinery/computer,
|
|
/obj/machinery/dna_scannernew,
|
|
/obj/machinery/nuclearbomb,
|
|
/obj/machinery/recharge_station,
|
|
/obj/machinery/smartfridge,
|
|
/obj/machinery/suit_storage_unit,
|
|
/obj/machinery/telecomms,
|
|
/obj/machinery/teleport,
|
|
/obj/structure/displaycase,
|
|
/obj/structure/filingcabinet,
|
|
/obj/structure/frame/computer,
|
|
))
|
|
///items we wont pick up
|
|
var/static/list/ignore_items = typecacheof(list(/obj/item/radio))
|
|
|
|
/// Food that Poly loves to eat (spoiler alert it's just crackers)
|
|
var/static/list/edibles = list(
|
|
/obj/item/food/cracker,
|
|
)
|
|
///list of commands we follow
|
|
var/static/list/pet_commands = list(
|
|
/datum/pet_command/idle,
|
|
/datum/pet_command/free,
|
|
/datum/pet_command/follow,
|
|
/datum/pet_command/perform_trick_sequence,
|
|
)
|
|
|
|
/// Tracks the times when we send a phrase through either being pet or attack to ensure it's not abused to flood
|
|
COOLDOWN_DECLARE(forced_speech_cooldown)
|
|
|
|
/mob/living/basic/parrot/Initialize(mapload)
|
|
. = ..()
|
|
setup_headset()
|
|
update_speech_blackboards()
|
|
ai_controller.set_blackboard_key(BB_PARROT_PERCH_TYPES, desired_perches)
|
|
ai_controller.set_blackboard_key(BB_IGNORE_ITEMS, ignore_items)
|
|
AddElement(/datum/element/pet_bonus) // parrots will listen for the signal this element sends in order to say something in response to the pat
|
|
AddElement(/datum/element/ai_retaliate)
|
|
AddElement(/datum/element/strippable, GLOB.strippable_parrot_items)
|
|
AddElement(/datum/element/simple_flying)
|
|
AddComponent(/datum/component/listen_and_repeat, desired_phrases = get_static_list_of_phrases(), blackboard_key = BB_PARROT_REPEAT_STRING)
|
|
AddComponent(/datum/component/tameable, food_types = edibles, tame_chance = 100, bonus_tame_chance = 0)
|
|
AddComponent(/datum/component/obeys_commands, pet_commands)
|
|
RegisterSignal(src, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(on_attacked)) // this means we could have a peaceful interaction, like getting a cracker
|
|
RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_injured)) // this means we got hurt and it's go time
|
|
RegisterSignal(src, COMSIG_ANIMAL_PET, PROC_REF(on_pet))
|
|
RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_item_on_signal))
|
|
ADD_TRAIT(src, TRAIT_CAN_MOUNT_HUMANS, INNATE_TRAIT)
|
|
|
|
/mob/living/basic/parrot/Destroy()
|
|
// should have cleaned these up on death, but let's be super safe in case that didn't happen
|
|
if(!QDELETED(ears))
|
|
QDEL_NULL(ears)
|
|
if(!QDELETED(held_item))
|
|
QDEL_NULL(held_item)
|
|
return ..()
|
|
|
|
/mob/living/basic/parrot/death(gibbed)
|
|
if(held_item)
|
|
held_item.forceMove(drop_location())
|
|
held_item = null
|
|
|
|
if(ears)
|
|
ears.forceMove(drop_location())
|
|
ears = null
|
|
|
|
if(!isnull(buckled))
|
|
buckled.unbuckle_mob(src, force = TRUE)
|
|
buckled = null
|
|
pixel_x = base_pixel_x
|
|
pixel_y = base_pixel_y
|
|
|
|
return ..()
|
|
|
|
/mob/living/basic/parrot/examine(mob/user)
|
|
. = ..()
|
|
. += "It appears to [isnull(held_item) ? "not be holding anything." : "be holding \a [held_item]."]"
|
|
|
|
if(stat != DEAD)
|
|
return
|
|
|
|
if(HAS_MIND_TRAIT(user, TRAIT_NAIVE))
|
|
. += pick(
|
|
"It seems tired and shagged out after a long squawk.",
|
|
"It seems to be pining for the fjords.",
|
|
"It's resting. It's a beautiful bird. Lovely plumage.",
|
|
)
|
|
else
|
|
. += pick(
|
|
"This is a late parrot.",
|
|
"This is an ex-parrot.",
|
|
"This parrot is no more.",
|
|
)
|
|
|
|
/mob/living/basic/parrot/say_dead(message)
|
|
return // this is so flarped
|
|
|
|
/mob/living/basic/parrot/get_status_tab_items()
|
|
. = ..()
|
|
. += "Held Item: [held_item]"
|
|
|
|
/mob/living/basic/parrot/radio(message, list/message_mods = list(), list/spans, language) //literally copied from human/radio(), but there's no other way to do this. at least it's better than it used to be.
|
|
. = ..()
|
|
if(. != NONE)
|
|
return
|
|
|
|
if(message_mods[MODE_HEADSET])
|
|
if(ears)
|
|
ears.talk_into(src, message, , spans, language, message_mods)
|
|
return ITALICS | REDUCE_RANGE
|
|
else if(message_mods[RADIO_EXTENSION] == MODE_DEPARTMENT)
|
|
if(ears)
|
|
ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
|
|
return ITALICS | REDUCE_RANGE
|
|
else if(message_mods[RADIO_EXTENSION] in GLOB.default_radio_channels)
|
|
if(ears)
|
|
ears.talk_into(src, message, message_mods[RADIO_EXTENSION], spans, language, message_mods)
|
|
return ITALICS | REDUCE_RANGE
|
|
|
|
return NONE
|
|
|
|
/mob/living/basic/parrot/update_icon_state()
|
|
. = ..()
|
|
if(stat == DEAD)
|
|
return
|
|
icon_state = HAS_TRAIT(src, TRAIT_PARROT_PERCHED) ? icon_sit : icon_living
|
|
|
|
/// Proc that we just use to see if we're rightclicking something for perch behavior or dropping the item we currently ahve
|
|
/mob/living/basic/parrot/resolve_right_click_attack(atom/target, list/modifiers)
|
|
if(!start_perching(target))
|
|
return SECONDARY_ATTACK_CALL_NORMAL
|
|
if(!isnull(held_item))
|
|
drop_held_item(gently = TRUE)
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/// Proc that handles sending the signal and returning a valid phrase to say. Will not do anything if we don't have a stat or if we're cliented.
|
|
/// Will return either a string or null.
|
|
/mob/living/basic/parrot/proc/get_phrase()
|
|
if(!isnull(client) || stat != CONSCIOUS)
|
|
return null
|
|
|
|
if(!COOLDOWN_FINISHED(src, forced_speech_cooldown))
|
|
return null
|
|
|
|
var/return_value = SEND_SIGNAL(src, COMSIG_NEEDS_NEW_PHRASE)
|
|
if(return_value & NO_NEW_PHRASE_AVAILABLE)
|
|
return null
|
|
|
|
COOLDOWN_START(src, forced_speech_cooldown, FORCED_SPEECH_COOLDOWN_DURATION)
|
|
return ai_controller.blackboard[BB_PARROT_REPEAT_STRING]
|
|
|
|
/// Proc that listens for when a parrot is pet so we can dispatch a voice line.
|
|
/mob/living/basic/parrot/proc/on_pet(mob/living/basic/source, mob/living/petter, modifiers)
|
|
SIGNAL_HANDLER
|
|
var/return_value = get_phrase()
|
|
if(isnull(return_value))
|
|
return
|
|
|
|
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), message = return_value, forced = "parrot oneliner on pet")
|
|
|
|
/// Proc that ascertains the type of perch we're dealing with and starts the perching process.
|
|
/// Returns TRUE if we started perching, FALSE otherwise.
|
|
/mob/living/basic/parrot/proc/start_perching(atom/target)
|
|
if(HAS_TRAIT(src, TRAIT_PARROT_PERCHED))
|
|
balloon_alert(src, "already perched!")
|
|
return FALSE
|
|
|
|
if(ishuman(target))
|
|
return perch_on_human(target)
|
|
|
|
if(!is_type_in_typecache(target, desired_perches))
|
|
return FALSE
|
|
|
|
forceMove(get_turf(target))
|
|
drop_held_item(gently = TRUE) // comfy :)
|
|
toggle_perched(perched = TRUE)
|
|
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(after_move))
|
|
return TRUE
|
|
|
|
/mob/living/basic/parrot/proc/after_move(atom/source)
|
|
SIGNAL_HANDLER
|
|
|
|
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
|
|
toggle_perched(perched = FALSE)
|
|
|
|
/// Proc that will perch us on a human. Returns TRUE if we perched, FALSE otherwise.
|
|
/mob/living/basic/parrot/proc/perch_on_human(mob/living/carbon/human/target)
|
|
if(LAZYLEN(target.buckled_mobs) >= target.max_buckled_mobs)
|
|
balloon_alert(src, "can't perch on them!")
|
|
return FALSE
|
|
|
|
forceMove(get_turf(target))
|
|
if(!target.buckle_mob(src, TRUE))
|
|
return FALSE
|
|
|
|
to_chat(src, span_notice("You sit on [target]'s shoulder."))
|
|
toggle_perched(perched = TRUE)
|
|
RegisterSignal(src, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_unbuckle))
|
|
return TRUE
|
|
|
|
/mob/living/basic/parrot/proc/on_unbuckle(mob/living/source, atom/movable/new_buckled)
|
|
SIGNAL_HANDLER
|
|
|
|
if(new_buckled)
|
|
return
|
|
UnregisterSignal(src, COMSIG_LIVING_SET_BUCKLED)
|
|
toggle_perched(perched = FALSE)
|
|
|
|
#define PERCH_SOURCE "perched"
|
|
|
|
/mob/living/basic/parrot/proc/toggle_perched(perched)
|
|
if(!perched)
|
|
REMOVE_TRAIT(src, TRAIT_PARROT_PERCHED, PERCH_SOURCE)
|
|
remove_offsets(PERCH_SOURCE)
|
|
else
|
|
ADD_TRAIT(src, TRAIT_PARROT_PERCHED, PERCH_SOURCE)
|
|
add_offsets(PERCH_SOURCE, y_add = 9)
|
|
update_appearance(UPDATE_ICON_STATE)
|
|
|
|
#undef PERCH_SOURCE
|
|
|
|
/// Master proc which will determine the intent of OUR attacks on an object and summon the relevant procs accordingly.
|
|
/// This is pretty much meant for players, AI will use the task-specific procs instead.
|
|
/mob/living/basic/parrot/early_melee_attack(atom/target, list/modifiers, ignore_cooldown)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
if(isitem(target) && steal_from_ground(target))
|
|
return BASIC_MOB_END_ATTACK_CHAIN_COOLDOWN
|
|
|
|
if(iscarbon(target) && steal_from_mob(target))
|
|
return BASIC_MOB_END_ATTACK_CHAIN_COOLDOWN
|
|
|
|
/// Picks up an item from the ground and puts it in our claws. Returns TRUE if we picked it up, FALSE otherwise.
|
|
/mob/living/basic/parrot/proc/steal_from_ground(obj/item/target)
|
|
if(!isnull(held_item))
|
|
balloon_alert(src, "already holding something!")
|
|
return FALSE
|
|
|
|
if(target.w_class > WEIGHT_CLASS_SMALL)
|
|
balloon_alert(src, "too big to pick up!")
|
|
return FALSE
|
|
|
|
pick_up_item(target)
|
|
visible_message(
|
|
span_notice("[src] grabs [held_item]!"),
|
|
span_notice("You grab [held_item]!"),
|
|
span_hear("You hear the sounds of wings flapping furiously."),
|
|
)
|
|
return TRUE
|
|
|
|
/// Looks for an item that we can snatch and puts it in our claws. Returns TRUE if we picked it up, FALSE otherwise.
|
|
/mob/living/basic/parrot/proc/steal_from_mob(mob/living/carbon/victim)
|
|
if(!isnull(held_item))
|
|
balloon_alert(src, "already holding something!")
|
|
return FALSE
|
|
|
|
for(var/obj/item/stealable in victim.held_items)
|
|
if(stealable.w_class > WEIGHT_CLASS_SMALL)
|
|
continue
|
|
|
|
if(!victim.temporarilyRemoveItemFromInventory(stealable))
|
|
continue
|
|
|
|
visible_message(
|
|
span_notice("[src] grabs [held_item] out of [victim]'s hand!"),
|
|
span_notice("You snag [held_item] out of [victim]'s hand!"),
|
|
span_hear("You hear the sounds of wings flapping furiously."),
|
|
)
|
|
pick_up_item(stealable)
|
|
return TRUE
|
|
|
|
return FALSE
|
|
|
|
/// If we're right-clicked on with a cracker, we eat the cracker.
|
|
/mob/living/basic/parrot/proc/on_attacked(mob/living/basic/source, obj/item/thing, mob/living/attacker, list/modifiers)
|
|
SIGNAL_HANDLER
|
|
if(!istype(thing, /obj/item/food/cracker)) // Poly wants a cracker
|
|
return
|
|
|
|
consume_cracker(thing) // potential clash with the tameable element so we'll leave it to that to handle qdeling the cracker.
|
|
return COMPONENT_NO_AFTERATTACK
|
|
|
|
/// Eats a cracker (or anything i guess). This would be nice to eventually fold into the basic_eating element but we do too much snowflake inventory code stuff for this to be reliable presently.
|
|
/// We don't qdel the item here, we assume the invoking proc will have handled that somehow.
|
|
/// Returns TRUE if we ate the thing.
|
|
/mob/living/basic/parrot/proc/consume_cracker(obj/item/thing)
|
|
to_chat(src, span_notice("[src] eagerly devours \the [thing]."))
|
|
if(!istype(thing, /obj/item/food/cracker))
|
|
return TRUE // we still ate it
|
|
|
|
if(health < maxHealth)
|
|
adjust_brute_loss(-10)
|
|
speech_probability_rate *= 1.27
|
|
speech_shuffle_rate += 10
|
|
update_speech_blackboards()
|
|
return TRUE
|
|
|
|
/// Handles special behavior whenever we are injured.
|
|
/mob/living/basic/parrot/proc/on_injured(mob/living/basic/source, mob/living/attacker, attack_flags)
|
|
SIGNAL_HANDLER
|
|
if(!isnull(client) || stat == CONSCIOUS)
|
|
return
|
|
|
|
drop_held_item(gently = FALSE)
|
|
|
|
var/return_value = get_phrase()
|
|
if(isnull(return_value))
|
|
return
|
|
|
|
INVOKE_ASYNC(src, TYPE_PROC_REF(/atom/movable, say), message = return_value, forced = "parrot oneliner on attack")
|
|
|
|
/// Handles picking up the item we're holding, done in its own proc because of a snowflake edge case we need to account for. No additional logic beyond that.
|
|
/// Returns TRUE if we picked it up, FALSE otherwise.
|
|
/mob/living/basic/parrot/proc/pick_up_item(obj/item/target)
|
|
if(istype(target, /obj/item/food/cracker))
|
|
consume_cracker(target)
|
|
qdel(target)
|
|
return
|
|
|
|
target.forceMove(src)
|
|
held_item = target
|
|
|
|
/// Handles dropping items we're holding. Gently is a special modifier we can use for special interactions.
|
|
/mob/living/basic/parrot/proc/drop_held_item(gently = TRUE)
|
|
if(isnull(held_item))
|
|
balloon_alert(src, "nothing to drop!")
|
|
return
|
|
|
|
if(stat != CONSCIOUS) // don't gotta do shit
|
|
return
|
|
|
|
if(!gently && isgrenade(held_item))
|
|
var/obj/item/grenade/bomb = held_item
|
|
balloon_alert(src, "bombs away!") // you'll likely die too so we can get away with the `!` here
|
|
bomb.forceMove(drop_location())
|
|
bomb.detonate()
|
|
return
|
|
|
|
balloon_alert(src, "dropped item")
|
|
held_item.forceMove(drop_location())
|
|
|
|
/mob/living/basic/parrot/Exited(atom/movable/gone, direction)
|
|
. = ..()
|
|
if(gone != held_item)
|
|
return
|
|
held_item = null
|
|
|
|
/mob/living/basic/parrot/vv_edit_var(var_name, vval)
|
|
. = ..() // give admins an easier time when it comes to fucking with poly
|
|
switch(var_name)
|
|
if(NAMEOF(src, speech_probability_rate))
|
|
update_speech_blackboards()
|
|
if(NAMEOF(src, speech_shuffle_rate))
|
|
update_speech_blackboards()
|
|
|
|
/// Updates our speech blackboards mob-side to reflect the current speech on the controller to ensure everything is synchronized.
|
|
/mob/living/basic/parrot/proc/update_speech_blackboards()
|
|
ai_controller.set_blackboard_key(BB_PARROT_REPEAT_PROBABILITY, speech_probability_rate)
|
|
ai_controller.set_blackboard_key(BB_PARROT_PHRASE_CHANGE_PROBABILITY, speech_shuffle_rate)
|
|
|
|
/// Will simply set up the headset for the parrot to use. Stub, implemented on subtypes.
|
|
/mob/living/basic/parrot/proc/setup_headset()
|
|
return
|
|
|
|
/// Gets a static list of phrases we wish to pass to the element.
|
|
/mob/living/basic/parrot/proc/get_static_list_of_phrases()
|
|
var/static/list/default_phrases = list(
|
|
"BAWWWWK george mellons griffing me!",
|
|
"Cracker?",
|
|
"Hello!",
|
|
"Hi!",
|
|
)
|
|
|
|
return default_phrases
|
|
|
|
/// Gets the available channels that this parrot has access to. Returns a list of the channels we can use.
|
|
/mob/living/basic/parrot/proc/get_available_channels()
|
|
var/list/returnable_list = list()
|
|
if(isnull(ears))
|
|
return returnable_list
|
|
|
|
var/list/headset_channels = ears.channels
|
|
for(var/channel in headset_channels)
|
|
returnable_list += GLOB.channel_tokens[channel] // will return something like ":e" or ":c" y'know
|
|
|
|
return returnable_list
|
|
|
|
/mob/living/basic/parrot/tamed(mob/living/tamer, atom/food)
|
|
. = ..()
|
|
new /obj/effect/temp_visual/heart(drop_location())
|
|
|
|
/mob/living/basic/parrot/proc/drop_item_on_signal(mob/living/user)
|
|
SIGNAL_HANDLER
|
|
|
|
drop_held_item()
|
|
return COMSIG_KB_ACTIVATED
|
|
|
|
#undef FORCED_SPEECH_COOLDOWN_DURATION
|