/* 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 = 1 var/forceProcess = 0 var/processTime = 8 var/lastProc = 0 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/choice = input("Customization Choices") as null|anything in list("Service NPC","Security NPC","Random","Custom") if(choice) if(choice == "Service NPC" || choice == "Security NPC") var/job = choice == "Service NPC" ? pick("Bartender","Cook","Botanist","Janitor") : pick("Warden","Detective","Security Officer") for(var/j in SSjob.occupations) var/datum/job/J = j if(J.title == job) T.myjob = J 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() break if(choice == "Random") T.myjob = pick(SSjob.occupations) 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() if(prob(25)) var/list/validchoices = list() for(var/mob/living/carbon/human/M in mob_list) validchoices += M var/mob/living/carbon/human/chosen = pick(validchoices) 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() if(prob(25)) var/cType = pick(list(SNPC_BRUTE,SNPC_STEALTH,SNPC_MARTYR,SNPC_PSYCHO)) T.makeTraitor(cType) T.loc = pick(get_area_turfs(T.job2area(T.myjob))) if(choice == "Custom") 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 || world.time > lastProc + processTime) 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() set waitfor = 0 forceProcess = 0 lastProc = world.time 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 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) 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() for(var/mob/living/carbon/human/C in nearby) var/perpname = C.get_face_name(C.get_id_name()) var/datum/data/record/R = find_record("name", perpname, data_core.security) if(R && R.fields["criminal"]) switch(R.fields["criminal"]) if("*Arrest*") retalTarget(C) 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("[text]", 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) 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 ..()