mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-11 23:23:28 +01:00
Here we go again
This commit is contained in:
@@ -20,4 +20,4 @@
|
||||
for(var/datum/light_source/L in light_sources)
|
||||
L.source_atom.update_light()
|
||||
|
||||
return 1
|
||||
return 1
|
||||
@@ -315,15 +315,7 @@
|
||||
msg += "[p_they(TRUE)] [p_have()] a stupid expression on [p_their()] face.\n"
|
||||
|
||||
if(get_int_organ(/obj/item/organ/internal/brain))
|
||||
if(istype(src, /mob/living/carbon/human/interactive))
|
||||
var/mob/living/carbon/human/interactive/auto = src
|
||||
if(auto.showexaminetext)
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] appears to be some sort of sick automaton, [p_their()] eyes are glazed over and [p_their()] mouth is slightly agape.</span>\n"
|
||||
if(auto.debugexamine)
|
||||
var/dodebug = auto.doing2string(auto.doing)
|
||||
var/interestdebug = auto.interest2string(auto.interest)
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] appears to be [interestdebug] and [dodebug].</span>\n"
|
||||
else if(dna.species.show_ssd)
|
||||
if(dna.species.show_ssd)
|
||||
if(!key)
|
||||
msg += "<span class='deadsay'>[p_they(TRUE)] [p_are()] totally catatonic. The stresses of life in deep-space must have been too much for [p_them()]. Any recovery is unlikely.</span>\n"
|
||||
else if(!client)
|
||||
|
||||
@@ -1,874 +0,0 @@
|
||||
/mob/living/carbon/human/interactive/proc/chatter(obj)
|
||||
var/verbs_use = pick_list(speak_file, "verbs_use")
|
||||
var/verbs_touch = pick_list(speak_file, "verbs_touch")
|
||||
var/verbs_move = pick_list(speak_file, "verbs_move")
|
||||
var/nouns_insult = pick_list(speak_file, "nouns_insult")
|
||||
var/nouns_generic = pick_list(speak_file, "nouns_generic")
|
||||
var/nouns_objects = pick_list(speak_file, "nouns_objects")
|
||||
var/nouns_body = pick_list(speak_file, "nouns_body")
|
||||
var/adjective_insult = pick_list(speak_file, "adjective_insult")
|
||||
var/adjective_objects = pick_list(speak_file, "adjective_objects")
|
||||
var/adjective_generic = pick_list(speak_file, "adjective_generic")
|
||||
var/curse_words = pick_list(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 & SNPC_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 & SNPC_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 & SNPC_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(speak_file, "curse_words")
|
||||
toSay += "[curse_words] "
|
||||
chatmsg += "Hey [nouns_generic], why don't you go [copytext(toSay, 1, length(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 != "")
|
||||
say(chatmsg)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/traitor(obj)
|
||||
|
||||
if(traitorType == SNPC_PSYCHO && nearby.len)
|
||||
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)
|
||||
custom_emote(1, "[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))
|
||||
custom_emote(1, "A fire bursts from [src]'s eyes, igniting white hot and consuming [p_their()] body in a flaming explosion!")
|
||||
explosion(src, 6, 6, 6)
|
||||
else
|
||||
inactivity_period = 0
|
||||
custom_emote(1, "[src]'s chest closes, hiding [p_their()] insides.")
|
||||
if(SNPC_PSYCHO)
|
||||
var/choice = pick(typesof(/obj/item/grenade/chem_grenade) - /obj/item/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/reagent_containers/glass/beaker/bluespace/internalBeaker = locate(/obj/item/reagent_containers/glass/beaker/bluespace) in allContents
|
||||
var/obj/item/storage/bag/plants/internalBag = locate(/obj/item/storage/bag/plants) in allContents
|
||||
|
||||
if(!internalBag)
|
||||
internalBag = new/obj/item/storage/bag/plants(src)
|
||||
if(!internalBeaker)
|
||||
internalBeaker = new/obj/item/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/obj/item/seeds/SEED = new /obj/item/seeds/random(src)
|
||||
custom_emote(1, "[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("atrazine", 10))
|
||||
internalBeaker.reagents.add_reagent("atrazine", 10)
|
||||
if(HP.pestlevel > 0)
|
||||
change = 1
|
||||
if(!internalBeaker.reagents.has_reagent("diethylamine", 10))
|
||||
internalBeaker.reagents.add_reagent("diethylamine", 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/reagent_containers/food/snacks/grown/GF = locate(/obj/item/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)
|
||||
var/obj/machinery/smartfridge/SF = locate(/obj/machinery/smartfridge) in range(12, src)
|
||||
if(!Adjacent(SF))
|
||||
tryWalk(get_turf(SF))
|
||||
else
|
||||
custom_emote(1, "[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, src)
|
||||
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/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/reagent_containers/food/drinks) - /obj/item/reagent_containers/food/drinks)
|
||||
if(drinkChoice)
|
||||
var/obj/item/reagent_containers/food/drinks/D = new drinkChoice(get_turf(src))
|
||||
RT.attackby(D,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!")]")
|
||||
custom_emote(2, "[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)
|
||||
if(Adjacent(TARGET))
|
||||
var/obj/item/restraints/R = locate() in allContents
|
||||
if(R)
|
||||
R.attack(TARGET, src) // go go bluespace restraint launcher!
|
||||
else if(TARGET in oview(7, src))
|
||||
var/obj/item/gun/G = locate() in allContents
|
||||
if(G)
|
||||
G.afterattack(TARGET, src)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/clowning(obj)
|
||||
if(shouldModulePass())
|
||||
return
|
||||
var/list/allContents = getAllContents()
|
||||
var/list/rangeCheck = oview(12, src)
|
||||
|
||||
var/mob/living/carbon/human/clownTarget
|
||||
var/list/clownPriority = list()
|
||||
|
||||
var/obj/item/reagent_containers/spray/S
|
||||
if(!locate(/obj/item/reagent_containers/spray) in allContents)
|
||||
new/obj/item/reagent_containers/spray(src)
|
||||
else
|
||||
S = locate(/obj/item/reagent_containers/spray) in allContents
|
||||
|
||||
for(var/mob/living/carbon/human/C in rangeCheck)
|
||||
var/pranksNearby = 100
|
||||
for(var/turf/simulated/T in orange(1, C))
|
||||
for(var/obj/item/A in T)
|
||||
if(istype(A,/obj/item/soap) || istype(A,/obj/item/reagent_containers/food/snacks/grown/banana) || istype(A,/obj/item/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/soap))
|
||||
npcDrop(A)
|
||||
hasPranked = 1
|
||||
if(istype(A,/obj/item/reagent_containers/food/snacks/grown/banana))
|
||||
var/obj/item/reagent_containers/food/snacks/B = A
|
||||
B.attack(src, src)
|
||||
if(istype(A,/obj/item/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/reagent_containers/hypospray/HPS
|
||||
|
||||
if(!locate(/obj/item/reagent_containers/hypospray) in allContents)
|
||||
new/obj/item/reagent_containers/hypospray(src)
|
||||
else
|
||||
HPS = locate(/obj/item/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("omnizine",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("omnizine") <= 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/reagent_containers/spray/SP = locate() in allContents
|
||||
if(!SP)
|
||||
SP = new /obj/item/reagent_containers/spray(src)
|
||||
var/obj/item/soap/SO = locate() in allContents
|
||||
if(!SO)
|
||||
SO = new /obj/item/soap(src)
|
||||
|
||||
if(SP.reagents.total_volume <= 5)
|
||||
SP.reagents.add_reagent("cleaner", 25) // bluespess water delivery for AI
|
||||
|
||||
var/obj/effect/decal/cleanable/TC
|
||||
TC = locate(/obj/effect/decal/cleanable) in view(6, src)
|
||||
|
||||
if(TC)
|
||||
if(!Adjacent(TC))
|
||||
tryWalk(TC)
|
||||
else
|
||||
var/turf/T = get_turf(TC)
|
||||
if(T && !T.density)
|
||||
SP.afterattack(TC, src, 1)
|
||||
else
|
||||
SO.afterattack(TC, src, 1)
|
||||
qdel(TC)
|
||||
|
||||
// START COOKING MODULE
|
||||
/mob/living/carbon/human/interactive/proc/refundrecipe(list/ingredients)
|
||||
for(var/obj/I in ingredients)
|
||||
I.loc = contents
|
||||
|
||||
// Ingredients may be in the rangeCheck or inside the chef's inventory.
|
||||
// As they are checked off, they are moved to a seperate list as to not be counted twice
|
||||
// If the recipe fails (eg somebody else took an ingredient before it was picked up) the ingredients are dumped back to inventory
|
||||
// That way, the chef has a better chance of making a recipe next ptick, if he has more stuff on him
|
||||
/mob/living/carbon/human/interactive/proc/makerecipe(datum/recipe/R, allContents, rangeCheck)
|
||||
set background = 1
|
||||
|
||||
var/list/ingredients[0]
|
||||
|
||||
for(var/P in R.items)
|
||||
var/obj/item/I = locate(P) in allContents
|
||||
if(I)
|
||||
ingredients += I
|
||||
I.forceMove(null)
|
||||
continue
|
||||
|
||||
I = locate(P) in rangeCheck
|
||||
TARGET = I
|
||||
if(I && !Adjacent(I))
|
||||
tryWalk(get_turf(I))
|
||||
sleep(get_dist(src, I))
|
||||
if(!I || !(I in rangeCheck))
|
||||
refundrecipe(ingredients)
|
||||
return 0
|
||||
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")], picking up [I].")
|
||||
ingredients += I
|
||||
I.forceMove(null)
|
||||
|
||||
// cheaply cook the ingredients into result
|
||||
sleep(R.time)
|
||||
for(var/obj/I in ingredients)
|
||||
qdel(I)
|
||||
ingredients.Cut()
|
||||
var/result = new R.result(get_turf(src))
|
||||
custom_emote(1, "[pick("gibbers","drools","slobbers","claps wildly","spits")] and, with a bang, \a [result] is cooked!")
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/souschef(obj)
|
||||
if(shouldModulePass() || enforceHome() || prob(SNPC_FUZZY_CHANCE_HIGH) || prob(SNPC_FUZZY_CHANCE_HIGH))
|
||||
return
|
||||
|
||||
if(doing & SNPC_SPECIAL)
|
||||
return
|
||||
doing |= SNPC_SPECIAL
|
||||
|
||||
var/static/list/customableTypes = list(/obj/item/reagent_containers/food/snacks/customizable,/obj/item/reagent_containers/food/snacks/breadslice,/obj/item/reagent_containers/food/snacks/bun,/obj/item/reagent_containers/food/snacks/sliceable/flatdough,/obj/item/reagent_containers/food/snacks/boiledspaghetti,/obj/item/trash/plate,/obj/item/trash/bowl)
|
||||
|
||||
var/static/list/rawtypes = list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/reagent_containers/food/snacks/rawcutlet, /obj/item/reagent_containers/food/snacks/rawsticks, /obj/item/reagent_containers/food/snacks/salmonmeat, /obj/item/reagent_containers/food/snacks/carpmeat, /obj/item/reagent_containers/food/snacks/catfishmeat, /obj/item/reagent_containers/food/snacks/spaghetti, /obj/item/reagent_containers/food/snacks/dough, /obj/item/reagent_containers/food/snacks/sliceable/flatdough, /obj/item/reagent_containers/food/snacks/doughslice, /obj/item/reagent_containers/food/snacks/meat, /obj/item/reagent_containers/food/snacks/boiledrice, /obj/item/reagent_containers/food/snacks/cheesewedge, /obj/item/reagent_containers/food/snacks/raw_bacon)
|
||||
|
||||
try
|
||||
var/list/allContents = getAllContents()
|
||||
var/list/rangeCheck = view(6, src)
|
||||
|
||||
//Bluespace in some inbuilt tools
|
||||
var/obj/item/kitchen/rollingpin/RP = locate() in allContents
|
||||
if(!RP)
|
||||
RP = new /obj/item/kitchen/rollingpin(src)
|
||||
|
||||
var/obj/item/kitchen/knife/KK = locate() in allContents
|
||||
if(!KK)
|
||||
KK = new /obj/item/kitchen/knife(src)
|
||||
|
||||
var/global/list/available_recipes
|
||||
if(!available_recipes)
|
||||
available_recipes = list()
|
||||
for(var/type in subtypesof(/datum/recipe))
|
||||
var/datum/recipe/recipe = new type
|
||||
if(recipe.result) // Ignore recipe subtypes that lack a result
|
||||
available_recipes += recipe
|
||||
else
|
||||
qdel(recipe)
|
||||
|
||||
var/foundCookable = 0
|
||||
|
||||
//Make some basic custom food
|
||||
var/foundCustom
|
||||
for(var/customType in customableTypes)
|
||||
var/A = locate(customType) in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/customizable/I = A
|
||||
if(A && (!istype(I) || I.ingredients.len <= 3))
|
||||
foundCustom = A // this will eventually wittle down to 0
|
||||
break
|
||||
|
||||
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
|
||||
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")], grabbing various foodstuffs from [SF] and sticking them in its mouth!")
|
||||
for(var/obj/item/A in SF.contents)
|
||||
if(prob(smartness/2))
|
||||
var/count = SF.item_quants[A.name]
|
||||
if(count)
|
||||
SF.item_quants[A.name] = count - 1
|
||||
A.forceMove(src)
|
||||
|
||||
if(foundCustom)
|
||||
var/obj/item/reagent_containers/food/snacks/FC = foundCustom
|
||||
for(var/obj/item/reagent_containers/food/snacks/toMake in allContents)
|
||||
if(prob(smartness))
|
||||
if(FC.reagents)
|
||||
if(toMake.reagents)
|
||||
var/raw = 0
|
||||
for(var/type in rawtypes)
|
||||
if(istype(toMake, type))
|
||||
raw = 1
|
||||
break
|
||||
if(!raw)
|
||||
npcDrop(toMake)
|
||||
FC.attackby(toMake, src)
|
||||
allContents -= toMake
|
||||
break
|
||||
else
|
||||
qdel(FC) // this food is usless, toss it
|
||||
|
||||
// Process tool-based ingredients
|
||||
var/obj/item/reagent_containers/food/snacks/dough/D = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/sliceable/flatdough/FD = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/rawcutlet/RC = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/sliceable/cheesewheel/CW = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/grown/potato/PO = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/meat/ME = locate() in rangeCheck
|
||||
var/obj/item/reagent_containers/food/snacks/raw_bacon/RB = locate() in rangeCheck
|
||||
|
||||
if(D)
|
||||
TARGET = D
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(D))
|
||||
sleep(get_dist(src, D))
|
||||
D.attackby(RP, src)
|
||||
foundCookable = 1
|
||||
else if(FD)
|
||||
TARGET = FD
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(FD))
|
||||
sleep(get_dist(src, FD))
|
||||
FD.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
else if(RC)
|
||||
TARGET = RC
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(RC))
|
||||
sleep(get_dist(src, RC))
|
||||
RC.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
else if(CW)
|
||||
TARGET = CW
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(CW))
|
||||
sleep(get_dist(src, CW))
|
||||
CW.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
else if(PO)
|
||||
TARGET = PO
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(PO))
|
||||
sleep(get_dist(src, PO))
|
||||
PO.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
else if(ME)
|
||||
TARGET = ME
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(ME))
|
||||
sleep(get_dist(src, ME))
|
||||
ME.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
else if(RB)
|
||||
TARGET = RB
|
||||
if(prob(50))
|
||||
tryWalk(get_turf(RB))
|
||||
sleep(get_dist(src, RB))
|
||||
RB.attackby(KK, src)
|
||||
foundCookable = 1
|
||||
|
||||
// refresh
|
||||
allContents = getAllContents()
|
||||
rangeCheck = view(6, src)
|
||||
|
||||
// Find most complex recipe we can cook
|
||||
var/ingredientZone = rangeCheck + allContents
|
||||
var/highest_count = 0
|
||||
var/datum/recipe/winner = null
|
||||
for(var/datum/recipe/R in available_recipes)
|
||||
if(R.check_items(ingredientZone) >= 0)
|
||||
var/count = (R.items ? R.items.len : 0)
|
||||
if(count > highest_count)
|
||||
highest_count = count
|
||||
winner = R
|
||||
|
||||
// make winner
|
||||
if(winner)
|
||||
if(makerecipe(winner, allContents, rangeCheck))
|
||||
foundCookable = 1
|
||||
|
||||
// refresh
|
||||
allContents = getAllContents()
|
||||
rangeCheck = view(6, src)
|
||||
|
||||
// dont display our ingredients
|
||||
var/list/finishedList = list()
|
||||
for(var/obj/item/reagent_containers/food/snacks/toDisplay in allContents)
|
||||
var/raw = 0
|
||||
for(var/type in rawtypes)
|
||||
if(istype(toDisplay, type))
|
||||
raw = 1
|
||||
break
|
||||
if(!raw)
|
||||
finishedList += toDisplay
|
||||
|
||||
for(var/obj/item/reagent_containers/food/snacks/toGrab in rangeCheck)
|
||||
if(!(locate(/obj/structure/table/reinforced) in get_turf(toGrab))) //it's not being displayed
|
||||
var/raw = 0
|
||||
for(var/type in rawtypes)
|
||||
if(istype(toGrab, type))
|
||||
raw = 1
|
||||
break
|
||||
if(!raw)
|
||||
foundCookable = 1
|
||||
if(!Adjacent(toGrab))
|
||||
tryWalk(toGrab)
|
||||
else
|
||||
finishedList += toGrab
|
||||
toGrab.forceMove(src)
|
||||
|
||||
if(finishedList.len)
|
||||
var/obj/structure/table/reinforced/RT
|
||||
|
||||
for(var/obj/structure/table/reinforced/toCheck in rangeCheck)
|
||||
var/counted = 0
|
||||
for(var/obj/item/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/reagent_containers/food/snacks/toPlop in finishedList)
|
||||
RT.attackby(toPlop,src)
|
||||
|
||||
if(!foundCookable)
|
||||
var/chosenType = pick(rawtypes)
|
||||
|
||||
var/obj/item/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]"
|
||||
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as [p_they()] vomit[p_s()] [newSnack] from [p_their()] mouth!")
|
||||
catch(var/exception/e)
|
||||
log_runtime(e, src, "Caught in SNPC cooking module")
|
||||
doing &= ~SNPC_SPECIAL
|
||||
// END COOKING MODULE
|
||||
|
||||
/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 = INTENT_HARM
|
||||
zone_sel.selecting = pick("chest","r_leg","l_leg","r_arm","l_arm","head")
|
||||
doing |= SNPC_FIGHTING
|
||||
if(retal)
|
||||
TARGET = retal_target
|
||||
else
|
||||
var/mob/living/M = locate(/mob/living) in oview(7, src)
|
||||
if(!M)
|
||||
doing = doing & ~SNPC_FIGHTING
|
||||
else if(M != src && !compareFaction(M.faction))
|
||||
TARGET = M
|
||||
|
||||
//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/best
|
||||
var/foundFav = 0
|
||||
var/list/allContents = getAllContents()
|
||||
for(var/test in allContents)
|
||||
for(var/a in favoured_types)
|
||||
if(ispath(test,a) && !(doing & SNPC_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))
|
||||
var/obj/item/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/gun))
|
||||
var/obj/item/gun/G = R
|
||||
if(G.can_shoot())
|
||||
best = R
|
||||
break // gun with ammo? screw the rest
|
||||
if(best && best != main_hand)
|
||||
take_to_slot(best,1)
|
||||
|
||||
if(TARGET && (doing & SNPC_FIGHTING)) // this is a redundancy check
|
||||
var/mob/living/M = TARGET
|
||||
if(istype(M,/mob/living))
|
||||
if(M.health > 1 && (M in oview(src, 6)))
|
||||
//THROWING OBJECTS
|
||||
for(var/A in allContents)
|
||||
if(istype(A,/obj/item/gun)) // guns are for shooting, not throwing.
|
||||
continue
|
||||
if(prob(robustness))
|
||||
if(istype(A,/obj/item))
|
||||
var/obj/item/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/grenade)) // Allahu ackbar! ALLAHU ACKBARR!!
|
||||
var/obj/item/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/gun))
|
||||
var/obj/item/gun/G = main_hand
|
||||
if(G.can_trigger_gun(src))
|
||||
var/shouldFire = 1
|
||||
if(istype(main_hand, /obj/item/gun/energy))
|
||||
var/obj/item/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/mob/stunCheck = TARGET
|
||||
if(stunning && stunCheck.stunned)
|
||||
shouldFire = 0
|
||||
if(shouldFire)
|
||||
if(!G.can_shoot())
|
||||
G.shoot_with_empty_chamber(src)
|
||||
npcDrop(G, 1)
|
||||
else
|
||||
G.process_fire(TARGET, src)
|
||||
else
|
||||
if(get_dist(src,TARGET) > 6)
|
||||
if(!walk2derpless(TARGET))
|
||||
timeout++
|
||||
else
|
||||
var/obj/item/W = main_hand
|
||||
W.attack(TARGET, src)
|
||||
else
|
||||
npcDrop(G, 1)
|
||||
else
|
||||
if(targetRange(TARGET) > 2)
|
||||
tryWalk(TARGET)
|
||||
else
|
||||
if(Adjacent(TARGET))
|
||||
a_intent = pick(INTENT_DISARM, INTENT_HARM)
|
||||
M.attack_hand(src)
|
||||
timeout++
|
||||
else if(timeout >= 10 || !(targetRange(M) > 14))
|
||||
doing = doing & ~SNPC_FIGHTING
|
||||
timeout = 0
|
||||
TARGET = null
|
||||
retal = 0
|
||||
retal_target = null
|
||||
else
|
||||
timeout++
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/past_verb(word)
|
||||
if(copytext(word, length(word)) == "e")
|
||||
return "[word]d"
|
||||
else
|
||||
return "[word]ed"
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/ing_verb(word)
|
||||
if(copytext(word, length(word)) == "e")
|
||||
return "[copytext(word, 1, length(word))]ing"
|
||||
else
|
||||
return "[word]ing"
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/paperwork_sentence()
|
||||
var/verbs_use = pick_list(speak_file, "verbs_use")
|
||||
var/verbs_touch = pick_list(speak_file, "verbs_touch")
|
||||
var/verbs_move = pick_list(speak_file, "verbs_move")
|
||||
var/nouns_insult = pick_list(speak_file, "nouns_insult")
|
||||
var/nouns_generic = pick_list(speak_file, "nouns_generic")
|
||||
var/nouns_objects = pick_list(speak_file, "nouns_objects")
|
||||
var/nouns_body = pick_list(speak_file, "nouns_body")
|
||||
var/adjective_insult = pick_list(speak_file, "adjective_insult")
|
||||
var/adjective_objects = pick_list(speak_file, "adjective_objects")
|
||||
var/adjective_generic = pick_list(speak_file, "adjective_generic")
|
||||
var/curse_words = pick_list(speak_file, "curse_words")
|
||||
var/result = pick("fired", "promoted", "demoted", "terminated", "incinerated", "sent to CentCom", "borged")
|
||||
|
||||
return pick(
|
||||
"The [adjective_insult] [pick(command_positions)] [past_verb(verbs_touch)] the [adjective_objects] [nouns_objects] and was [result].",
|
||||
"The [adjective_generic] [pick(engineering_positions)] [past_verb(verbs_touch)] the [adjective_insult] [nouns_objects]. [capitalize(curse_words)], the [nouns_insult] was [result].",
|
||||
"The [adjective_insult] [pick(security_positions)] [past_verb(verbs_touch)] the [adjective_generic] [nouns_insult] [pick(support_positions)]'s [nouns_body] and had to be [result].",
|
||||
"Medical had to [verbs_use] the [adjective_generic] [pick(command_positions)]'s [adjective_objects] [nouns_body] after the incident.",
|
||||
"I demand that [nouns_generic] respond with a [adjective_generic] update ASAP.",
|
||||
"Would like an update from [nouns_generic] regarding the [adjective_insult] [pick(command_positions)] being [result].",
|
||||
"The [pick(medical_positions)] needs to [verbs_move] faster when the crew's [adjective_objects] [nouns_body]s are injured, or they will be [result].",
|
||||
"[capitalize(curse_words)] [adjective_insult] [curse_words].",
|
||||
"<br><br>")
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/pickStamp(allContents)
|
||||
var/list/stamps[0]
|
||||
for(var/obj/item/stamp/S in allContents)
|
||||
stamps += S
|
||||
if(stamps.len)
|
||||
return pick(stamps)
|
||||
|
||||
// just make one, maybe
|
||||
if(prob(SNPC_FUZZY_CHANCE_LOW / 2))
|
||||
for(var/p in favoured_types)
|
||||
if(ispath(p, /obj/item/stamp))
|
||||
return new p(src)
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/paperwork(obj)
|
||||
set background = 1
|
||||
|
||||
if(shouldModulePass() || !prob(SNPC_FUZZY_CHANCE_LOW / 4))
|
||||
return
|
||||
|
||||
var/list/allContents = getAllContents()
|
||||
|
||||
var/obj/item/paper/P = locate() in allContents
|
||||
var/obj/item/stamp/S = pickStamp(allContents)
|
||||
var/mob/living/carbon/human/H = locate() in nearby
|
||||
|
||||
if(!P)
|
||||
P = new /obj/item/paper(src)
|
||||
|
||||
if(P && S && H)
|
||||
if(!P.stamped || !P.stamped.len)
|
||||
// generate form
|
||||
P.name = pick("Inspection Report", "Re: Crew", "Complaint", "To: CentCom")
|
||||
P.info = {"<center><img src=ntlogo.png><br><b><font size="1">[paperwork_sentence()]</font></b></center>"}
|
||||
for(var/I in 1 to rand(10, 20))
|
||||
P.info += "[paperwork_sentence()] "
|
||||
P.info += {"<br><br>[pick("Signed", "Sincerely", "Regards")], <font face="Times New Roman"><i>[real_name]</i></font>"}
|
||||
P.update_icon()
|
||||
P.stamp(S)
|
||||
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] and throws [P] on the ground!")
|
||||
npcDrop(P)
|
||||
P.throw_at(H, P.throw_range, P.throw_speed, src)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/stamping(obj)
|
||||
if(shouldModulePass())
|
||||
return
|
||||
|
||||
var/list/allContents = getAllContents()
|
||||
var/list/rangeCheck = view(7, src)
|
||||
|
||||
var/obj/item/stamp/S = pickStamp(allContents)
|
||||
if(!S)
|
||||
return
|
||||
|
||||
// stamp a paper we're holding, and drop it
|
||||
var/obj/item/paper/P = locate() in allContents
|
||||
if(P)
|
||||
if(!P.stamped || !P.stamped.len)
|
||||
P.stamp(S)
|
||||
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as they stamp \the [P] with \a [S]!")
|
||||
npcDrop(P, 1)
|
||||
return
|
||||
|
||||
// stamp a paper in the world
|
||||
for(var/obj/item/paper/A in rangeCheck)
|
||||
if(!A.stamped || !A.stamped.len)
|
||||
if(!Adjacent(A))
|
||||
tryWalk(A)
|
||||
else
|
||||
A.stamp(S)
|
||||
custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as they stamp \the [A] with \a [S]!")
|
||||
return
|
||||
@@ -1,960 +0,0 @@
|
||||
/*
|
||||
NPC VAR EXPLANATIONS (for modules and other things)
|
||||
|
||||
doing = their current action, SNPC_INTERACTING, SNPC_TRAVEL or SNPC_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
|
||||
*/
|
||||
/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/atom/TARGET = null
|
||||
var/atom/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/card/id/MYID
|
||||
var/obj/item/card/id/RPID // the "real" idea they use
|
||||
var/obj/item/pda/MYPDA
|
||||
var/obj/item/main_hand
|
||||
var/obj/item/other_hand
|
||||
var/TRAITS = 0
|
||||
var/obj/item/card/id/Path_ID
|
||||
var/default_job = /datum/job/civilian // the type for the default job
|
||||
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 = SNPC_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/forceProcess = 0
|
||||
var/speak_file = "npc_chatter.json"
|
||||
var/debugexamine = FALSE //If we show debug info in our examine
|
||||
var/showexaminetext = TRUE //If we show our telltale examine text
|
||||
|
||||
var/voice_saved = FALSE
|
||||
|
||||
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()
|
||||
if(voice_saved)
|
||||
return
|
||||
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)
|
||||
change_eye_color(255, 0, 0)
|
||||
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)
|
||||
change_gender(pick("male", "female"))
|
||||
rename_character(real_name, dna.species.get_random_name(gender))
|
||||
//job handling
|
||||
myjob = new default_job()
|
||||
job = myjob.title
|
||||
mind.assigned_role = job
|
||||
myjob.equip(src)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/reset()
|
||||
walk(src, 0)
|
||||
timeout = 100
|
||||
retal = 0
|
||||
doing = 0
|
||||
inactivity_period = 0
|
||||
|
||||
/client/proc/resetSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing)
|
||||
set name = "Reset SNPC"
|
||||
set desc = "Reset the SNPC"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
if(istype(T))
|
||||
T.reset()
|
||||
|
||||
/client/proc/customiseSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing)
|
||||
set name = "Customize SNPC"
|
||||
set desc = "Customize the SNPC"
|
||||
set category = "Debug"
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
if(!istype(T))
|
||||
return
|
||||
|
||||
var/list/jobs[0]
|
||||
for(var/datum/job/j in SSjobs.occupations)
|
||||
if(j.title != "AI" && j.title != "Cyborg")
|
||||
jobs[j.title] = j
|
||||
jobs = sortAssoc(jobs)
|
||||
var/job_name = input("Choose Job") as null|anything in jobs
|
||||
|
||||
if(job_name)
|
||||
var/datum/job/cjob = jobs[job_name]
|
||||
var/alt_title = input("Choose Alt Title") in (list(job_name) + cjob.alt_titles)
|
||||
|
||||
T.myjob = cjob
|
||||
T.job = cjob.title
|
||||
T.mind.assigned_role = cjob.title
|
||||
for(var/obj/item/I in T)
|
||||
if(istype(I, /obj/item/implant))
|
||||
continue
|
||||
if(istype(I, /obj/item/organ))
|
||||
continue
|
||||
qdel(I)
|
||||
T.myjob.equip(T)
|
||||
T.doSetup(alt_title)
|
||||
|
||||
var/shouldDoppel = input("Do you want the SNPC to disguise themself as a crewmember?") as anything in list("Yes", "No")
|
||||
if(shouldDoppel == "Yes")
|
||||
var/list/validchoices = list()
|
||||
for(var/mob/living/carbon/human/M in GLOB.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
|
||||
T.set_species(chosen.dna.species.type)
|
||||
T.dna = toDoppel.Clone()
|
||||
T.body_accessory = chosen.body_accessory
|
||||
T.UpdateAppearance()
|
||||
domutcheck(T)
|
||||
|
||||
var/doTrait = input("Do you want the SNPC to be a traitor?") as anything in list("Yes", "No")
|
||||
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 anything in list("Yes", "No")
|
||||
if(doTele == "Yes")
|
||||
T.loc = pick(get_area_turfs(T.job2area(T.myjob)))
|
||||
|
||||
T.revive()
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/doSetup(alt_title = null)
|
||||
Path_ID = new /obj/item/card/id(src)
|
||||
|
||||
var/datum/job/captain/C = new/datum/job/captain
|
||||
Path_ID.access = C.get_access()
|
||||
|
||||
if(!alt_title)
|
||||
alt_title = job
|
||||
|
||||
MYID = new(src)
|
||||
MYID.name = "[real_name]'s ID Card ([alt_title])"
|
||||
MYID.assignment = "[alt_title]"
|
||||
MYID.rank = job
|
||||
MYID.sex = capitalize(gender)
|
||||
MYID.age = age
|
||||
MYID.registered_name = real_name
|
||||
MYID.photo = get_id_photo(src)
|
||||
MYID.access = Path_ID.access.Copy() // Automatons have strange powers... strange indeed
|
||||
|
||||
RPID = new(src)
|
||||
RPID.name = "[real_name]'s ID Card ([alt_title])"
|
||||
RPID.assignment = "[alt_title]"
|
||||
RPID.rank = job
|
||||
RPID.sex = capitalize(gender)
|
||||
RPID.age = age
|
||||
RPID.registered_name = real_name
|
||||
RPID.photo = get_id_photo(src)
|
||||
RPID.access = myjob.get_access()
|
||||
|
||||
if(wear_id)
|
||||
qdel(wear_id)
|
||||
if(!equip_to_slot_or_del(MYID, slot_wear_id))
|
||||
create_attack_log("<font color='blue'>Deleted ID due to slot contention</font>")
|
||||
if(wear_pda)
|
||||
MYPDA = wear_pda
|
||||
else
|
||||
MYPDA = new(src)
|
||||
equip_to_slot_or_del(MYPDA, slot_wear_pda)
|
||||
MYPDA.owner = real_name
|
||||
MYPDA.ownjob = alt_title
|
||||
MYPDA.ownrank = job
|
||||
MYPDA.name = "PDA-[real_name] ([alt_title])"
|
||||
zone_sel.selecting = "chest"
|
||||
//arms
|
||||
if(prob((SNPC_FUZZY_CHANCE_LOW+SNPC_FUZZY_CHANCE_HIGH)/4))
|
||||
var/obj/item/organ/external/R = bodyparts_by_name["r_arm"]
|
||||
if(R)
|
||||
R.robotize(make_tough = 1)
|
||||
else
|
||||
var/obj/item/organ/external/L = bodyparts_by_name["l_arm"]
|
||||
if(L)
|
||||
L.robotize(make_tough = 1)
|
||||
//legs
|
||||
if(prob((SNPC_FUZZY_CHANCE_LOW+SNPC_FUZZY_CHANCE_HIGH)/4))
|
||||
var/obj/item/organ/external/R = bodyparts_by_name["r_leg"]
|
||||
if(R)
|
||||
R.robotize(make_tough = 1)
|
||||
else
|
||||
var/obj/item/organ/external/L = bodyparts_by_name["l_leg"]
|
||||
if(L)
|
||||
L.robotize(make_tough = 1)
|
||||
UpdateDamageIcon()
|
||||
regenerate_icons()
|
||||
|
||||
hand = 0
|
||||
functions = list("nearbyscan", "combat", "shitcurity", "chatter") // stop customize adding multiple copies of a function
|
||||
setup_job(job)
|
||||
|
||||
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/InteractiveProcess()
|
||||
if(ticker.current_state == GAME_STATE_FINISHED)
|
||||
saveVoice()
|
||||
voice_saved = TRUE
|
||||
doProcess()
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/setup_job(thejob)
|
||||
switch(thejob)
|
||||
if("Civilian")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item)
|
||||
if("Captain", "Head of Personnel")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item/stamp/captain,/obj/item/disk/nuclear)
|
||||
if("Nanotrasen Representative")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item/stamp/centcom, /obj/item/paper, /obj/item/melee/classic_baton/ntcane)
|
||||
functions += "paperwork"
|
||||
if("Magistrate", "Internal Affairs Agent")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item/stamp/law, /obj/item/paper)
|
||||
functions += "paperwork"
|
||||
if("Quartermaster", "Cargo Technician")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item/stamp/granted, /obj/item/stamp/denied, /obj/item/paper, /obj/item/clipboard)
|
||||
functions += "stamping"
|
||||
if("Chef")
|
||||
favoured_types = list(/obj/item/reagent_containers/food, /obj/item/kitchen)
|
||||
functions += "souschef"
|
||||
restrictedJob = 1
|
||||
if("Bartender")
|
||||
favoured_types = list(/obj/item/reagent_containers/food, /obj/item/kitchen)
|
||||
functions += "bartend"
|
||||
restrictedJob = 1
|
||||
if("Station Engineer", "Chief Engineer", "Life Support Specialist", "Mechanic")
|
||||
favoured_types = list(/obj/item/stack, /obj/item, /obj/item/clothing)
|
||||
if("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Geneticist", "Psychiatrist", "Paramedic", "Brig Physician")
|
||||
favoured_types = list(/obj/item/reagent_containers/glass/beaker, /obj/item/storage/firstaid, /obj/item/stack/medical, /obj/item/reagent_containers/syringe)
|
||||
functions += "healpeople"
|
||||
if("Research Director", "Scientist", "Roboticist")
|
||||
favoured_types = list(/obj/item/reagent_containers/glass/beaker, /obj/item/stack, /obj/item/reagent_containers)
|
||||
if("Head of Security", "Warden", "Security Officer", "Detective", "Security Pod Pilot", "Blueshield")
|
||||
favoured_types = list(/obj/item/clothing, /obj/item, /obj/item/restraints)
|
||||
if("Janitor")
|
||||
favoured_types = list(/obj/item/mop, /obj/item/reagent_containers/glass/bucket, /obj/item/reagent_containers/spray/cleaner, /obj/effect/decal/cleanable)
|
||||
functions += "dojanitor"
|
||||
if("Clown")
|
||||
favoured_types = list(/obj/item/soap, /obj/item/reagent_containers/food/snacks/grown/banana, /obj/item/grown/bananapeel)
|
||||
functions += "clowning"
|
||||
if("Botanist")
|
||||
favoured_types = list(/obj/machinery/hydroponics, /obj/item/reagent_containers, /obj/item)
|
||||
functions += "botany"
|
||||
restrictedJob = 1
|
||||
else
|
||||
favoured_types = list(/obj/item/clothing)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/makeTraitor(var/inPers)
|
||||
isTraitor = 1
|
||||
traitorScale = (slyness + smartness) + rand(-10,10)
|
||||
traitorType = inPers
|
||||
|
||||
ticker.mode.traitors += mind
|
||||
mind.special_role = SPECIAL_ROLE_TRAITOR
|
||||
var/datum/mindslaves/slaved = new()
|
||||
slaved.masters += mind
|
||||
mind.som = slaved
|
||||
ticker.mode.update_traitor_icons_added(mind)
|
||||
|
||||
switch(traitorType)
|
||||
if(SNPC_BRUTE) // SMASH KILL RAAARGH
|
||||
var/datum/objective/assassinate/A = new
|
||||
A.owner = mind
|
||||
A.find_target()
|
||||
mind.objectives += A
|
||||
traitorTarget = A.target.current
|
||||
if(SNPC_STEALTH) // Shhh we is sneekies
|
||||
var/datum/objective/steal/S = new
|
||||
S.owner = mind
|
||||
S.find_target()
|
||||
mind.objectives += S
|
||||
traitorTarget = locate(S.steal_target.typepath) 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
|
||||
var/datum/objective/O = new("Destroy \the [traitorTarget].")
|
||||
O.owner = mind
|
||||
mind.objectives += O
|
||||
if(SNPC_PSYCHO) // YOU'RE LIKE A FLESH BICYLE AND I WANT TO DISMANTLE YOU
|
||||
var/datum/objective/hijack/H = new
|
||||
H.owner = mind
|
||||
mind.objectives += H
|
||||
traitorTarget = null
|
||||
|
||||
functions += "traitor"
|
||||
faction -= "neutral"
|
||||
faction += "hostile"
|
||||
|
||||
/mob/living/carbon/human/interactive/create_mob_hud()
|
||||
if(!hud_used)
|
||||
hud_used = new /datum/hud/human(src)
|
||||
|
||||
/mob/living/carbon/human/interactive/Initialize()
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/mob/living/carbon/human/interactive/LateInitialize()
|
||||
. = ..()
|
||||
GLOB.snpc_list += src
|
||||
|
||||
create_mob_hud()
|
||||
|
||||
sync_mind()
|
||||
random()
|
||||
doSetup()
|
||||
START_PROCESSING(SSnpcpool, src)
|
||||
loadVoice()
|
||||
GLOB.hear_radio_list += src
|
||||
|
||||
// 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/Destroy()
|
||||
SSnpcpool.stop_processing(src)
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/retalTarget(mob/living/target)
|
||||
var/mob/living/M = target
|
||||
if(istype(M))
|
||||
if(health > 0)
|
||||
if(M.a_intent == INTENT_HELP && !incapacitated())
|
||||
chatter()
|
||||
if(istype(target, /mob/living/carbon) && !retal && prob(SNPC_FUZZY_CHANCE_LOW))
|
||||
var/mob/living/carbon/C = target
|
||||
if(!Adjacent(target))
|
||||
tryWalk(target)
|
||||
else
|
||||
C.help_shake_act(src)
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
retal = 1
|
||||
retal_target = target
|
||||
|
||||
//Retaliation clauses
|
||||
|
||||
/mob/living/carbon/human/interactive/attacked_by(obj/item/I, mob/living/user, def_zone)
|
||||
..()
|
||||
retalTarget(user)
|
||||
|
||||
/mob/living/carbon/human/interactive/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
..()
|
||||
var/mob/living/carbon/C = locate(/mob/living/carbon) in view(SNPC_MIN_RANGE_FIND, src)
|
||||
if(C)
|
||||
retalTarget(C)
|
||||
|
||||
/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P)
|
||||
..()
|
||||
retalTarget(P.firer)
|
||||
|
||||
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
|
||||
..()
|
||||
retalTarget(M)
|
||||
|
||||
/mob/living/carbon/human/interactive/show_inv(mob/user)
|
||||
..()
|
||||
retalTarget(user)
|
||||
|
||||
/mob/living/carbon/human/interactive/can_inject(mob/user, error_msg, target_zone, var/penetrate_thick = 0)
|
||||
..()
|
||||
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 & SNPC_INTERACTING)
|
||||
toReturn += "interacting with something, "
|
||||
if(doin & SNPC_FIGHTING)
|
||||
toReturn += "engaging in combat, "
|
||||
if(doin & SNPC_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(slot_l_store, slot_r_store, slot_l_hand, slot_r_hand)
|
||||
var/obj/item/I = get_item_by_slot(pick(slots))
|
||||
var/obj/item/storage/BP = get_item_by_slot(slot_back)
|
||||
if(back && BP && I)
|
||||
// hack to allow SNPCs to "sticky grab" items without losing their inventorying
|
||||
var/oldnodrop = I.flags | NODROP
|
||||
I.flags &= ~NODROP
|
||||
if(BP.can_be_inserted(I))
|
||||
BP.handle_item_insertion(I)
|
||||
I.flags |= oldnodrop
|
||||
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/death()
|
||||
// Only execute the below if we successfully died
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
saveVoice()
|
||||
|
||||
/mob/living/carbon/human/interactive/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol)
|
||||
if(!istype(speaker, /mob/living/carbon/human/interactive))
|
||||
knownStrings |= html_decode(multilingual_to_message(message_pieces))
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/interactive/hear_radio(list/message_pieces, verb = "says", part_a, part_b, mob/speaker = null, hard_to_hear = 0, vname = "", atom/follow_target)
|
||||
if(!istype(speaker, /mob/living/carbon/human/interactive))
|
||||
knownStrings |= html_decode(multilingual_to_message(message_pieces))
|
||||
..()
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/doProcess()
|
||||
set waitfor = FALSE
|
||||
if(IsDeadOrIncap())
|
||||
reset()
|
||||
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
|
||||
var/mistake_chance = (100 - smartness) / 2
|
||||
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
|
||||
inactivity_period = 20
|
||||
AL.panel_open = 1
|
||||
AL.update_icon()
|
||||
AL.shock(src, mistake_chance)
|
||||
sleep(5)
|
||||
if(QDELETED(AL))
|
||||
return
|
||||
AL.unlock()
|
||||
if(prob(mistake_chance))
|
||||
if(!AL.wires.IsIndexCut(AIRLOCK_WIRE_DOOR_BOLTS))
|
||||
AL.wires.CutWireIndex(AIRLOCK_WIRE_DOOR_BOLTS)
|
||||
else
|
||||
if(AL.wires.IsIndexCut(AIRLOCK_WIRE_DOOR_BOLTS))
|
||||
AL.wires.CutWireIndex(AIRLOCK_WIRE_DOOR_BOLTS, 1)
|
||||
if(AL.locked)
|
||||
AL.wires.UpdatePulsed(AIRLOCK_WIRE_DOOR_BOLTS)
|
||||
if(!AL.wires.IsIndexCut(AIRLOCK_WIRE_MAIN_POWER1))
|
||||
AL.wires.CutWireIndex(AIRLOCK_WIRE_MAIN_POWER1)
|
||||
if(prob(mistake_chance) && !AL.wires.IsIndexCut(AIRLOCK_WIRE_SAFETY))
|
||||
AL.wires.CutWireIndex(AIRLOCK_WIRE_SAFETY)
|
||||
if(prob(mistake_chance) && !AL.wires.IsIndexCut(AIRLOCK_WIRE_ELECTRIFY))
|
||||
AL.wires.CutWireIndex(AIRLOCK_WIRE_ELECTRIFY)
|
||||
sleep(5)
|
||||
if(QDELETED(AL))
|
||||
return
|
||||
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(grabbed_by.len > 0)
|
||||
for(var/obj/item/grab/G in grabbed_by)
|
||||
if(Adjacent(G))
|
||||
a_intent = INTENT_DISARM
|
||||
G.assailant.attack_hand(src)
|
||||
inactivity_period = 10
|
||||
|
||||
if(buckled)
|
||||
resist()
|
||||
inactivity_period = 10
|
||||
|
||||
//proc functions
|
||||
for(var/Proc in functions)
|
||||
if(!IsDeadOrIncap())
|
||||
INVOKE_ASYNC(src, Proc)
|
||||
|
||||
|
||||
//target interaction stays hardcoded
|
||||
|
||||
if(TARGET && (TARGET in blacklistItems)) // don't use blacklisted items
|
||||
TARGET = null
|
||||
|
||||
if(TARGET && Adjacent(TARGET))
|
||||
doing |= SNPC_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))
|
||||
inactivity_period = 10
|
||||
D.open()
|
||||
var/turf/T = get_step(get_step(D.loc, dir), dir) //recursion yo
|
||||
tryWalk(T)
|
||||
//THIEVING SKILLS
|
||||
insert_into_backpack() // dump random item into backpack to make space
|
||||
//---------ITEMS
|
||||
if(istype(TARGET, /obj/item))
|
||||
var/obj/item/I = TARGET
|
||||
if(I.anchored)
|
||||
TARGET = null
|
||||
else if(istype(TARGET, /obj/item))
|
||||
var/obj/item/W = TARGET
|
||||
if(W.force >= best_force || prob((SNPC_FUZZY_CHANCE_LOW + SNPC_FUZZY_CHANCE_HIGH) / 2) || favouredObjIn(list(W)))
|
||||
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))
|
||||
drop_item()
|
||||
dressup(TARGET)
|
||||
update_hands = 1
|
||||
if(MYPDA in loc)
|
||||
equip_to_appropriate_slot(MYPDA)
|
||||
if(MYID in 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/W = main_hand
|
||||
STR.attackby(W, src)
|
||||
else
|
||||
STR.attack_hand(src)
|
||||
interest += targetInterestShift
|
||||
doing = doing & ~SNPC_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 |= SNPC_TRAVEL
|
||||
if(!isTraitor || !traitorTarget || get_dist(src, traitorTarget) >= SNPC_MAX_RANGE_FIND || get_dist(src, traitorTarget) <= 1)
|
||||
var/choice = rand(1,50)
|
||||
switch(choice)
|
||||
if(1 to 30)
|
||||
//chance to chase an item
|
||||
TARGET = locate(/obj/item) in favouredObjIn(oview(SNPC_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(SNPC_MAX_RANGE_FIND, src, 1))))
|
||||
if(46 to 50)
|
||||
TARGET = pick(target_filter(oview(SNPC_MIN_RANGE_FIND, src)))
|
||||
else
|
||||
TARGET = traitorTarget
|
||||
tryWalk(TARGET)
|
||||
LAST_TARGET = TARGET
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/dressup(obj/item/clothing/C)
|
||||
set waitfor = FALSE
|
||||
inactivity_period = 12
|
||||
sleep(5)
|
||||
if(!QDELETED(C) && !QDELETED(src))
|
||||
take_to_slot(C,1)
|
||||
if(!equip_to_appropriate_slot(C))
|
||||
var/obj/item/I = get_item_by_slot(C)
|
||||
unEquip(I)
|
||||
sleep(5)
|
||||
if(!QDELETED(src) && !QDELETED(C))
|
||||
equip_to_appropriate_slot(C)
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/favouredObjIn(list/inList)
|
||||
var/list/outList = list()
|
||||
for(var/i in inList)
|
||||
for(var/path in favoured_types)
|
||||
if(istype(i, path))
|
||||
outList += i
|
||||
if(!outList.len)
|
||||
outList = inList
|
||||
return outList
|
||||
|
||||
/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, 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, SNPC_MAX_RANGE_FIND + 1, 250,1, id=Path_ID, simulated_only = 0)
|
||||
|
||||
if(myPath)
|
||||
if(myPath.len > 0)
|
||||
doing = doing & ~SNPC_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
|
||||
switch(T.title)
|
||||
if("Civilian", "Paramedic")
|
||||
return /area/hallway/primary
|
||||
if("Captain", "Head of Personnel", "Blueshield")
|
||||
return /area/bridge
|
||||
if("Bartender")
|
||||
return /area/crew_quarters/bar
|
||||
if("Chef")
|
||||
return /area/crew_quarters/kitchen
|
||||
if("Station Engineer", "Chief Engineer", "Mechanic")
|
||||
return /area/engine
|
||||
if("Life Support Specialist")
|
||||
return /area/atmos
|
||||
if("Chief Medical Officer", "Medical Doctor", "Chemist", "Virologist", "Psychiatrist")
|
||||
return /area/medical
|
||||
if("Geneticist")
|
||||
return /area/medical/genetics
|
||||
if("Research Director", "Scientist")
|
||||
return /area/toxins
|
||||
if("Roboticist")
|
||||
return /area/assembly/robotics
|
||||
if("Head of Security", "Warden", "Security Officer", "Detective", "Security Pod Pilot", "Brig Physician", "Magistrate", "Internal Affairs Agent")
|
||||
return /area/security
|
||||
if("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/lighting_overlay, /obj/structure/cable, /obj/machinery/atmospherics, /obj/item/radio/intercom)
|
||||
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 & (SNPC_FIGHTING | SNPC_SPECIAL))
|
||||
return 1
|
||||
if(retal)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/getAllContents()
|
||||
var/list/allContents = list()
|
||||
for(var/atom/A in contents)
|
||||
allContents += A
|
||||
if(A.contents.len)
|
||||
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) && validHome.len)
|
||||
tryWalk(pick(get_area_turfs(job2area(myjob))))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/npcDrop(obj/item/A, blacklist = 0)
|
||||
if(blacklist)
|
||||
blacklistItems += A
|
||||
unEquip(A)
|
||||
enforce_hands()
|
||||
update_icons()
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/compareFaction(list/targetFactions)
|
||||
var/hasSame = 0
|
||||
|
||||
for(var/A in targetFactions)
|
||||
if(A in faction)
|
||||
hasSame = 1
|
||||
|
||||
return hasSame
|
||||
|
||||
/mob/living/carbon/human/interactive/proc/nearbyscan(obj)
|
||||
nearby = list()
|
||||
for(var/mob/living/M in view(4,src))
|
||||
if(M != src)
|
||||
nearby += M
|
||||
|
||||
/mob/living/carbon/human/interactive/rename_character(oldname, newname)
|
||||
if(!..())
|
||||
return 0
|
||||
|
||||
if(oldname)
|
||||
if(MYID)
|
||||
MYID.registered_name = newname
|
||||
MYID.name = "[newname]'s ID Card ([MYID.assignment])"
|
||||
if(RPID)
|
||||
RPID.registered_name = MYID.registered_name
|
||||
RPID.name = MYID.name
|
||||
return 1
|
||||
@@ -1,24 +0,0 @@
|
||||
/mob/living/carbon/human/interactive/angry/Initialize(mapload)
|
||||
TRAITS |= TRAIT_ROBUST
|
||||
TRAITS |= TRAIT_MEAN
|
||||
faction += "bot_angry"
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/interactive/friendly/Initialize(mapload)
|
||||
TRAITS |= TRAIT_FRIENDLY
|
||||
TRAITS |= TRAIT_UNROBUST
|
||||
faction += "bot_friendly"
|
||||
faction += "neutral"
|
||||
functions -= "combat"
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/interactive/greytide/Initialize(mapload)
|
||||
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
|
||||
return ..()
|
||||
@@ -8,6 +8,15 @@
|
||||
return 0
|
||||
var/datum/gas_mixture/environment = loc.return_air()
|
||||
|
||||
if(client || registered_z) // This is a temporary error tracker to make sure we've caught everything
|
||||
var/turf/T = get_turf(src)
|
||||
if(client && registered_z != T.z)
|
||||
message_admins("[src] [ADMIN_FLW(src, "FLW")] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z]. If you could ask them how that happened and notify the coders, it would be appreciated.")
|
||||
log_game("Z-TRACKING: [src] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z].")
|
||||
update_z(T.z)
|
||||
else if (!client && registered_z)
|
||||
log_game("Z-TRACKING: [src] of type [src.type] has a Z-registration despite not having a client.")
|
||||
update_z(null)
|
||||
if(stat != DEAD)
|
||||
//Chemicals in the body
|
||||
handle_chemicals_in_body()
|
||||
|
||||
@@ -953,6 +953,27 @@
|
||||
|
||||
to_chat(src, "<span class='notice'>You can taste [english_list(final_taste_list)].</span>")
|
||||
|
||||
/mob/living/proc/update_z(new_z) // 1+ to register, null to unregister
|
||||
if(registered_z != new_z)
|
||||
if(registered_z)
|
||||
SSmobs.clients_by_zlevel[registered_z] -= src
|
||||
if(client)
|
||||
if(new_z)
|
||||
SSmobs.clients_by_zlevel[new_z] += src
|
||||
for (var/I in length(SSidlenpcpool.idle_mobs_by_zlevel[new_z]) to 1 step -1) //Backwards loop because we're removing (guarantees optimal rather than worst-case performance), it's fine to use .len here but doesn't compile on 511
|
||||
var/mob/living/simple_animal/SA = SSidlenpcpool.idle_mobs_by_zlevel[new_z][I]
|
||||
if (SA)
|
||||
SA.toggle_ai(AI_ON) // Guarantees responsiveness for when appearing right next to mobs
|
||||
else
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[new_z] -= SA
|
||||
registered_z = new_z
|
||||
else
|
||||
registered_z = null
|
||||
|
||||
/mob/living/onTransitZ(old_z,new_z)
|
||||
..()
|
||||
update_z(new_z)
|
||||
|
||||
/mob/living/proc/owns_soul()
|
||||
if(mind)
|
||||
return mind.soulOwner == mind
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
update_stat("mob login")
|
||||
update_sight()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(isturf(T))
|
||||
update_z(T.z)
|
||||
|
||||
//If they're SSD, remove it so they can wake back up.
|
||||
player_logged = 0
|
||||
//Vents
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/mob/living/Logout()
|
||||
update_z(null)
|
||||
if(ranged_ability && client)
|
||||
ranged_ability.remove_mousepointer(client)
|
||||
..()
|
||||
|
||||
@@ -634,7 +634,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["trackbot"])
|
||||
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animal_list
|
||||
var/mob/living/simple_animal/bot/target = locate(href_list["trackbot"]) in GLOB.simple_animals
|
||||
if(target)
|
||||
ai_actual_track(target)
|
||||
else
|
||||
@@ -642,7 +642,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["callbot"]) //Command a bot to move to a selected location.
|
||||
Bot = locate(href_list["callbot"]) in GLOB.simple_animal_list
|
||||
Bot = locate(href_list["callbot"]) in GLOB.simple_animals
|
||||
if(!Bot || Bot.remote_disabled || control_disabled)
|
||||
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
|
||||
waypoint_mode = 1
|
||||
@@ -650,7 +650,7 @@ var/list/ai_verbs_default = list(
|
||||
return
|
||||
|
||||
if(href_list["interface"]) //Remotely connect to a bot!
|
||||
Bot = locate(href_list["interface"]) in GLOB.simple_animal_list
|
||||
Bot = locate(href_list["interface"]) in GLOB.simple_animals
|
||||
if(!Bot || Bot.remote_disabled || control_disabled)
|
||||
return
|
||||
Bot.attack_ai(src)
|
||||
@@ -746,7 +746,7 @@ var/list/ai_verbs_default = list(
|
||||
d += "<A HREF=?src=[UID()];botrefresh=\ref[Bot]>Query network status</A><br>"
|
||||
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='20%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
|
||||
|
||||
for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animal_list)
|
||||
for(var/mob/living/simple_animal/bot/Bot in GLOB.simple_animals)
|
||||
if(is_ai_allowed(Bot.z) && !Bot.remote_disabled) //Only non-emagged bots on the allowed Z-level are detected!
|
||||
bot_area = get_area(Bot)
|
||||
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!) </span>[Bot.name]" : Bot.name] ([Bot.model])</td>"
|
||||
|
||||
@@ -451,7 +451,7 @@
|
||||
response_harm = "kicks"
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_INVALID
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Ian/process_ai()
|
||||
/mob/living/simple_animal/pet/corgi/Ian/Life()
|
||||
..()
|
||||
|
||||
//Feeding, chasing food, FOOOOODDDD
|
||||
@@ -578,7 +578,7 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/process_ai()
|
||||
/mob/living/simple_animal/pet/corgi/Lisa/Life()
|
||||
..()
|
||||
|
||||
make_babies()
|
||||
|
||||
@@ -54,9 +54,8 @@
|
||||
else if(prob(5))
|
||||
emote("snuffles")
|
||||
|
||||
/mob/living/simple_animal/mouse/process_ai()
|
||||
/mob/living/simple_animal/mouse/Life()
|
||||
..()
|
||||
|
||||
if(prob(0.5))
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "mouse_[mouse_color]_sleep"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
see_in_dark = 5
|
||||
gold_core_spawnable = CHEM_MOB_SPAWN_FRIENDLY
|
||||
|
||||
/mob/living/simple_animal/pet/pug/process_ai()
|
||||
/mob/living/simple_animal/pet/pug/Life()
|
||||
..()
|
||||
|
||||
if(!resting && !buckled)
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
var/stat_exclusive = 0 //Mobs with this set to 1 will exclusively attack things defined by stat_attack, stat_attack 2 means they will only attack corpses
|
||||
var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction
|
||||
|
||||
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
|
||||
|
||||
//typecache of things this mob will attack in DestroySurroundings() if it has environment_smash
|
||||
var/list/environment_target_typecache = list(
|
||||
/obj/machinery/door/window,
|
||||
@@ -66,12 +64,6 @@
|
||||
walk(src, 0)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/process_ai()
|
||||
..()
|
||||
if(!AICanContinue())
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/handle_automated_action()
|
||||
if(AIStatus == AI_OFF)
|
||||
return 0
|
||||
@@ -83,7 +75,7 @@
|
||||
DestroySurroundings()
|
||||
if(!MoveToTarget(possible_targets)) //if we lose our target
|
||||
if(AIShouldSleep(possible_targets)) // we try to acquire a new one
|
||||
AIStatus = AI_IDLE // otherwise we go idle
|
||||
toggle_ai(AI_IDLE) // otherwise we go idle
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user)
|
||||
@@ -264,8 +256,8 @@
|
||||
if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight
|
||||
search_objects = 0
|
||||
target = null
|
||||
if(AIStatus == AI_IDLE)
|
||||
AIStatus = AI_ON
|
||||
if(AIStatus != AI_ON && AIStatus != AI_OFF)
|
||||
toggle_ai(AI_ON)
|
||||
FindTarget()
|
||||
else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
|
||||
FindTarget()
|
||||
@@ -401,9 +393,43 @@
|
||||
if(AI_IDLE)
|
||||
if(FindTarget(possible_targets, 1))
|
||||
. = 1
|
||||
AIStatus = AI_ON //Wake up for more than one Life() cycle.
|
||||
toggle_ai(AI_ON) //Wake up for more than one Life() cycle.
|
||||
else
|
||||
. = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/AIShouldSleep(var/list/possible_targets)
|
||||
return !FindTarget(possible_targets, 1)
|
||||
|
||||
/mob/living/simple_animal/hostile/consider_wakeup()
|
||||
..()
|
||||
var/list/tlist
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
|
||||
if(!length(SSmobs.clients_by_zlevel[T.z])) // It's fine to use .len here but doesn't compile on 511
|
||||
toggle_ai(AI_Z_OFF)
|
||||
return
|
||||
|
||||
var/cheap_search = isturf(T) && !(T.z == 1) // The original check for SSmapping's station z level trait, unfortunately it isn't here.
|
||||
if(cheap_search)
|
||||
tlist = ListTargetsLazy(T.z)
|
||||
else
|
||||
tlist = ListTargets()
|
||||
|
||||
if(AIStatus == AI_IDLE && FindTarget(tlist, 1))
|
||||
if(cheap_search) //Try again with full effort
|
||||
FindTarget()
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/hostile/proc/ListTargetsLazy(var/_Z)//Step 1, find out what we can see
|
||||
var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/spacepod))
|
||||
. = list()
|
||||
for(var/I in SSmobs.clients_by_zlevel[_Z])
|
||||
var/mob/M = I
|
||||
if(get_dist(M, src) < vision_range)
|
||||
if(isturf(M.loc))
|
||||
. += M
|
||||
else if(M.loc.type in hostile_machines)
|
||||
. += M.loc
|
||||
@@ -142,7 +142,7 @@
|
||||
var/pre_attack = 0
|
||||
loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1})
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/process_ai()
|
||||
/mob/living/simple_animal/hostile/asteroid/goliath/Life()
|
||||
..()
|
||||
handle_preattack()
|
||||
|
||||
|
||||
@@ -80,10 +80,14 @@
|
||||
var/deathmessage = ""
|
||||
var/death_sound = null //The sound played on death
|
||||
|
||||
var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever)
|
||||
var/can_have_ai = TRUE //once we have become sentient, we can never go back
|
||||
var/shouldwakeup = FALSE //convenience var for forcibly waking up an idling AI on next check.
|
||||
|
||||
|
||||
/mob/living/simple_animal/Initialize()
|
||||
..()
|
||||
GLOB.simple_animal_list += src
|
||||
GLOB.simple_animals[AIStatus] += src
|
||||
verbs -= /mob/verb/observe
|
||||
if(!can_hide)
|
||||
verbs -= /mob/living/simple_animal/verb/hide
|
||||
@@ -97,7 +101,18 @@
|
||||
collar.forceMove(loc)
|
||||
collar = null
|
||||
master_commander = null
|
||||
GLOB.simple_animal_list -= src
|
||||
GLOB.simple_animals[AIStatus] -= src
|
||||
if(SSnpcpool.state == SS_PAUSED && LAZYLEN(SSnpcpool.currentrun))
|
||||
SSnpcpool.currentrun -= src
|
||||
|
||||
if(nest)
|
||||
nest.spawned_mobs -= src
|
||||
nest = null
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if (T && AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/Login()
|
||||
@@ -111,12 +126,6 @@
|
||||
health = Clamp(health, 0, maxHealth)
|
||||
med_hud_set_status()
|
||||
|
||||
|
||||
/mob/living/simple_animal/proc/process_ai()
|
||||
handle_automated_movement()
|
||||
handle_automated_action()
|
||||
handle_automated_speech()
|
||||
|
||||
/mob/living/simple_animal/lay_down()
|
||||
..()
|
||||
handle_resting_state_icons()
|
||||
@@ -562,6 +571,8 @@
|
||||
/* End Inventory */
|
||||
|
||||
/mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion
|
||||
toggle_ai(AI_OFF)
|
||||
can_have_ai = FALSE
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/update_sight()
|
||||
@@ -581,4 +592,37 @@
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/can_hear()
|
||||
. = TRUE
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/proc/consider_wakeup()
|
||||
if(pulledby || shouldwakeup)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(!ckey && !stat)//Not unconscious
|
||||
if(AIStatus == AI_IDLE)
|
||||
toggle_ai(AI_ON)
|
||||
|
||||
/mob/living/simple_animal/proc/toggle_ai(togglestatus)
|
||||
if(!can_have_ai && (togglestatus != AI_OFF))
|
||||
return
|
||||
if(AIStatus != togglestatus)
|
||||
if(togglestatus > 0 && togglestatus < 5)
|
||||
if(togglestatus == AI_Z_OFF || AIStatus == AI_Z_OFF)
|
||||
var/turf/T = get_turf(src)
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] -= src
|
||||
else
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[T.z] += src
|
||||
GLOB.simple_animals[AIStatus] -= src
|
||||
GLOB.simple_animals[togglestatus] += src
|
||||
AIStatus = togglestatus
|
||||
else
|
||||
stack_trace("Something attempted to set simple animals AI to an invalid state: [togglestatus]")
|
||||
|
||||
/mob/living/simple_animal/onTransitZ(old_z, new_z)
|
||||
..()
|
||||
if(AIStatus == AI_Z_OFF)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[old_z] -= src
|
||||
toggle_ai(initial(AIStatus))
|
||||
@@ -29,7 +29,7 @@
|
||||
spawned_mobs = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/spawner/process_ai()
|
||||
/mob/living/simple_animal/hostile/spawner/Life()
|
||||
..()
|
||||
spawn_mob()
|
||||
|
||||
|
||||
@@ -202,3 +202,4 @@
|
||||
var/list/tkgrabbed_objects = list() // Assoc list of items to TK grabs
|
||||
|
||||
var/forced_look = null // This can either be a numerical direction or a soft object reference (UID). It makes the mob always face towards the selected thing.
|
||||
var/registered_z
|
||||
@@ -193,7 +193,7 @@
|
||||
close_spawn_windows()
|
||||
var/obj/O = locate("landmark*Observer-Start")
|
||||
to_chat(src, "<span class='notice'>Now teleporting.</span>")
|
||||
observer.loc = O.loc
|
||||
observer.forceMove(O.loc)
|
||||
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
|
||||
client.prefs.update_preview_icon(1)
|
||||
observer.icon = client.prefs.preview_icon
|
||||
@@ -344,27 +344,27 @@
|
||||
else if(IsSyndicateCommand(rank))
|
||||
character.loc = pick(syndicateofficer)
|
||||
else
|
||||
character.loc = pick(aroomwarp)
|
||||
character.forceMove(pick(aroomwarp))
|
||||
join_message = "has arrived"
|
||||
else
|
||||
if(spawning_at)
|
||||
S = spawntypes[spawning_at]
|
||||
if(S && istype(S))
|
||||
if(S.check_job_spawning(rank))
|
||||
character.loc = pick(S.turfs)
|
||||
character.forceMove(pick(S.turfs))
|
||||
join_message = S.msg
|
||||
else
|
||||
to_chat(character, "Your chosen spawnpoint ([S.display_name]) is unavailable for your chosen job. Spawning you at the Arrivals shuttle instead.")
|
||||
character.loc = pick(latejoin)
|
||||
character.forceMove(pick(latejoin))
|
||||
join_message = "has arrived on the station"
|
||||
else
|
||||
character.loc = pick(latejoin)
|
||||
character.forceMove(pick(latejoin))
|
||||
join_message = "has arrived on the station"
|
||||
|
||||
character.lastarea = get_area(loc)
|
||||
// Moving wheelchair if they have one
|
||||
if(character.buckled && istype(character.buckled, /obj/structure/chair/wheelchair))
|
||||
character.buckled.loc = character.loc
|
||||
character.buckled.forceMove(character.loc)
|
||||
character.buckled.dir = character.dir
|
||||
|
||||
character = SSjobs.EquipRank(character, rank, 1) //equips the human
|
||||
|
||||
Reference in New Issue
Block a user