diff --git a/code/__HELPERS/heap.dm b/code/__HELPERS/heap.dm
index b878969571e..50a11e71abb 100644
--- a/code/__HELPERS/heap.dm
+++ b/code/__HELPERS/heap.dm
@@ -24,7 +24,7 @@
//(i.e the max or the min dependant on the comparison function)
/datum/heap/proc/Pop()
if(!L.len)
- return 0
+ return null
. = L[1]
L[1] = L[L.len]
@@ -36,8 +36,8 @@
/datum/heap/proc/Swim(var/index)
var/parent = round(index * 0.5)
- while(parent > 0 && (call(cmp)(L[index],L[parent]) > 0))
- L.Swap(index,parent)
+ while(parent > 0 && (call(cmp)(L[index], L[parent]) > 0))
+ L.Swap(index, parent)
index = parent
parent = round(index * 0.5)
@@ -45,8 +45,8 @@
/datum/heap/proc/Sink(var/index)
var/g_child = GetGreaterChild(index)
- while(g_child > 0 && (call(cmp)(L[index],L[g_child]) < 0))
- L.Swap(index,g_child)
+ while(g_child > 0 && (call(cmp)(L[index], L[g_child]) < 0))
+ L.Swap(index, g_child)
index = g_child
g_child = GetGreaterChild(index)
@@ -59,7 +59,7 @@
if(index * 2 + 1 > L.len)
return index * 2
- if(call(cmp)(L[index * 2],L[index * 2 + 1]) < 0)
+ if(call(cmp)(L[index * 2], L[index * 2 + 1]) < 0)
return index * 2 + 1
else
return index * 2
diff --git a/code/defines/procs/AStar.dm b/code/defines/procs/AStar.dm
index 1d6fa5619e2..e2212ed8fd3 100644
--- a/code/defines/procs/AStar.dm
+++ b/code/defines/procs/AStar.dm
@@ -62,24 +62,23 @@ Actual Adjacent procs :
return b.f - a.f
//wrapper that returns an empty list if A* failed to find a path
-/proc/get_path_to(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
+/proc/get_path_to(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id = null, turf/exclude = null, simulated_only = TRUE)
var/list/path = AStar(caller, end, dist, maxnodes, maxnodedepth, mintargetdist, adjacent, id, exclude, simulated_only)
if(!path)
path = list()
return path
//the actual algorithm
-/proc/AStar(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id=null, turf/exclude=null, simulated_only = 1)
-
+/proc/AStar(caller, end, dist, maxnodes, maxnodedepth = 30, mintargetdist, adjacent = /turf/proc/reachableAdjacentTurfs, id = null, turf/exclude = null, simulated_only = TRUE)
//sanitation
var/start = get_turf(caller)
if(!start)
- return 0
+ return null
if(maxnodes)
//if start turf is farther than maxnodes from end turf, no need to do anything
if(call(start, dist)(end) > maxnodes)
- return 0
+ return null
maxnodedepth = maxnodes //no need to consider path longer than maxnodes
var/datum/heap/open = new /datum/heap(/proc/HeapPathWeightCompare) //the open list
@@ -92,7 +91,6 @@ Actual Adjacent procs :
//then run the main loop
while(!open.IsEmpty() && !path)
- {
//get the lower f node on the open list
cur = open.Pop() //get the lower f turf in the open list
closed.Add(cur.source) //and tell we've processed it
@@ -100,7 +98,7 @@ Actual Adjacent procs :
//if we only want to get near the target, check if we're close enough
var/closeenough
if(mintargetdist)
- closeenough = call(cur.source,dist)(end) <= mintargetdist
+ closeenough = call(cur.source, dist)(end) <= mintargetdist
//if too many steps, abandon that path
if(maxnodedepth && (cur.nt > maxnodedepth))
@@ -118,12 +116,13 @@ Actual Adjacent procs :
break
//get adjacents turfs using the adjacent proc, checking for access with id
- var/list/L = call(cur.source,adjacent)(caller, id, simulated_only)
- for(var/turf/T in L)
+ var/list/L = call(cur.source, adjacent)(caller, id, simulated_only)
+ for(var/t in L)
+ var/turf/T = t
if(T == exclude || (T in closed))
continue
- var/newg = cur.g + call(cur.source,dist)(T)
+ var/newg = cur.g + call(cur.source, dist)(T)
if(!T.PNode) //is not already in open list, so add it
open.Insert(new /datum/pathnode(T,cur,newg,call(T,dist)(end),cur.nt+1))
else //is already in open list, check if it's a better way from the current turf
@@ -134,18 +133,17 @@ Actual Adjacent procs :
T.PNode.nt = cur.nt + 1
open.ReSort(T.PNode)//reorder the changed element in the list
- }
-
//cleaning after us
for(var/datum/pathnode/PN in open.L)
PN.source.PNode = null
- for(var/turf/T in closed)
+ for(var/t in closed)
+ var/turf/T = t
T.PNode = null
//reverse the path to get it from start to finish
if(path)
- for(var/i = 1; i <= path.len/2; i++)
- path.Swap(i,path.len-i+1)
+ for(var/i in 1 to path.len / 2)
+ path.Swap(i, path.len - i + 1)
return path
@@ -156,10 +154,10 @@ Actual Adjacent procs :
var/turf/simulated/T
for(var/dir in GLOB.cardinal)
- T = get_step(src,dir)
+ T = get_step(src, dir)
if(!T || (simulated_only && !istype(T)))
continue
- if(!T.density && !LinkBlockedWithAccess(T,caller, ID))
+ if(!T.density && !LinkBlockedWithAccess(T, caller, ID))
L.Add(T)
return L
@@ -170,15 +168,21 @@ Actual Adjacent procs :
/turf/proc/LinkBlockedWithAccess(turf/T, caller, ID)
var/adir = get_dir(src, T)
var/rdir = get_dir(T, src)
+ var/atom/caller_atom = caller
+ if(!istype(caller_atom))
+ caller_atom = null
for(var/obj/structure/window/W in src)
if(!W.CanAStarPass(ID, adir))
- return 1
+ return TRUE
for(var/obj/machinery/door/window/W in src)
if(!W.CanAStarPass(ID, adir))
- return 1
+ return TRUE
for(var/obj/O in T)
- if(!O.CanAStarPass(ID, rdir, caller))
- return 1
+ var/pass_through = FALSE
+ if(caller_atom)
+ pass_through = caller_atom.CanAStarPassTo(ID, adir, O)
+ if(!O.CanAStarPass(ID, rdir, caller) && !pass_through)
+ return TRUE
- return 0
+ return FALSE
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 74fc4b12458..67675b24449 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1066,6 +1066,13 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
color = C
return
+/*
+ Checks whether this atom can traverse the destination object when used as source for AStar.
+ This should only be used as an override to /obj/proc/CanAStarPass. Aka don't use this unless you can't change the object's proc.
+ Returning TRUE here will override the above proc's result.
+*/
+/atom/proc/CanAStarPassTo(ID, dir, obj/destination)
+ return TRUE
/** Call this when you want to present a renaming prompt to the user.
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 5052874f5cc..138d156040a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -21,9 +21,9 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
can_be_hit = FALSE
suicidal_hands = TRUE
- var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
var/hitsound = null
var/usesound = null
+ var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
var/throwhitsound
var/w_class = WEIGHT_CLASS_NORMAL
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
@@ -115,6 +115,7 @@ GLOBAL_DATUM_INIT(fire_overlay, /image, image("icon" = 'icons/goonstation/effect
hitsound = 'sound/items/welder.ogg'
if(damtype == "brute")
hitsound = "swing_hit"
+ LAZYINITLIST(attack_verb)
if(!move_resist)
determine_move_resist()
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index e2eee66e4aa..73a08ef2bfd 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -14,45 +14,45 @@
//Only a maximum of one action and one intent should be active at any given time.
//Actions
-#define PARROT_PERCH 1 //Sitting/sleeping, not moving
-#define PARROT_SWOOP 2 //Moving towards or away from a target
-#define PARROT_WANDER 4 //Moving without a specific target in mind
+#define PARROT_PERCH (1<<0) //Sitting/sleeping, not moving
+#define PARROT_SWOOP (1<<1) //Moving towards or away from a target
+#define PARROT_WANDER (1<<2) //Moving without a specific target in mind
//Intents
-#define PARROT_STEAL 8 //Flying towards a target to steal it/from it
-#define PARROT_ATTACK 16 //Flying towards a target to attack it
-#define PARROT_RETURN 32 //Flying towards its perch
-#define PARROT_FLEE 64 //Flying away from its attacker
-
+#define PARROT_STEAL (1<<3) //Flying towards a target to steal it/from it
+#define PARROT_ATTACK (1<<4) //Flying towards a target to attack it
+#define PARROT_RETURN (1<<5) //Flying towards its perch
+#define PARROT_FLEE (1<<6) //Flying away from its attacker
/mob/living/simple_animal/parrot
- name = "\improper Parrot"
- desc = "The parrot squaks, \"It's a Parrot! BAWWK!\""
+ name = "parrot"
+ desc = "The parrot squaks, \"It's a parrot! BAWWK!\""
icon = 'icons/mob/animal.dmi'
icon_state = "parrot_fly"
icon_living = "parrot_fly"
icon_dead = "parrot_dead"
pass_flags = PASSTABLE
- can_collar = 1
+ can_collar = TRUE
var/list/clean_speak = list(
"Hi",
"Hello!",
"Cracker?",
- "BAWWWWK george mellons griffing me")
- speak_emote = list("squawks","says","yells")
- emote_hear = list("squawks","bawks")
+ "BAWWWWK george mellons griffing me"
+ )
+ speak_emote = list("squawks", "says", "yells")
+ emote_hear = list("squawks", "bawks")
emote_see = list("flutters its wings")
speak_chance = 1//1% (1 in 100) chance every tick; So about once per 150 seconds, assuming an average tick is 1.5s
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/cracker = 3)
- response_help = "pets the"
- response_disarm = "gently moves aside the"
- response_harm = "swats the"
- stop_automated_movement = 1
- universal_speak = 1
+ response_help = "pets"
+ response_disarm = "gently moves aside"
+ response_harm = "swats"
+ stop_automated_movement = TRUE
+ universal_speak = TRUE
mob_size = MOB_SIZE_SMALL
var/parrot_state = PARROT_WANDER //Hunt for a perch when created
@@ -63,8 +63,8 @@
var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower.
var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every process_ai() and at 0 the parrot will return to regular speed.
- var/list/speech_buffer = list()
- var/list/available_channels = list()
+ var/list/speech_buffer
+ var/list/available_channels
//Headset for Poly to yell at engineers :)
var/obj/item/radio/headset/ears = null
@@ -78,7 +78,7 @@
var/obj/parrot_perch = null
var/obj/desired_perches = list(/obj/structure/computerframe, /obj/structure/displaycase, \
/obj/structure/filingcabinet, /obj/machinery/teleport, \
- /obj/machinery/suit_storage_unit, /obj/machinery/clonepod, \
+ /obj/machinery/suit_storage_unit, /obj/machinery/clonepod, \
/obj/machinery/dna_scannernew, /obj/machinery/tcomms, \
/obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \
/obj/machinery/recharge_station, /obj/machinery/smartfridge, \
@@ -89,9 +89,10 @@
flying = TRUE
gold_core_spawnable = FRIENDLY_SPAWN
-
/mob/living/simple_animal/parrot/New()
..()
+ speech_buffer = list()
+ available_channels = list()
GLOB.hear_radio_list += src
if(!ears)
var/headset = pick(/obj/item/radio/headset/headset_sec, \
@@ -116,9 +117,9 @@
/mob/living/simple_animal/parrot/death(gibbed)
if(can_die())
if(held_item)
- held_item.loc = src.loc
- held_item = null
- walk(src,0)
+ custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
+ drop_held_item()
+ walk(src, 0)
return ..()
/mob/living/simple_animal/parrot/Stat()
@@ -128,7 +129,7 @@
/*
* Inventory
*/
-/mob/living/simple_animal/parrot/show_inv(mob/user as mob)
+/mob/living/simple_animal/parrot/show_inv(mob/user)
user.set_machine(src)
var/dat = {"
"}
@@ -147,9 +148,8 @@
popup.open()
/mob/living/simple_animal/parrot/Topic(href, href_list)
-
//Can the usr physically do this?
- if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
+ if(!usr.canmove || usr.stat || usr.restrained() || !usr.Adjacent(src))
return
//Is the usr's mob type able to do this?
@@ -185,7 +185,7 @@
if(!item_to_add)
return
- if( !istype(item_to_add, /obj/item/radio/headset) )
+ if(!istype(item_to_add, /obj/item/radio/headset))
to_chat(usr, "This object won't fit.")
return
@@ -221,16 +221,16 @@
else
..()
-
/*
* Attack responces
*/
//Humans, monkeys, aliens
-/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob)
+/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M)
..()
- if(client) return
- if(!stat && M.a_intent == "hurt")
+ if(client)
+ return
+ if(!stat && M.a_intent == "harm")
icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks
if(parrot_state == PARROT_PERCH)
@@ -242,12 +242,15 @@
if(M.health < 50) //Weakened mob? Fight back!
parrot_state |= PARROT_ATTACK
else
+ if(held_item)
+ custom_emote(EMOTE_VISUAL, "lets go of [held_item]!")
+
parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
- drop_held_item(0)
+ drop_held_item(FALSE)
return
//Mobs with objects
-/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
+/mob/living/simple_animal/parrot/attackby(obj/item/O, mob/user, params)
..()
if(!stat && !client && !istype(O, /obj/item/stack/medical))
if(O.force)
@@ -255,13 +258,13 @@
parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
parrot_interest = user
- parrot_state = PARROT_SWOOP | PARROT_FLEE
+ parrot_state = PARROT_SWOOP|PARROT_FLEE
icon_state = "parrot_fly"
- drop_held_item(0)
+ drop_held_item(FALSE)
return
//Bullets
-/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj)
+/mob/living/simple_animal/parrot/bullet_act(obj/item/projectile/P)
..()
if(!stat && !client)
if(parrot_state == PARROT_PERCH)
@@ -271,10 +274,9 @@
parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL!
parrot_been_shot += 5
icon_state = "parrot_fly"
- drop_held_item(0)
+ drop_held_item(FALSE)
return
-
/*
* AI - Not really intelligent, but I'm calling it AI anyway.
*/
@@ -302,10 +304,9 @@
parrot_state = PARROT_WANDER
return
- if(!isturf(src.loc) || !canmove || buckled)
+ if(!isturf(loc) || !canmove || buckled)
return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove)
-
//-----SPEECH
/* Parrot speech mimickry!
Phrases that the parrot hears in mob/living/say() get added to speach_buffer.
@@ -318,12 +319,11 @@
clean_speak += pick(speech_buffer)
speech_buffer.Cut()
-
//-----SLEEPING
if(parrot_state == PARROT_PERCH)
- if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us
+ if(parrot_perch && parrot_perch.loc != loc) //Make sure someone hasnt moved our perch on us
if(parrot_perch in view(src))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
icon_state = "parrot_fly"
return
else
@@ -333,7 +333,6 @@
if(--parrot_sleep_dur) //Zzz
return
-
else
//This way we only call the stuff below once every [sleep_max] ticks.
parrot_sleep_dur = parrot_sleep_max
@@ -344,8 +343,8 @@
//Search for item to steal
parrot_interest = search_for_item()
if(parrot_interest)
- custom_emote(1,"looks in [parrot_interest]'s direction and takes flight.")
- parrot_state = PARROT_SWOOP | PARROT_STEAL
+ custom_emote(EMOTE_VISUAL, "looks in [parrot_interest]'s direction and takes flight.")
+ parrot_state = PARROT_SWOOP|PARROT_STEAL
icon_state = "parrot_fly"
return
@@ -366,88 +365,98 @@
if(AM)
if(istype(AM, /obj/item) || isliving(AM)) //If stealable item
parrot_interest = AM
- custom_emote(1,"turns and flies towards [parrot_interest]")
- parrot_state = PARROT_SWOOP | PARROT_STEAL
+ parrot_state = PARROT_SWOOP|PARROT_STEAL
+ face_atom(AM)
+ custom_emote(EMOTE_VISUAL, "turns and flies towards [parrot_interest].")
return
else //Else it's a perch
parrot_perch = AM
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
return
return
if(parrot_interest && (parrot_interest in view(src)))
- parrot_state = PARROT_SWOOP | PARROT_STEAL
+ parrot_state = PARROT_SWOOP|PARROT_STEAL
return
if(parrot_perch && (parrot_perch in view(src)))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
return
else //Have an item but no perch? Find one!
parrot_perch = search_for_perch()
if(parrot_perch)
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
return
//-----STEALING
- else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL))
- walk(src,0)
- if(!parrot_interest || held_item)
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ else if(parrot_state == (PARROT_SWOOP|PARROT_STEAL))
+ walk(src, 0)
+
+ if(!parrot_interest || held_item || !(parrot_interest in view(src)))
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
return
- if(!(parrot_interest in view(src)))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-
- if(in_range(src, parrot_interest))
-
+ if(Adjacent(parrot_interest))
if(isliving(parrot_interest))
steal_from_mob()
-
else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch
if(!parrot_perch || parrot_interest.loc != parrot_perch.loc)
- held_item = parrot_interest
- parrot_interest.loc = src
- visible_message("[src] grabs the [held_item]!", "You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
+ try_grab_item(parrot_interest)
+ visible_message("[src] grabs [held_item]!", "You grab [held_item]!", "You hear the sounds of wings flapping furiously.")
parrot_interest = null
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
return
- walk_to(src, parrot_interest, 1, parrot_speed)
+ var/list/path_to_take = get_path_to(src, get_turf(parrot_interest), /turf/proc/Distance_cardinal)
+ if(length(path_to_take) <= 1) // The target is below us
+ parrot_interest = null
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
+ return
+
+ walk_to(src, path_to_take[2], 0, parrot_speed)
return
//-----RETURNING TO PERCH
- else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN))
+ else if(parrot_state == (PARROT_SWOOP|PARROT_RETURN))
walk(src, 0)
+
if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else.
parrot_perch = null
parrot_state = PARROT_WANDER
return
- if(in_range(src, parrot_perch))
- src.loc = parrot_perch.loc
+ if(Adjacent(parrot_perch))
+ forceMove(parrot_perch.loc)
drop_held_item()
parrot_state = PARROT_PERCH
icon_state = "parrot_sit"
return
- walk_to(src, parrot_perch, 1, parrot_speed)
+ var/list/path_to_take = get_path_to(src, get_turf(parrot_perch), /turf/proc/Distance_cardinal)
+ if(length(path_to_take) <= 1) // The target is below us
+ parrot_perch = null
+ parrot_state = PARROT_WANDER
+ return
+
+ walk_to(src, path_to_take[2], 0, parrot_speed)
return
//-----FLEEING
- else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE))
- walk(src,0)
- if(!parrot_interest || !isliving(parrot_interest)) //Sanity
- parrot_state = PARROT_WANDER
+ else if(parrot_state == (PARROT_SWOOP|PARROT_FLEE))
+ walk(src, 0)
- walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot)
+ if(!parrot_interest || !isliving(parrot_interest) || !Adjacent(parrot_interest)) //Sanity
+ parrot_state = PARROT_WANDER
+ parrot_interest = null
+ return
+
+ walk_away(src, parrot_interest, 0, parrot_speed - parrot_been_shot)
parrot_been_shot--
return
//-----ATTACKING
- else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK))
-
+ else if(parrot_state == (PARROT_SWOOP|PARROT_ATTACK))
//If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander
if(!parrot_interest || !isliving(parrot_interest))
parrot_interest = null
@@ -457,8 +466,7 @@
var/mob/living/L = parrot_interest
//If the mob is close enough to interact with
- if(in_range(src, parrot_interest))
-
+ if(Adjacent(parrot_interest))
//If the mob we've been chasing/attacking dies or falls into crit, check for loot!
if(L.stat)
parrot_interest = null
@@ -466,34 +474,34 @@
held_item = steal_from_ground()
if(!held_item)
held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances.
+ update_held_icon()
if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home
- parrot_state = PARROT_SWOOP | PARROT_RETURN
+ parrot_state = PARROT_SWOOP|PARROT_RETURN
else
parrot_state = PARROT_WANDER
return
//Time for the hurt to begin!
- var/damage = rand(5,10)
+ var/damage = rand(5, 10)
if(ishuman(parrot_interest))
var/mob/living/carbon/human/H = parrot_interest
var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone)))
- H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp = 1)
- custom_emote(1, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
-
+ H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp = TRUE)
+ custom_emote(EMOTE_VISUAL, pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
else
L.adjustBruteLoss(damage)
- custom_emote(1, pick("pecks at [L].", "claws [L]."))
+ custom_emote(EMOTE_VISUAL, pick("pecks at [L].", "claws [L]."))
return
-
//Otherwise, fly towards the mob!
else
+ // No AStar here because the parrot is pissed and isn't thinking rationally.
walk_to(src, parrot_interest, 1, parrot_speed)
return
//-----STATE MISHAP
else //This should not happen. If it does lets reset everything and try again
- walk(src,0)
+ walk(src, 0)
parrot_interest = null
parrot_perch = null
drop_held_item()
@@ -516,6 +524,10 @@
if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src)
continue
+ // Can we find a path to it?
+ if(loc != AM.loc && !length(get_path_to(src, get_turf(AM), /turf/proc/Distance_cardinal)))
+ continue
+
if(istype(AM, /obj/item))
var/obj/item/I = AM
if(I.w_class < WEIGHT_CLASS_SMALL)
@@ -529,6 +541,10 @@
/mob/living/simple_animal/parrot/proc/search_for_perch()
for(var/obj/O in view(src))
+ // Can we find a path to it?
+ if(loc != O.loc && !length(get_path_to(src, get_turf(O), /turf/proc/Distance_cardinal)))
+ continue
+
for(var/path in desired_perches)
if(istype(O, path))
return O
@@ -537,6 +553,10 @@
//This proc was made to save on doing two 'in view' loops seperatly
/mob/living/simple_animal/parrot/proc/search_for_perch_and_item()
for(var/atom/movable/AM in view(src))
+ // Can we find a path to it?
+ if(loc != AM.loc && !length(get_path_to(src, get_turf(AM), /turf/proc/Distance_cardinal)))
+ continue
+
for(var/perch_path in desired_perches)
if(istype(AM, perch_path))
return AM
@@ -556,7 +576,6 @@
return C
return null
-
/*
* Verbs - These are actually procs, but can be used as verbs by player-controlled parrots.
*/
@@ -569,20 +588,18 @@
return -1
if(held_item)
- to_chat(src, "You are already holding the [held_item]")
+ to_chat(src, "You are already holding [held_item]")
return 1
- for(var/obj/item/I in view(1,src))
+ for(var/obj/item/I in view(1, src))
//Make sure we're not already holding it and it's small enough
if(I.loc != src && I.w_class <= WEIGHT_CLASS_SMALL)
-
//If we have a perch and the item is sitting on it, continue
if(!client && parrot_perch && I.loc == parrot_perch.loc)
continue
- held_item = I
- I.loc = src
- visible_message("[src] grabs the [held_item]!", "You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
+ try_grab_item(I)
+ visible_message("[src] grabs [held_item]!", "You grab [held_item]!", "You hear the sounds of wings flapping furiously.")
return held_item
to_chat(src, "There is nothing of interest to take.")
@@ -597,23 +614,21 @@
return -1
if(held_item)
- to_chat(src, "You are already holding the [held_item]")
+ to_chat(src, "You are already holding [held_item]")
return 1
var/obj/item/stolen_item = null
- for(var/mob/living/carbon/C in view(1,src))
+ for(var/mob/living/carbon/C in view(1, src))
if(C.l_hand && C.l_hand.w_class <= WEIGHT_CLASS_SMALL)
stolen_item = C.l_hand
if(C.r_hand && C.r_hand.w_class <= WEIGHT_CLASS_SMALL)
stolen_item = C.r_hand
- if(stolen_item)
- C.unEquip(stolen_item)
- held_item = stolen_item
- stolen_item.loc = src
- visible_message("[src] grabs the [held_item] out of [C]'s hand!", "You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.")
+ if(stolen_item && C.unEquip(stolen_item))
+ try_grab_item(stolen_item)
+ visible_message("[src] grabs [held_item] out of [C]'s hand!", "You snag [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.")
return held_item
to_chat(src, "There is nothing of interest to take.")
@@ -627,11 +642,10 @@
if(stat)
return
- src.drop_held_item()
-
+ drop_held_item()
return
-/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1)
+/mob/living/simple_animal/parrot/proc/drop_held_item(drop_gently = TRUE)
set name = "Drop held item"
set category = "Parrot"
set desc = "Drop the item you're holding."
@@ -646,16 +660,18 @@
if(!drop_gently)
if(istype(held_item, /obj/item/grenade))
var/obj/item/grenade/G = held_item
- G.loc = src.loc
+ G.forceMove(loc)
G.prime()
- to_chat(src, "You let go of the [held_item]!")
+ to_chat(src, "You let go of [held_item]!")
held_item = null
+ update_held_icon()
return 1
- to_chat(src, "You drop the [held_item].")
+ to_chat(src, "You drop [held_item].")
- held_item.loc = src.loc
+ held_item.forceMove(loc)
held_item = null
+ update_held_icon()
return 1
/mob/living/simple_animal/parrot/proc/perch_player()
@@ -667,15 +683,30 @@
return
if(icon_state == "parrot_fly")
- for(var/atom/movable/AM in view(src,1))
+ for(var/atom/movable/AM in view(src, 1))
for(var/perch_path in desired_perches)
if(istype(AM, perch_path))
- src.loc = AM.loc
+ forceMove(AM.loc)
icon_state = "parrot_sit"
return
to_chat(src, "There is no perch nearby to sit on.")
return
+/**
+ * Attempts to pick up an adjacent item
+ *
+ * Arguments:
+ * * I - The item to try and pick up
+ */
+/mob/living/simple_animal/parrot/proc/try_grab_item(obj/I)
+ if(!Adjacent(I))
+ return
+ if(held_item)
+ drop_held_item()
+ held_item = I
+ update_held_icon()
+ I.forceMove(src)
+
/*
* Sub-types
*/
@@ -706,7 +737,7 @@
available_channels = list(":e")
..()
-/mob/living/simple_animal/parrot/handle_message_mode(var/message_mode, list/message_pieces, var/verb, var/used_radios)
+/mob/living/simple_animal/parrot/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(message_mode && istype(ears))
ears.talk_into(src, message_pieces, message_mode, verb)
used_radios += ears
@@ -716,15 +747,30 @@
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
..()
-
-
-/mob/living/simple_animal/parrot/hear_radio(list/message_pieces, var/verb="says", var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/atom/follow_target)
+/mob/living/simple_animal/parrot/hear_radio(list/message_pieces, verb = "says", part_a, part_b, mob/speaker = null, hard_to_hear = 0, atom/follow_target)
if(speaker != src && prob(50))
parrot_hear(html_decode(multilingual_to_message(message_pieces)))
..()
-
-/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="")
+/mob/living/simple_animal/parrot/proc/parrot_hear(message)
if(!message || stat)
return
speech_buffer.Add(message)
+
+/mob/living/simple_animal/parrot/proc/update_held_icon()
+ underlays.Cut()
+
+ if(!held_item)
+ return
+
+ var/matrix/m180 = matrix(held_item.transform)
+ m180.Turn(180)
+
+ var/held_item_icon = image(held_item, pixel_y = -8)
+ animate(held_item_icon, transform = m180)
+ underlays += held_item_icon
+
+/mob/living/simple_animal/parrot/CanAStarPassTo(ID, dir, obj/destination)
+ for(var/path in desired_perches)
+ if(istype(destination, path))
+ return TRUE