Files
Bubberstation/code/modules/mob/interactive.dm
phil235 11ca987acb Merges Pull and Grab into a single functionality. Pulling someone is now the same as a passive grab. You can start pulling someone with ctrlclick or by using the grab intent with empty hand. Using the grab intent again on the pulled person tries to grab them aggressively, then neck grab, then kill grab.
Two mobs can no longer pull the same mob at the same time. Pulling someone break any other pull/grab from other mob on that person.

The grab item is gone entirely.

You can now only grab one mob at a time, instead of two (one for each hand).

Being aggressively grabbed or more now counts as being restrained (like handcuffed). A neck grab or more makes you lie down and prevents you from getting up until the grab is broken.

Fixes movement when moving with a grabbed person.
Fixes movement when moving a pulled person around you diagonally.
Fixes neckgrab moving the victim on your turf even if the turf is dense.
2016-05-24 01:28:04 +02:00

1583 lines
48 KiB
Plaintext

/*
NPC VAR EXPLANATIONS (for modules and other things)
doing = their current action, INTERACTING, TRAVEL or FIGHTING
interest = how interested the NPC is in the situation, if they are idle, this drops
timeout = this is internal
TARGET = their current target
LAST_TARGET = their last target
nearby = a list of nearby mobs
best_force = the highest force object, used for checking when to swap items
retal = this is internal
retal_target = this is internal
update_hands = this is a bool (1/0) to determine if the NPC should update what is in his hands
MYID = their ID card
MYPDA = their PDA
main_hand = what is in their "main" hand (chosen from left > right)
TRAITS = the traits assigned to this npc
mymjob = the job assigned to the npc
robustness = the chance for the npc to hit something
smartness = the inverse chance for an npc to do stupid things
attitude = the chance for an npc to do rude or mean things
slyness = the chance for an npc to do naughty things ie thieving
functions = the list of procs that the npc will use for modules
graytide = shitmin var to make them go psycho
*/
#define NPC_SPEAK_FILE "npc_chatter.json"
/mob/living/carbon/human/interactive
name = "interactive station member"
var/doing = 0
var/interest = 10
var/maxInterest = 10
var/timeout = 0
var/inactivity_period = 0
var/TARGET = null
var/LAST_TARGET = null
var/list/nearby = list()
var/best_force = 0
var/retal = 0
var/mob/retal_target = null
var/update_hands = 0
var/list/blacklistItems = list() // items we should be ignoring
var/maxStepsTick = 6 // step as many times as we can per frame
//Job and mind data
var/obj/item/weapon/card/id/MYID
var/obj/item/weapon/card/id/RPID // the "real" idea they use
var/obj/item/device/pda/MYPDA
var/obj/item/main_hand
var/obj/item/other_hand
var/TRAITS = 0
var/obj/item/weapon/card/id/Path_ID
var/datum/job/myjob
var/list/myPath = list()
faction = list("synth")
//trait vars
var/robustness = 50
var/smartness = 50
var/attitude = 50
var/slyness = 50
var/graytide = 0
var/list/favoured_types = list() // allow a mob to favour a type, and hold onto them
var/chattyness = CHANCE_TALK
var/targetInterestShift = 5 // how much a good action should "reward" the npc
//modules
var/list/functions = list("nearbyscan","combat","shitcurity","chatter")
var/restrictedJob = 0
var/shouldUseDynamicProc = 0 // switch to make the AI control it's own proccessing
var/alternateProcessing = 0
var/forceProcess = 0
var/processTime = 10
var/list/knownStrings = list()
//snpc traitor variables
var/isTraitor = 0
var/traitorTarget
var/traitorScale = 0 // our ability as a traitor
var/traitorType = 0
/// SNPC voice handling
/mob/living/carbon/human/interactive/proc/loadVoice()
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
S["knownStrings"] >> knownStrings
if(isnull(knownStrings))
knownStrings = list()
/mob/living/carbon/human/interactive/proc/saveVoice()
var/savefile/S = new /savefile("data/npc_saves/snpc.sav")
S["knownStrings"] << knownStrings
//botPool funcs
/mob/living/carbon/human/interactive/proc/takeDelegate(mob/living/carbon/human/interactive/from,doReset=TRUE)
eye_color = "red"
if(from == src)
return FALSE
TARGET = from.TARGET
LAST_TARGET = from.LAST_TARGET
retal = from.retal
retal_target = from.retal_target
doing = from.doing
//
timeout = 0
inactivity_period = 0
interest = maxInterest
//
update_icons()
if(doReset)
from.TARGET = null
from.LAST_TARGET = null
from.retal = 0
from.retal_target = null
from.doing = 0
return TRUE
//end pool funcs
/mob/living/carbon/human/interactive/proc/random()
//this is here because this has no client/prefs/brain whatever.
age = rand(AGE_MIN,AGE_MAX)
//job handling
myjob = new/datum/job/assistant()
job = myjob.title
myjob.equip(src)
myjob.apply_fingerprints(src)
/mob/living/carbon/human/interactive/attacked_by(obj/item/I, mob/living/user, def_zone)
..()
retal = 1
retal_target = user
/mob/living/carbon/human/interactive/bullet_act(var/obj/item/projectile/P)
var/potentialAssault = locate(/mob/living) in view(2,P.starting)
if(potentialAssault)
retal = 1
retal_target = potentialAssault
..()
/client/proc/resetSNPC(var/mob/A in SSnpc.botPool_l)
set name = "Reset SNPC"
set desc = "Reset the SNPC"
set category = "Debug"
if(!holder)
return
if(A)
if(!istype(A,/mob/living/carbon/human/interactive))
return
var/mob/living/carbon/human/interactive/T = A
if(T)
T.timeout = 100
T.retal = 0
T.doing = 0
/client/proc/toggleSNPC(var/mob/A in SSnpc.botPool_l)
set name = "Toggle SNPC Proccessing Mode"
set desc = "Toggle SNPC Proccessing Mode"
set category = "Debug"
if(!holder)
return
if(A)
if(!istype(A,/mob/living/carbon/human/interactive))
return
var/mob/living/carbon/human/interactive/T = A
if(T)
T.alternateProcessing = !T.alternateProcessing
T.forceProcess = 1
usr << "[T]'s processing has been switched to [T.alternateProcessing ? "High Profile" : "Low Profile"]"
/client/proc/customiseSNPC(var/mob/A in SSnpc.botPool_l)
set name = "Customize SNPC"
set desc = "Customise the SNPC"
set category = "Debug"
if(!holder)
return
if(A)
if(!istype(A,/mob/living/carbon/human/interactive))
return
var/mob/living/carbon/human/interactive/T = A
var/cjob = input("Choose Job") as null|anything in SSjob.occupations
if(cjob)
T.myjob = cjob
T.job = T.myjob.title
for(var/obj/item/W in T)
qdel(W)
T.myjob.equip(T)
T.myjob.apply_fingerprints(T)
T.doSetup()
var/shouldDoppel = input("Do you want the SNPC to disguise themself as a crewmember?") as null|anything in list("Yes","No")
if(shouldDoppel)
if(shouldDoppel == "Yes")
var/list/validchoices = list()
for(var/mob/living/carbon/human/M in mob_list)
validchoices += M
var/mob/living/carbon/human/chosen = input("Which crewmember?") as null|anything in validchoices
if(chosen)
var/datum/dna/toDoppel = chosen.dna
T.real_name = toDoppel.real_name
toDoppel.transfer_identity(T, transfer_SE=1)
T.updateappearance(mutcolor_update=1)
T.domutcheck()
var/doTrait = input("Do you want the SNPC to be a traitor?") as null|anything in list("Yes","No")
if(doTrait)
if(doTrait == "Yes")
var/list/tType = list("Brute" = SNPC_BRUTE, "Stealth" = SNPC_STEALTH, "Martyr" = SNPC_MARTYR, "Psycho" = SNPC_PSYCHO)
var/cType = input("Choose the traitor personality.") as null|anything in tType
if(cType)
var/value = tType[cType]
T.makeTraitor(value)
var/doTele = input("Place the SNPC in their department?") as null|anything in list("Yes","No")
if(doTele)
if(doTele == "Yes")
T.loc = pick(get_area_turfs(T.job2area(T.myjob)))
/mob/living/carbon/human/interactive/proc/doSetup()
Path_ID = new /obj/item/weapon/card/id(src)
var/datum/job/captain/C = new/datum/job/captain
Path_ID.access = C.get_access()
MYID = new(src)
MYID.name = "[src.real_name]'s ID Card ([myjob.title])"
MYID.assignment = "[myjob.title]"
MYID.registered_name = src.real_name
MYID.access = Path_ID.access // Automatons have strange powers... strange indeed
RPID = new(src)
RPID.name = "[src.real_name]'s ID Card ([myjob.title])"
RPID.assignment = "[myjob.title]"
RPID.registered_name = src.real_name
RPID.access = myjob.get_access()
equip_to_slot_or_del(MYID, slot_wear_id)
MYPDA = new(src)
MYPDA.owner = real_name
MYPDA.ownjob = "Crew"
MYPDA.name = "PDA-[real_name] ([myjob.title])"
equip_to_slot_or_del(MYPDA, slot_belt)
zone_selected = "chest"
//arms
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/4))
BP.change_bodypart_status(ORGAN_ROBOTIC)
update_icons()
update_damage_overlays(0)
hand = 0
functions = list("nearbyscan","combat","shitcurity","chatter") // stop customize adding multiple copies of a function
//job specific favours
switch(myjob.title)
if("Assistant")
favoured_types = list(/obj/item/clothing, /obj/item/weapon)
if("Captain","Head of Personnel")
favoured_types = list(/obj/item/clothing, /obj/item/weapon/stamp/captain,/obj/item/weapon/disk/nuclear)
if("Cook")
favoured_types = list(/obj/item/weapon/reagent_containers/food, /obj/item/weapon/kitchen)
functions += "souschef"
restrictedJob = 1
if("Bartender")
favoured_types = list(/obj/item/weapon/reagent_containers/food, /obj/item/weapon/kitchen)
functions += "bartend"
restrictedJob = 1
if("Station Engineer","Chief Engineer","Atmospheric Technician")
favoured_types = list(/obj/item/stack, /obj/item/weapon, /obj/item/clothing)
if("Chief Medical Officer","Medical Doctor","Chemist","Virologist","Geneticist")
favoured_types = list(/obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/storage/firstaid, /obj/item/stack/medical, /obj/item/weapon/reagent_containers/syringe)
functions += "healpeople"
if("Research Director","Scientist","Roboticist")
favoured_types = list(/obj/item/weapon/reagent_containers/glass/beaker, /obj/item/stack, /obj/item/weapon/reagent_containers)
if("Head of Security","Warden","Security Officer","Detective")
favoured_types = list(/obj/item/clothing, /obj/item/weapon, /obj/item/weapon/restraints)
if("Janitor")
favoured_types = list(/obj/item/weapon/mop, /obj/item/weapon/reagent_containers/glass/bucket, /obj/item/weapon/reagent_containers/spray/cleaner, /obj/effect/decal/cleanable)
functions += "dojanitor"
if("Clown")
favoured_types = list(/obj/item/weapon/soap, /obj/item/weapon/reagent_containers/food/snacks/grown/banana,/obj/item/weapon/grown/bananapeel)
functions += "clowning"
if("Botanist")
favoured_types = list(/obj/machinery/hydroponics, /obj/item/weapon/reagent_containers, /obj/item/weapon)
functions += "botany"
restrictedJob = 1
else
favoured_types = list(/obj/item/clothing)
if(TRAITS & TRAIT_ROBUST)
robustness = 75
else if(TRAITS & TRAIT_UNROBUST)
robustness = 25
//modifiers are prob chances, lower = smarter
if(TRAITS & TRAIT_SMART)
smartness = 75
else if(TRAITS & TRAIT_DUMB)
disabilities |= CLUMSY
smartness = 25
if(TRAITS & TRAIT_MEAN)
attitude = 75
else if(TRAITS & TRAIT_FRIENDLY)
attitude = 1
if(TRAITS & TRAIT_THIEVING)
slyness = 75
/mob/living/carbon/human/interactive/proc/makeTraitor(var/inPers)
isTraitor = 1
traitorScale = (slyness + smartness) + rand(-10,10)
traitorType = inPers
switch(traitorType)
if(SNPC_BRUTE) // SMASH KILL RAAARGH
traitorTarget = pick(mob_list)
if(SNPC_STEALTH) // Shhh we is sneekies
var/A = pick(typesof(/datum/objective_item/steal) - /datum/objective_item/steal)
var/datum/objective_item/steal/S = new A
traitorTarget = locate(S.targetitem) in world
if(SNPC_MARTYR) // MY LIFE FOR SPESZUL
var/targetType = pick(/obj/structure/particle_accelerator,/obj/machinery/gravity_generator/main,/obj/machinery/power/smes)
traitorTarget = locate(targetType) in world
if(SNPC_PSYCHO) // YOU'RE LIKE A FLESH BICYLE AND I WANT TO DISMANTLE YOU
traitorTarget = null
functions += "traitor"
faction -= "neutral"
faction += "hostile"
/mob/living/carbon/human/interactive/New()
..()
src.set_species(/datum/species/synth)
var/datum/species/synth/mSyn = dna.species
mSyn.assume_disguise(new/datum/species/human,src)
random()
doSetup()
SSnpc.insertBot(src)
loadVoice()
// a little bit of variation to make individuals more unique
robustness += rand(-10,10)
smartness += rand(-10,10)
attitude += rand(-10,10)
slyness += rand(-10,10)
doProcess()
/mob/living/carbon/human/interactive/proc/retalTarget(var/target)
var/mob/living/carbon/human/M = target
if(target)
if(health > 0)
if(M.a_intent == "help")
chatter()
if(M.a_intent == "harm")
retal = 1
retal_target = target
//Retaliation clauses
/mob/living/carbon/human/interactive/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
..(AM,skipcatch,hitpush,blocked)
var/mob/living/carbon/C = locate(/mob/living/carbon) in view(MIN_RANGE_FIND,src)
if(C)
retalTarget(C)
/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P, def_zone)
..(P,def_zone)
retalTarget(P.firer)
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
..(M)
retalTarget(M)
/mob/living/carbon/human/interactive/show_inv(mob/user)
..(user)
retalTarget(user)
/mob/living/carbon/human/interactive/can_inject(mob/user, error_msg, target_zone, var/penetrate_thick = 0)
..(user,error_msg,target_zone,penetrate_thick)
retalTarget(user)
//THESE EXIST FOR DEBUGGING OF THE DOING/INTEREST SYSTEM EASILY
/mob/living/carbon/human/interactive/proc/doing2string(doin)
var/toReturn = ""
if(!doin)
toReturn = "not doing anything"
if(doin & INTERACTING)
toReturn += "interacting with something, "
if(doin & FIGHTING)
toReturn += "engaging in combat, "
if(doin & TRAVEL)
toReturn += "and going somewhere"
return toReturn
/mob/living/carbon/human/interactive/proc/interest2string(inter)
var/toReturn = "Flatlined"
if(inter >= 0 && inter <= 25)
toReturn = "Very Bored"
if(inter >= 26 && inter <= 50)
toReturn = "Bored"
if(inter >= 51 && inter <= 75)
toReturn = "Content"
if(inter >= 76)
toReturn = "Excited"
return toReturn
//END DEBUG
/mob/living/carbon/human/interactive/proc/IsDeadOrIncap(checkDead = TRUE)
if(!canmove)
return 1
if(health <= 0 && checkDead)
return 1
if(restrained())
return 1
if(paralysis)
return 1
if(stunned)
return 1
if(stat)
return 1
if(inactivity_period > 0)
return 1
return 0
/mob/living/carbon/human/interactive/proc/enforce_hands()
if(main_hand)
if(main_hand.loc != src)
main_hand = null
if(other_hand)
if(other_hand.loc != src)
other_hand = null
if(hand)
if(!l_hand)
main_hand = null
if(r_hand)
swap_hands()
else
if(!r_hand)
main_hand = null
if(l_hand)
swap_hands()
/mob/living/carbon/human/interactive/proc/swap_hands()
hand = !hand
var/obj/item/T = other_hand
main_hand = other_hand
other_hand = T
update_hands = 1
/mob/living/carbon/human/interactive/proc/take_to_slot(obj/item/G, var/hands=0)
var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_l_hand,"right hand" = slot_r_hand)
if(hands)
slots = list ("left hand" = slot_l_hand,"right hand" = slot_r_hand)
G.loc = src
if(G.force && G.force > best_force)
best_force = G.force
equip_in_one_of_slots(G, slots)
update_hands = 1
/mob/living/carbon/human/interactive/proc/insert_into_backpack()
var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_l_hand,"right hand" = slot_r_hand)
var/obj/item/I = get_item_by_slot(pick(slots))
var/obj/item/weapon/storage/BP = get_item_by_slot(slot_back)
if(back && BP && I)
if(BP.can_be_inserted(I,0))
BP.handle_item_insertion(I,0)
else
unEquip(I,TRUE)
update_hands = 1
/mob/living/carbon/human/interactive/proc/targetRange(towhere)
return get_dist(get_turf(towhere), get_turf(src))
/mob/living/carbon/human/interactive/Life()
..()
if(ticker.current_state == GAME_STATE_FINISHED)
saveVoice()
if(!alternateProcessing || forceProcess)
doProcess()
/mob/living/carbon/human/interactive/death()
saveVoice()
..()
/mob/living/carbon/human/interactive/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
if(speaker != src)
knownStrings |= html_decode(raw_message)
..()
/mob/living/carbon/human/interactive/proc/doProcess()
forceProcess = 0
if(shouldUseDynamicProc)
var/isSeen = 0
for(var/mob/living/carbon/human/A in orange(12,src))
if(A.client)
isSeen = 1
alternateProcessing = isSeen
if(alternateProcessing)
forceProcess = 1
if(IsDeadOrIncap())
walk(src,0)
return
//---------------------------
//---- interest flow control
if(interest < 0 || inactivity_period < 0)
if(interest < 0)
interest = 0
if(inactivity_period < 0)
inactivity_period = 0
if(interest > maxInterest)
interest = maxInterest
//---------------------------
//VIEW FUNCTIONS
//doorscan is now integrated into life and runs before all other procs
spawn(0)
for(var/dir in alldirs)
var/turf/T = get_step(src,dir)
if(T)
for(var/obj/machinery/door/D in T.contents)
if(!istype(D,/obj/machinery/door/poddoor) && D.density)
spawn(0)
if(istype(D,/obj/machinery/door/airlock))
var/obj/machinery/door/airlock/AL = D
if(!AL.CanAStarPass(RPID)) // only crack open doors we can't get through
AL.panel_open = 1
AL.update_icon()
AL.shock(src,(100 - smartness)/2)
sleep(5)
AL.unbolt()
if(!AL.wires.is_cut(WIRE_BOLTS))
AL.wires.cut(WIRE_BOLTS)
if(!AL.wires.is_cut(WIRE_POWER1))
AL.wires.cut(WIRE_POWER1)
if(!AL.wires.is_cut(WIRE_POWER2))
AL.wires.cut(WIRE_POWER2)
sleep(5)
AL.panel_open = 0
AL.update_icon()
D.open()
if(update_hands)
if(l_hand || r_hand)
if(l_hand)
hand = 1
main_hand = l_hand
if(r_hand)
other_hand = r_hand
else if(r_hand)
hand = 0
main_hand = r_hand
if(l_hand) //this technically shouldnt occur, but its a redundancy
other_hand = l_hand
update_icons()
update_hands = 0
if(pulledby)
if(Adjacent(pulledby))
a_intent = "disarm"
pulledby.attack_hand(src)
inactivity_period = 10
if(buckled)
resist()
inactivity_period = 10
//proc functions
for(var/Proc in functions)
if(!IsDeadOrIncap())
callfunction(Proc)
//target interaction stays hardcoded
if(TARGET) // don't use blacklisted items
if(TARGET in blacklistItems)
TARGET = null
if((TARGET && Adjacent(TARGET)))
doing |= INTERACTING
//--------DOORS
if(istype(TARGET, /obj/machinery/door))
var/obj/machinery/door/D = TARGET
if(D.check_access(MYID) && !istype(D,/obj/machinery/door/poddoor))
D.open()
sleep(15)
var/turf/T = get_step(get_step(D.loc,dir),dir) //recursion yo
tryWalk(T)
//THIEVING SKILLS
if(!TARGET in blacklistItems)
insert_into_backpack() // dump random item into backpack to make space
//---------ITEMS
if(istype(TARGET, /obj/item))
if(istype(TARGET, /obj/item/weapon))
var/obj/item/weapon/W = TARGET
if(W.force >= best_force || prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/2))
if(!l_hand || !r_hand)
put_in_hands(W)
else
insert_into_backpack()
else
if(!l_hand || !r_hand)
put_in_hands(TARGET)
else
insert_into_backpack()
//---------FASHION
if(istype(TARGET,/obj/item/clothing))
var/obj/item/clothing/C = TARGET
drop_item()
spawn(5)
take_to_slot(C,1)
if(!equip_to_appropriate_slot(C))
var/obj/item/I = get_item_by_slot(C)
unEquip(I)
spawn(5)
equip_to_appropriate_slot(C)
update_hands = 1
if(MYPDA in src.loc || MYID in src.loc)
if(MYPDA in src.loc)
equip_to_appropriate_slot(MYPDA)
if(MYID in src.loc)
equip_to_appropriate_slot(MYID)
//THIEVING SKILLS END
//-------------TOUCH ME
if(istype(TARGET,/obj/structure))
var/obj/structure/STR = TARGET
if(main_hand)
var/obj/item/weapon/W = main_hand
STR.attackby(W, src)
else
STR.attack_hand(src)
interest += targetInterestShift
doing = doing & ~INTERACTING
timeout = 0
TARGET = null
else
if(TARGET)
tryWalk(TARGET)
timeout++
if(doing == 0)
interest--
else
interest++
if(inactivity_period > 0)
inactivity_period--
if(interest <= 0 || timeout >= 10) // facilitate boredom functions
TARGET = null
doing = 0
timeout = 0
myPath = list()
//this is boring, lets move
if(!doing && !IsDeadOrIncap() && !TARGET)
doing |= TRAVEL
if(!isTraitor || !traitorTarget)
var/choice = rand(1,50)
switch(choice)
if(1 to 30)
//chance to chase an item
TARGET = locate(/obj/item) in favouredObjIn(oview(MIN_RANGE_FIND,src))
if(31 to 40)
TARGET = safepick(get_area_turfs(job2area(myjob)))
if(41 to 45)
TARGET = pick(target_filter(favouredObjIn(urange(MAX_RANGE_FIND,src,1))))
if(46 to 50)
TARGET = pick(target_filter(oview(MIN_RANGE_FIND,src)))
else if(isTraitor && traitorTarget)
TARGET = traitorTarget
tryWalk(TARGET)
LAST_TARGET = TARGET
if(alternateProcessing)
spawn(processTime)
doProcess()
/mob/living/carbon/human/interactive/proc/favouredObjIn(var/list/inList)
var/list/outList = list()
for(var/i in inList)
for(var/path in favoured_types)
if(ispath(i,path))
outList += i
if(outList.len <= 0)
outList = inList
return outList
/mob/living/carbon/human/interactive/proc/callfunction(Proc)
set waitfor = 0
spawn(0)
call(src,Proc)(src)
/mob/living/carbon/human/interactive/proc/tryWalk(turf/inTarget)
if(restrictedJob) // we're a job that has to stay in our home
if(!(get_turf(inTarget) in get_area_turfs(job2area(myjob))))
TARGET = null
return
if(!IsDeadOrIncap())
if(!walk2derpless(inTarget))
timeout++
else
timeout++
/mob/living/carbon/human/interactive/proc/getGoodPath(target,var/maxtries=512)
set background = 1
var/turf/end = get_turf(target)
var/turf/current = get_turf(src)
var/list/path = list()
var/tries = 0
while(current != end && tries < maxtries)
var/turf/shortest = current
for(var/turf/T in view(current,1))
var/foundDense = 0
for(var/atom/A in T)
if(A.density)
foundDense = 1
if(T.density == 0 && !foundDense)
if(get_dist(T, target) < get_dist(shortest,target))
shortest = T
else
tries++
else
tries++
current = shortest
path += shortest
return path
/mob/living/carbon/human/interactive/proc/walk2derpless(target)
set background = 1
if(!target)
return 0
if(myPath.len <= 0)
myPath = get_path_to(src, get_turf(target), /turf/proc/Distance, MAX_RANGE_FIND + 1, 250,1, id=Path_ID)
if(myPath)
if(myPath.len > 0)
doing = doing & ~TRAVEL
for(var/i = 0; i < maxStepsTick; ++i)
if(!IsDeadOrIncap())
if(myPath.len >= 1)
walk_to(src,myPath[1],0,5)
myPath -= myPath[1]
return 1
return 0
/mob/living/carbon/human/interactive/proc/job2area(target)
var/datum/job/T = target
if(T.title == "Assistant")
return /area/hallway/primary
if(T.title == "Captain" || T.title == "Head of Personnel")
return /area/bridge
if(T.title == "Bartender")
return /area/crew_quarters/bar
if(T.title == "Cook")
return /area/crew_quarters/kitchen
if(T.title == "Station Engineer" || T.title == "Chief Engineer" || T.title == "Atmospheric Technician")
return /area/engine
if(T.title == "Chief Medical Officer" || T.title == "Medical Doctor" || T.title == "Chemist" || T.title == "Virologist" || T.title == "Geneticist")
return /area/medical
if(T.title == "Research Director" || T.title == "Scientist" || T.title == "Roboticist")
return /area/toxins
if(T.title == "Head of Security" || T.title == "Warden" || T.title == "Security Officer" || T.title == "Detective")
return /area/security
if(T.title == "Botanist")
return /area/hydroponics
else
return pick(/area/hallway,/area/crew_quarters)
/mob/living/carbon/human/interactive/proc/target_filter(target)
var/list/filtered_targets = list(/area, /turf, /obj/machinery/door, /atom/movable/light, /obj/structure/cable, /obj/machinery/atmospherics)
var/list/L = target
for(var/atom/A in target) // added a bunch of "junk" that clogs up the general find procs
if(is_type_in_list(A,filtered_targets))
L -= A
return L
/mob/living/carbon/human/interactive/proc/shouldModulePass() // returns 1 if the npc is in anything "primary"
if(doing & FIGHTING)
return 1
if(retal)
return 1
return 0
///BUILT IN MODULES
/mob/living/carbon/human/interactive/proc/chatter(obj)
var/verbs_use = pick_list(NPC_SPEAK_FILE,"verbs_use")
var/verbs_touch = pick_list(NPC_SPEAK_FILE,"verbs_touch")
var/verbs_move = pick_list(NPC_SPEAK_FILE,"verbs_move")
var/nouns_insult = pick_list(NPC_SPEAK_FILE,"nouns_insult")
var/nouns_generic = pick_list(NPC_SPEAK_FILE,"nouns_generic")
var/nouns_objects = pick_list(NPC_SPEAK_FILE,"nouns_objects")
var/nouns_body = pick_list(NPC_SPEAK_FILE,"nouns_body")
var/adjective_insult = pick_list(NPC_SPEAK_FILE,"adjective_insult")
var/adjective_objects = pick_list(NPC_SPEAK_FILE,"adjective_objects")
var/adjective_generic = pick_list(NPC_SPEAK_FILE,"adjective_generic")
var/curse_words = pick_list(NPC_SPEAK_FILE,"curse_words")
var/chatmsg = ""
if(prob(10)) // 10% chance to broadcast it over the radio
chatmsg = ";"
if(prob(chattyness) || knownStrings.len < 10) // say a generic phrase, otherwise draw from our strings.
if(doing & INTERACTING)
if(prob(chattyness))
chatmsg += pick("This [nouns_objects] is a little [adjective_objects].",
"Well [verbs_use] my [nouns_body], this [nouns_insult] is pretty [adjective_insult].",
"[capitalize(curse_words)], what am I meant to do with this [adjective_insult] [nouns_objects].")
else if(doing & TRAVEL)
if(prob(chattyness))
chatmsg += pick("Oh [curse_words], [verbs_move]!",
"Time to get my [adjective_generic] [adjective_insult] [nouns_body] elsewhere.",
"I wonder if there is anything to [verbs_use] and [verbs_touch] somewhere else..")
else if(doing & FIGHTING)
if(prob(chattyness))
chatmsg += pick("I'm going to [verbs_use] you, you [adjective_insult] [nouns_insult]!",
"Rend and [verbs_touch], Rend and [verbs_use]!",
"You [nouns_insult], I'm going to [verbs_use] you right in the [nouns_body]. JUST YOU WAIT!")
if(prob(chattyness/2))
chatmsg = ";"
var/what = pick(1,2,3,4,5)
switch(what)
if(1)
chatmsg += "Well [curse_words], this is a [adjective_generic] situation."
if(2)
chatmsg += "Oh [curse_words], that [nouns_insult] was one hell of an [adjective_insult] [nouns_body]."
if(3)
chatmsg += "I want to [verbs_use] that [nouns_insult] when I find them."
if(4)
chatmsg += "[pick("Innocent","Guilty","Traitorous","Honk")] until proven [adjective_generic]!"
if(5)
var/toSay = ""
for(var/i = 0; i < 5; i++)
curse_words = pick_list(NPC_SPEAK_FILE,"curse_words")
toSay += "[curse_words] "
chatmsg += "Hey [nouns_generic], why dont you go [toSay], you [nouns_insult]!"
else if(prob(chattyness))
chatmsg += pick(knownStrings)
if(prob(25)) // cut out some phrases now and then to make sure we're fresh and new
knownStrings -= pick(chatmsg)
if(chatmsg != ";" && chatmsg != "")
src.say(chatmsg)
/mob/living/carbon/human/interactive/proc/getAllContents()
var/list/allContents = list()
for(var/atom/A in contents)
allContents += A
if(A.contents.len > 0)
for(var/atom/B in A)
allContents += B
return allContents
/mob/living/carbon/human/interactive/proc/enforceHome()
var/list/validHome = get_area_turfs(job2area(myjob))
if(TARGET)
var/atom/tcheck = TARGET
if(tcheck)
if(!(get_turf(tcheck) in validHome))
TARGET = null
return 1
if(!(get_turf(src) in validHome))
tryWalk(pick(get_area_turfs(job2area(myjob))))
return 1
return 0
/mob/living/carbon/human/interactive/proc/npcDrop(var/obj/item/A,var/blacklist = 0)
if(blacklist)
blacklistItems += A
A.loc = get_turf(src) // drop item works inconsistently
enforce_hands()
update_icons()
/mob/living/carbon/human/interactive/proc/traitor(obj)
if(traitorType == SNPC_PSYCHO)
traitorTarget = pick(nearby)
if(prob(traitorScale))
if(!Adjacent(traitorTarget) && !(traitorType == SNPC_PSYCHO))
tryWalk(get_turf(traitorTarget))
else
switch(traitorType)
if(SNPC_BRUTE)
retal = 1
retal_target = traitorTarget
if(SNPC_STEALTH)
if(istype(traitorTarget,/mob)) // it's inside something, lets kick their shit in
var/mob/M = traitorTarget
if(!M.stat)
retal = 1
retal_target = traitorTarget
else
var/obj/item/I = traitorTarget
I.loc = get_turf(traitorTarget) // pull it outta them
else
take_to_slot(traitorTarget)
if(SNPC_MARTYR)
customEmote("[src]'s chest opens up, revealing a large mass of explosives and tangled wires!")
if(inactivity_period <= 0)
inactivity_period = 9999 // technically infinite
if(do_after(src,60,target=traitorTarget))
customEmote("A fire bursts from [src]'s eyes, igniting white hot and consuming their body in a flaming explosion!")
explosion(src, 6, 6, 6)
else
inactivity_period = 0
customEmote("[src]'s chest closes, hiding their insides.")
if(SNPC_PSYCHO)
var/choice = pick(typesof(/obj/item/weapon/grenade/chem_grenade) - /obj/item/weapon/grenade/chem_grenade)
new choice(src)
retal = 1
retal_target = traitorTarget
/mob/living/carbon/human/interactive/proc/botany(obj)
if(shouldModulePass())
return
if(enforceHome())
return
var/list/allContents = getAllContents()
var/obj/item/weapon/reagent_containers/glass/beaker/bluespace/internalBeaker = locate(/obj/item/weapon/reagent_containers/glass/beaker/bluespace) in allContents
var/obj/item/weapon/storage/bag/plants/internalBag = locate(/obj/item/weapon/storage/bag/plants) in allContents
if(!internalBag)
internalBag = new/obj/item/weapon/storage/bag/plants(src)
if(!internalBeaker)
internalBeaker = new/obj/item/weapon/reagent_containers/glass/beaker/bluespace(src)
internalBeaker.name = "Grow-U-All Super Spray"
if(internalBeaker && internalBag)
var/obj/machinery/hydroponics/HP
//consider the appropriate target
var/list/considered = list()
for(var/obj/machinery/hydroponics/tester in view(12,src))
considered[tester] = 1
if(!tester.myseed)
considered[tester] += 50
if(tester.weedlevel > 0)
considered[tester] += 5
if(tester.pestlevel > 0)
considered[tester] += 5
if(tester.nutrilevel < tester.maxnutri)
considered[tester] += 15
if(tester.waterlevel < tester.maxwater)
considered[tester] += 15
if(tester.harvest || tester.dead)
considered[tester] += 100
considered[tester] = max(1,considered[tester] - get_dist(src,tester))
var/index = 0
for(var/A in considered)
++index
if(considered[A] > considered[HP] || !HP)
HP = considered[index]
if(HP)
TARGET = HP
if(!Adjacent(HP))
tryWalk(get_turf(HP))
else
if(HP.harvest || HP.dead)
HP.attack_hand(src)
else if(!HP.myseed)
var/seedType = pick(typesof(/obj/item/seeds) - /obj/item/seeds)
var/obj/item/seeds/SEED = new seedType(src)
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")] towards [TARGET], producing a [SEED]!")
HP.attackby(SEED,src)
else
var/change = 0
if(HP.weedlevel > 0)
change = 1
if(!internalBeaker.reagents.has_reagent("weedkiller", 10))
internalBeaker.reagents.add_reagent("weedkiller",10)
if(HP.pestlevel > 0)
change = 1
if(!internalBeaker.reagents.has_reagent("pestkiller", 10))
internalBeaker.reagents.add_reagent("pestkiller",10)
if(HP.nutrilevel < HP.maxnutri)
change = 1
if(!internalBeaker.reagents.has_reagent("eznutriment", 15))
internalBeaker.reagents.add_reagent("eznutriment",15)
if(!internalBeaker.reagents.has_reagent("diethylamine", 15))
internalBeaker.reagents.add_reagent("diethylamine",15)
if(HP.waterlevel < HP.maxwater)
change = 1
if(!internalBeaker.reagents.has_reagent("holywater", 50))
internalBeaker.reagents.add_reagent("holywater",50)
if(change)
HP.attackby(internalBeaker,src)
var/obj/item/weapon/reagent_containers/food/snacks/grown/GF = locate(/obj/item/weapon/reagent_containers/food/snacks/grown) in view(12,src)
if(GF)
if(!Adjacent(GF))
tryWalk(get_turf(GF))
else
GF.attackby(internalBag,src)
if(internalBag.contents.len > 0)
var/obj/machinery/smartfridge/SF = locate(/obj/machinery/smartfridge) in range(12,src)
if(!Adjacent(SF))
tryWalk(get_turf(SF))
else
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")], upending the [internalBag]'s contents all over the [SF]!")
//smartfridges call updateUsrDialog when you call attackby, so we're going to have to cheese-magic-space this
for(var/obj/toLoad in internalBag.contents)
if(contents.len >= SF.max_n_of_items)
break
if(SF.accept_check(toLoad))
SF.load(toLoad)
else
qdel(toLoad) // destroy everything we dont need
/mob/living/carbon/human/interactive/proc/bartend(obj)
if(shouldModulePass())
return
if(enforceHome())
return
var/list/rangeCheck = oview(6,src)
var/obj/structure/table/RT
var/mob/living/carbon/human/serveTarget
for(var/mob/living/carbon/human/H in rangeCheck)
if(!locate(/obj/item/weapon/reagent_containers/food/drinks) in orange(1,H))
serveTarget = H
if(serveTarget)
RT = locate(/obj/structure/table) in orange(1,serveTarget)
if(RT && serveTarget)
if(!Adjacent(RT))
tryWalk(get_turf(RT))
else
var/drinkChoice = pick(typesof(/obj/item/weapon/reagent_containers/food/drinks) - /obj/item/weapon/reagent_containers/food/drinks)
if(drinkChoice)
var/obj/item/weapon/reagent_containers/food/drinks/D = new drinkChoice(get_turf(src))
RT.attackby(D,src)
src.say("[pick("Something to wet your whistle!","Down the hatch, a tasty beverage!","One drink, coming right up!","Tasty liquid for your oral intake!","Enjoy!")]")
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")], serving up a [D]!")
/mob/living/carbon/human/interactive/proc/shitcurity(obj)
var/list/allContents = getAllContents()
if(retal && TARGET)
for(var/obj/item/I in allContents)
if(istype(I,/obj/item/weapon/restraints))
I.attack(TARGET,src) // go go bluespace restraint launcher!
sleep(25)
/mob/living/carbon/human/interactive/proc/clowning(obj)
if(shouldModulePass())
return
var/list/allContents = getAllContents()
var/list/rangeCheck = orange(12,src)
var/mob/living/carbon/human/clownTarget
var/list/clownPriority = list()
var/obj/item/weapon/reagent_containers/spray/S
if(!locate(/obj/item/weapon/reagent_containers/spray) in allContents)
new/obj/item/weapon/reagent_containers/spray(src)
else
S = locate(/obj/item/weapon/reagent_containers/spray) in allContents
for(var/mob/living/carbon/human/C in rangeCheck)
var/pranksNearby = 100
for(var/turf/open/T in orange(1,C))
for(var/obj/item/A in T)
if(istype(A,/obj/item/weapon/soap) || istype(A,/obj/item/weapon/reagent_containers/food/snacks/grown/banana) || istype(A,/obj/item/weapon/grown/bananapeel))
pranksNearby--
if(T.wet)
pranksNearby -= 10
clownPriority[C] = pranksNearby
for(var/A in clownPriority)
if(!clownTarget)
clownTarget = A
else
if(clownPriority[A] > clownPriority[clownTarget])
clownTarget = clownPriority[A]
if(clownTarget)
if(!Adjacent(clownTarget))
tryWalk(clownTarget)
else
var/hasPranked = 0
for(var/A in allContents)
if(prob(smartness/2) && !hasPranked)
if(istype(A,/obj/item/weapon/soap))
npcDrop(A)
hasPranked = 1
if(istype(A,/obj/item/weapon/reagent_containers/food/snacks/grown/banana))
var/obj/item/weapon/reagent_containers/food/snacks/B = A
B.attack(src, src)
if(istype(A,/obj/item/weapon/grown/bananapeel))
npcDrop(A)
hasPranked = 1
if(!hasPranked)
if(S.reagents.total_volume <= 5)
S.reagents.add_reagent("water", 25)
S.afterattack(get_turf(pick(orange(1,clownTarget))),src)
/mob/living/carbon/human/interactive/proc/healpeople(obj)
var/shouldTryHeal = 0
var/obj/item/stack/medical/M
var/list/allContents = getAllContents()
for(var/A in allContents)
if(istype(A,/obj/item/stack/medical))
shouldTryHeal = 1
M = A
var/obj/item/weapon/reagent_containers/hypospray/HPS
if(!locate(/obj/item/weapon/reagent_containers/hypospray) in allContents)
new/obj/item/weapon/reagent_containers/hypospray(src)
else
HPS = locate(/obj/item/weapon/reagent_containers/hypospray) in allContents
if(!shouldTryHeal)
shouldTryHeal = 2 // we have no stackables to use, lets use our internal hypospray instead
if(shouldTryHeal == 1)
for(var/mob/living/carbon/human/C in nearby)
if(istype(C,/mob/living/carbon/human)) //I haven't the foggiest clue why this is turning up non-carbons but sure here whatever
if(C.health <= 75)
if(get_dist(src,C) <= 2)
src.say("Wait, [C], let me heal you!")
M.attack(C,src)
sleep(25)
else
tryWalk(get_turf(C))
else if(shouldTryHeal == 2)
if(HPS)
if(HPS.reagents.total_volume <= 0)
HPS.reagents.add_reagent("tricordrazine",30)
for(var/mob/living/carbon/human/C in nearby)
if(istype(C,/mob/living/carbon/human))
if(C.health <= 75 && C.reagents.get_reagent_amount("tricordrazine") <= 0) // make sure they wont be overdosing
if(get_dist(src,C) <= 2)
src.say("Wait, [C], let me heal you!")
HPS.attack(C,src)
sleep(25)
else
tryWalk(get_turf(C))
/mob/living/carbon/human/interactive/proc/dojanitor(obj)
if(shouldModulePass())
return
var/list/allContents = getAllContents()
//now with bluespace magic!
var/obj/item/weapon/reagent_containers/spray/S
if(!locate(/obj/item/weapon/reagent_containers/spray) in allContents)
new/obj/item/weapon/reagent_containers/spray(src)
else
S = locate(/obj/item/weapon/reagent_containers/spray) in allContents
if(S)
if(S.reagents.total_volume <= 5)
S.reagents.add_reagent("cleaner", 25) // bluespess water delivery for AI
var/obj/effect/decal/cleanable/TC
TC = locate(/obj/effect/decal/cleanable) in range(MAX_RANGE_FIND,src)
if(TC)
if(!Adjacent(TC))
tryWalk(TC)
else
S.afterattack(TC,src)
sleep(25)
/mob/living/carbon/human/interactive/proc/customEmote(var/text)
for(var/mob/living/carbon/M in view(src))
M.show_message("<span class='notice'>[text]</span>", 2)
// START COOKING MODULE
/mob/living/carbon/human/interactive/proc/cookingwithmagic(var/obj/item/weapon/reagent_containers/food/snacks/target)
if(Adjacent(target))
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")] towards [target], and with a bang, it's instantly cooked!")
var/obj/item/weapon/reagent_containers/food/snacks/S = new target.cooked_type (get_turf(src))
target.initialize_cooked_food(S, 100)
if(target) // cleaning up old food seems inconsistent, so this will clean up stragglers
qdel(target)
else
tryWalk(target)
/mob/living/carbon/human/interactive/proc/souschef(obj)
if(shouldModulePass())
return
if(enforceHome())
return
var/list/allContents = getAllContents()
//Bluespace in some inbuilt tools
var/obj/item/weapon/kitchen/rollingpin/RP = locate(/obj/item/weapon/kitchen/rollingpin) in allContents
if(!RP)
new/obj/item/weapon/kitchen/rollingpin(src)
var/obj/item/weapon/kitchen/knife/KK = locate(/obj/item/weapon/kitchen/knife) in allContents
if(!KK)
new/obj/item/weapon/kitchen/knife(src)
var/foundCookable = 0
if(RP && KK) // Ready to cook!
var/list/rangeCheck = view(6,src)
//Make some basic custom food
var/list/customableTypes = list(/obj/item/weapon/reagent_containers/food/snacks/customizable,/obj/item/weapon/reagent_containers/food/snacks/store/bread/plain,/obj/item/weapon/reagent_containers/food/snacks/pizzabread,/obj/item/weapon/reagent_containers/food/snacks/bun,/obj/item/weapon/reagent_containers/food/snacks/store/cake/plain,/obj/item/weapon/reagent_containers/food/snacks/pie/plain,/obj/item/weapon/reagent_containers/food/snacks/pastrybase)
var/foundCustom
for(var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/DP in rangeCheck) // donkpockets are hitler to chef SNPCs
if(prob(50))
customEmote("[src] points at the [DP], emitting a loud [pick("bellow","screech","yell","scream")], and it bursts into flame.")
qdel(DP)
for(var/customType in customableTypes)
var/A = locate(customType) in rangeCheck
if(A)
foundCustom = A // this will eventually wittle down to 0
var/obj/machinery/smartfridge/SF = locate(/obj/machinery/smartfridge) in rangeCheck
if(SF)
if(SF.contents.len > 0)
if(!Adjacent(SF))
tryWalk(get_turf(SF))
else
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")], grabbing various foodstuffs from [SF] and sticking them in it's mouth!")
for(var/obj/item/A in SF.contents)
if(prob(smartness/2))
A.loc = src
if(foundCustom)
var/obj/item/weapon/reagent_containers/food/snacks/FC = foundCustom
for(var/obj/item/weapon/reagent_containers/food/snacks/toMake in allContents)
if(prob(smartness))
if(FC.reagents)
FC.attackby(toMake,src)
else
qdel(FC) // this food is usless, toss it
//Process dough into various states
var/obj/item/weapon/reagent_containers/food/snacks/dough/D = locate(/obj/item/weapon/reagent_containers/food/snacks/dough) in rangeCheck
var/obj/item/weapon/reagent_containers/food/snacks/flatdough/FD = locate(/obj/item/weapon/reagent_containers/food/snacks/flatdough) in rangeCheck
var/obj/item/weapon/reagent_containers/food/snacks/cakebatter/CB = locate(/obj/item/weapon/reagent_containers/food/snacks/cakebatter) in rangeCheck
var/obj/item/weapon/reagent_containers/food/snacks/piedough/PD = locate(/obj/item/weapon/reagent_containers/food/snacks/piedough) in rangeCheck
if(D)
TARGET = D
var/choice = pick(1,2)
if(choice == 1)
tryWalk(get_turf(D))
sleep(get_dist(src,D))
D.attackby(RP,src)
else
cookingwithmagic(D)
foundCookable = 1
else if(FD)
TARGET = FD
var/choice = pick(1,2)
if(choice == 1)
tryWalk(get_turf(D))
sleep(get_dist(src,D))
FD.attackby(KK,src)
else
cookingwithmagic(FD)
foundCookable = 1
else if(CB)
TARGET = CB
var/choice = pick(1,2)
if(choice == 1)
tryWalk(get_turf(D))
sleep(get_dist(src,D))
CB.attackby(RP,src)
else
cookingwithmagic(CB)
foundCookable = 1
else if(PD)
TARGET = PD
var/choice = pick(1,2)
if(choice == 1)
tryWalk(get_turf(D))
sleep(get_dist(src,D))
PD.attackby(KK,src)
else
cookingwithmagic(PD)
foundCookable = 1
//Cook various regular foods into processed versions
var/obj/item/weapon/reagent_containers/food/snacks/toCook = locate(/obj/item/weapon/reagent_containers/food/snacks) in rangeCheck
if(toCook)
if(toCook.cooked_type)
TARGET = toCook
foundCookable = 1
if(Adjacent(toCook))
cookingwithmagic(toCook)
else
tryWalk(get_turf(toCook))
var/list/finishedList = list()
for(var/obj/item/weapon/reagent_containers/food/snacks/toDisplay in allContents)
if(!toDisplay.cooked_type && !istype(toDisplay,/obj/item/weapon/reagent_containers/food/snacks/grown)) // dont display our ingredients
finishedList += toDisplay
for(var/obj/item/weapon/reagent_containers/food/snacks/toGrab in rangeCheck)
if(!(locate(/obj/structure/table/reinforced) in get_turf(toGrab))) //it's not being displayed
foundCookable = 1
if(!Adjacent(toGrab))
tryWalk(toGrab)
else
toGrab.loc = src
if(finishedList.len > 0)
var/obj/structure/table/reinforced/RT
for(var/obj/structure/table/reinforced/toCheck in rangeCheck)
var/counted = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/S in get_turf(toCheck))
++counted
if(counted < 12) // make sure theres not too much food here
RT = toCheck
break
if(RT)
foundCookable = 1
if(!Adjacent(RT))
tryWalk(get_turf(RT))
else
for(var/obj/item/weapon/reagent_containers/food/snacks/toPlop in allContents)
RT.attackby(toPlop,src)
if(!foundCookable)
var/list/allTypes = list(/obj/item/weapon/reagent_containers/food/snacks/piedough,/obj/item/weapon/reagent_containers/food/snacks/cakebatter,/obj/item/weapon/reagent_containers/food/snacks/dough,/obj/item/weapon/reagent_containers/food/snacks/flatdough)
for(var/A in typesof(/obj/item/weapon/reagent_containers/food/snacks))
var/obj/item/weapon/reagent_containers/food/snacks/O = A
if(initial(O.cooked_type))
allTypes += A
var/chosenType = pick(allTypes)
var/obj/item/weapon/reagent_containers/food/snacks/newSnack = new chosenType(get_turf(src))
TARGET = newSnack
newSnack.reagents.remove_any((newSnack.reagents.total_volume/2)-1)
newSnack.name = "Synthetic [newSnack.name]"
customEmote("[src] [pick("gibbers","drools","slobbers","claps wildly","spits")] as they vomit [newSnack] from their mouth!")
// END COOKING MODULE
/mob/living/carbon/human/interactive/proc/compareFaction(var/list/targetFactions)
var/hasSame = 0
for(var/A in targetFactions)
if(A in faction)
hasSame = 1
return hasSame
/mob/living/carbon/human/interactive/proc/combat(obj)
set background = 1
enforce_hands()
if(canmove)
if((graytide || (TRAITS & TRAIT_MEAN)) || retal)
interest += targetInterestShift
a_intent = "harm"
zone_selected = pick("chest","r_leg","l_leg","r_arm","l_arm","head")
doing |= FIGHTING
if(retal)
TARGET = retal_target
else
var/mob/living/M = locate(/mob/living) in oview(7,src)
if(M != src && !compareFaction(M.faction))
TARGET = M
if(!M)
doing = doing & ~FIGHTING
//no infighting
if(retal)
if(retal_target)
if(compareFaction(retal_target.faction))
retal = 0
retal_target = null
TARGET = null
doing = 0
//ensure we're using the best object possible
var/obj/item/weapon/best
var/foundFav = 0
var/list/allContents = getAllContents()
for(var/test in allContents)
for(var/a in favoured_types)
if(ispath(test,a) && !(doing & FIGHTING)) // if we're not in combat and we find our favourite things, use them (for people like janitor and doctors)
best = test
foundFav = 1
return
if(!foundFav)
if(istype(test,/obj/item/weapon))
var/obj/item/weapon/R = test
if(R.force > 2) // make sure we don't equip any non-weaponlike items, ie bags and stuff
if(!best)
best = R
else
if(best.force < R.force)
best = R
if(istype(R,/obj/item/weapon/gun))
var/obj/item/weapon/gun/G = R
if(G.can_shoot())
best = R
break // gun with ammo? screw the rest
if(best)
take_to_slot(best,1)
if((TARGET && (doing & FIGHTING))) // this is a redundancy check
var/mob/living/M = TARGET
if(istype(M,/mob/living))
if(M.health > 1)
//THROWING OBJECTS
for(var/A in allContents)
if(istype(A,/obj/item/weapon/gun)) // guns are for shooting, not throwing.
continue
if(prob(robustness))
if(istype(A,/obj/item/weapon))
var/obj/item/weapon/W = A
if(W.throwforce > 19) // Only throw worthwile stuff, no more lobbing wrenches at wenches
npcDrop(W,1)
throw_item(TARGET)
if(istype(A,/obj/item/weapon/grenade)) // Allahu ackbar! ALLAHU ACKBARR!!
var/obj/item/weapon/grenade/G = A
G.attack_self(src)
if(prob(smartness))
npcDrop(G,1)
sleep(15)
throw_item(TARGET)
if(!main_hand && other_hand)
swap_hands()
if(main_hand)
if(main_hand.force != 0)
if(istype(main_hand,/obj/item/weapon/gun))
var/obj/item/weapon/gun/G = main_hand
if(G.can_trigger_gun(src))
if(istype(main_hand,/obj/item/weapon/gun/projectile))
var/obj/item/weapon/gun/projectile/P = main_hand
if(!P.chambered)
P.chamber_round()
P.update_icon()
else if(P.get_ammo(1) == 0)
P.update_icon()
npcDrop(P,1)
else
P.afterattack(TARGET, src)
else if(istype(main_hand,/obj/item/weapon/gun/energy))
var/obj/item/weapon/gun/energy/P = main_hand
var/stunning = 0
for(var/A in P.ammo_type)
if(ispath(A,/obj/item/ammo_casing/energy/electrode))
stunning = 1
var/shouldFire = 1
var/mob/stunCheck = TARGET
if(stunning && stunCheck.stunned)
shouldFire = 0
if(shouldFire)
if(P.power_supply.charge <= 10) // can shoot seems to bug out for tasers, using this hacky method instead
P.update_icon()
npcDrop(P,1)
else
P.afterattack(TARGET, src)
else
if(get_dist(src,TARGET) > 6)
if(!walk2derpless(TARGET))
timeout++
else
var/obj/item/weapon/W = main_hand
W.attack(TARGET,src)
else
G.loc = get_turf(src) // drop item works inconsistently
enforce_hands()
update_icons()
else
if(targetRange(TARGET) > 2)
tryWalk(TARGET)
else
if(Adjacent(TARGET))
a_intent = pick("disarm","harm")
M.attack_hand(src)
timeout++
else if(timeout >= 10 || !(targetRange(M) > 14))
doing = doing & ~FIGHTING
timeout = 0
TARGET = null
retal = 0
retal_target = null
else
timeout++
/mob/living/carbon/human/interactive/proc/nearbyscan(obj)
nearby = list()
for(var/mob/living/M in view(4,src))
if(M != src)
nearby += M
//END OF MODULES
/mob/living/carbon/human/interactive/angry/New()
TRAITS |= TRAIT_ROBUST
TRAITS |= TRAIT_MEAN
faction += "bot_angry"
..()
/mob/living/carbon/human/interactive/friendly/New()
TRAITS |= TRAIT_FRIENDLY
TRAITS |= TRAIT_UNROBUST
faction += "bot_friendly"
faction += "neutral"
functions -= "combat"
..()
/mob/living/carbon/human/interactive/greytide/New()
TRAITS |= TRAIT_ROBUST
TRAITS |= TRAIT_MEAN
TRAITS |= TRAIT_THIEVING
TRAITS |= TRAIT_DUMB
maxInterest = 5 // really short attention span
targetInterestShift = 2 // likewise
faction += "bot_grey"
graytide = 1
..()