diff --git a/code/controllers/Processes/npcai.dm b/code/controllers/Processes/npcai.dm index 1f8d2a34e9e..a93c6e881de 100644 --- a/code/controllers/Processes/npcai.dm +++ b/code/controllers/Processes/npcai.dm @@ -2,7 +2,6 @@ var/global/datum/controller/process/npcai/npcai_master /datum/controller/process/npcai var/current_cycle - var/saved_voice = 0 /datum/controller/process/npcai/setup() name = "npc ai" @@ -36,25 +35,6 @@ var/global/datum/controller/process/npcai/npcai_master catchBadType(M) simple_animal_list -= M - if(ticker.current_state == GAME_STATE_FINISHED && !saved_voice) - var/mob/living/carbon/human/interactive/M = safepick(snpc_list) - if(M) - M.saveVoice() - saved_voice = 1 - - for(last_object in snpc_list) - var/mob/living/carbon/human/interactive/M = last_object - if(istype(M) && !QDELETED(M)) - try - if(!M.alternateProcessing || M.forceProcess) - M.doProcess() - catch(var/exception/e) - catchException(e, M) - SCHECK - else - catchBadType(M) - snpc_list -= M - current_cycle++ diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index 8513fbfdaad..27c8141dfc3 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -1,3 +1,7 @@ +#define PROCESSING_NPCS 0 +#define PROCESSING_DELEGATES 1 +#define PROCESSING_ASSISTANTS 2 + SUBSYSTEM_DEF(npcpool) name = "NPC Pool" flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND @@ -5,21 +9,24 @@ SUBSYSTEM_DEF(npcpool) runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME var/list/canBeUsed = list() - var/list/canBeUsed_non = list() var/list/needsDelegate = list() var/list/needsAssistant = list() - var/list/needsHelp_non = list() - var/list/botPool_l = list() //list of all npcs using the pool - var/list/botPool_l_non = list() //list of all non SNPC mobs using the pool + + var/list/processing = list() + var/list/currentrun = list() + var/stage -/datum/controller/subsystem/npcpool/proc/insertBot(toInsert) - if(istype(toInsert, /mob/living/carbon/human/interactive)) - botPool_l |= toInsert +/datum/controller/subsystem/npcpool/stat_entry() + ..("NPCS:[processing.len]|D:[needsDelegate.len]|A:[needsAssistant.len]|U:[canBeUsed.len]") -/datum/controller/subsystem/npcpool/proc/removeBot(toRemove) - botPool_l -= toRemove +/datum/controller/subsystem/npcpool/proc/stop_processing(mob/living/carbon/human/interactive/I) + processing -= I + currentrun -= I + needsDelegate -= I + canBeUsed -= I + needsAssistant -= I -/datum/controller/subsystem/npcpool/fire() +/datum/controller/subsystem/npcpool/fire(resumed = FALSE) //bot delegation and coordination systems //General checklist/Tasks for delegating a task or coordinating it (for SNPCs) // 1. Bot proximity to task target: if too far, delegate, if close, coordinate @@ -28,70 +35,93 @@ SUBSYSTEM_DEF(npcpool) // 4. Process coordination: if a bot(or bots) has been asked to coordinate, assign them to help. // 5. Do all assignments: goes through the delegated/coordianted bots and assigns the right variables/tasks to them. - listclearnulls(canBeUsed) + if (!resumed) + src.currentrun = processing.Copy() + stage = PROCESSING_NPCS + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + var/list/canBeUsed = src.canBeUsed - //SNPC handling - for(var/mob/living/carbon/human/interactive/check in botPool_l) - if(!check) - botPool_l -= check - continue - var/checkInRange = view(SNPC_MAX_RANGE_FIND, check) - if(!(locate(check.TARGET) in checkInRange)) - needsDelegate |= check + if(stage == PROCESSING_NPCS) + while(currentrun.len) + var/mob/living/carbon/human/interactive/thing = currentrun[currentrun.len] + --currentrun.len - else if(check.IsDeadOrIncap(0)) - needsDelegate |= check + thing.InteractiveProcess() - else if(check.doing & SNPC_FIGHTING) - needsAssistant |= check + var/checkInRange = view(SNPC_MAX_RANGE_FIND,thing) + if(thing.IsDeadOrIncap(FALSE) || !(locate(thing.TARGET) in checkInRange)) + needsDelegate += thing + else if(thing.doing & SNPC_FIGHTING) + needsAssistant += thing + else + canBeUsed += thing - else - canBeUsed |= check + if (MC_TICK_CHECK) + return + stage = PROCESSING_DELEGATES + currentrun = needsDelegate //localcache + src.currentrun = currentrun - if(needsDelegate.len) - needsDelegate -= pick(needsDelegate) // cheapo way to make sure stuff doesn't pingpong around in the pool forever. delegation runs seperately to each loop so it will work much smoother + if(stage == PROCESSING_DELEGATES) + while(currentrun.len && canBeUsed.len) + var/mob/living/carbon/human/interactive/check = currentrun[currentrun.len] + var/mob/living/carbon/human/interactive/candidate = canBeUsed[canBeUsed.len] + --currentrun.len - for(var/mob/living/carbon/human/interactive/check in needsDelegate) - if(!check) - needsDelegate -= check - continue - if(canBeUsed.len) - var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed) - var/facCount = 0 - var/helpProb = 0 - for(var/C in check.faction) - for(var/D in candidate.faction) - if(D == C) - helpProb = min(100, helpProb + 25) - facCount++ - if(facCount == 1 && helpProb > 0) - helpProb = 100 - if(prob(helpProb)) - if(candidate.takeDelegate(check)) - needsDelegate -= check - canBeUsed -= candidate - candidate.change_eye_color(255, 0, 0) + var/helpProb = 0 + var/list/chfac = check.faction + var/list/canfac = candidate.faction + var/facCount = LAZYLEN(chfac) * LAZYLEN(canfac) - if(needsAssistant.len) - needsAssistant -= pick(needsAssistant) + for(var/C in chfac) + if(C in canfac) + helpProb = min(100,helpProb + 25) + if(helpProb >= 100) + break - for(var/mob/living/carbon/human/interactive/check in needsAssistant) - if(!check) - needsAssistant -= check - continue - if(canBeUsed.len) - var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed) - var/facCount = 0 - var/helpProb = 0 - for(var/C in check.faction) - for(var/D in candidate.faction) - if(D == C) - helpProb = min(100, helpProb + 25) - facCount++ - if(facCount == 1 && helpProb > 0) - helpProb = 100 - if(prob(helpProb)) - if(candidate.takeDelegate(check, 0)) - needsAssistant -= check - canBeUsed -= candidate - candidate.change_eye_color(255, 255, 0) + if(facCount == 1 && helpProb) + helpProb = 100 + + if(prob(helpProb) && candidate.takeDelegate(check)) + --canBeUsed.len + candidate.change_eye_color(255, 0, 0) + candidate.update_icons() + + if(MC_TICK_CHECK) + return + stage = PROCESSING_ASSISTANTS + currentrun = needsAssistant //localcache + src.currentrun = currentrun + + //no need for the stage check + + while(currentrun.len && canBeUsed.len) + var/mob/living/carbon/human/interactive/check = currentrun[currentrun.len] + var/mob/living/carbon/human/interactive/candidate = canBeUsed[canBeUsed.len] + --currentrun.len + + var/helpProb = 0 + var/list/chfac = check.faction + var/list/canfac = candidate.faction + var/facCount = LAZYLEN(chfac) * LAZYLEN(canfac) + + for(var/C in chfac) + if(C in canfac) + helpProb = min(100,helpProb + 25) + if(helpProb >= 100) + break + + if(facCount == 1 && helpProb) + helpProb = 100 + + if(prob(helpProb) && candidate.takeDelegate(check,FALSE)) + --canBeUsed.len + candidate.change_eye_color(255, 255, 0) + candidate.update_icons() + + if(!currentrun.len || MC_TICK_CHECK) //don't change SS state if it isn't necessary + return + +/datum/controller/subsystem/npcpool/Recover() + processing = SSnpcpool.processing \ No newline at end of file diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 4e9380e2fed..e87a411f8ce 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -85,7 +85,7 @@ debug_variables(SSmobs) feedback_add_details("admin_verb","DMob") if("NPC AI") - debug_variables(npcai_master) + debug_variables(SSnpcai) feedback_add_details("admin_verb","DNPCAI") if("Shuttle") debug_variables(shuttle_master) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index dae563c7e19..81fa11d6e72 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -213,7 +213,6 @@ var/list/admin_verbs_proccall = list( ) var/list/admin_verbs_snpc = list( /client/proc/resetSNPC, - /client/proc/toggleSNPC, /client/proc/customiseSNPC, /client/proc/hide_snpc_verbs ) diff --git a/code/modules/mob/living/carbon/human/interactive/interactive.dm b/code/modules/mob/living/carbon/human/interactive/interactive.dm index 3c56ac3d47f..72b4076415f 100644 --- a/code/modules/mob/living/carbon/human/interactive/interactive.dm +++ b/code/modules/mob/living/carbon/human/interactive/interactive.dm @@ -67,14 +67,13 @@ //modules var/list/functions = list("nearbyscan","combat","shitcurity","chatter") var/restrictedJob = 0 - var/shouldUseDynamicProc = 0 // switch to make the AI control it's own proccessing - var/alternateProcessing = 0 var/forceProcess = 0 - var/processTime = 10 var/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 @@ -95,6 +94,8 @@ 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 @@ -142,7 +143,7 @@ doing = 0 inactivity_period = 0 -/client/proc/resetSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.botPool_l) +/client/proc/resetSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing) set name = "Reset SNPC" set desc = "Reset the SNPC" set category = "Debug" @@ -153,20 +154,7 @@ if(istype(T)) T.reset() -/client/proc/toggleSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.botPool_l) - set name = "Toggle SNPC Proccessing Mode" - set desc = "Toggle SNPC Proccessing Mode" - set category = "Debug" - - if(!holder) - return - - if(istype(T)) - T.alternateProcessing = !T.alternateProcessing - T.forceProcess = 1 - to_chat(usr, "[T]'s processing has been switched to [T.alternateProcessing ? "High Profile" : "Low Profile"]") - -/client/proc/customiseSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.botPool_l) +/client/proc/customiseSNPC(mob/living/carbon/human/interactive/T in SSnpcpool.processing) set name = "Customize SNPC" set desc = "Customize the SNPC" set category = "Debug" @@ -316,6 +304,12 @@ 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") @@ -419,7 +413,7 @@ sync_mind() random() doSetup() - SSnpcpool.insertBot(src) + START_PROCESSING(SSnpcpool, src) loadVoice() hear_radio_list += src @@ -432,9 +426,7 @@ doProcess() /mob/living/carbon/human/interactive/Destroy() - hear_radio_list -= src - snpc_list -= src - SSnpcpool.removeBot(src) + SSnpcpool.stop_processing(src) return ..() /mob/living/carbon/human/interactive/proc/retalTarget(mob/living/target) @@ -592,17 +584,7 @@ ..() /mob/living/carbon/human/interactive/proc/doProcess() - forceProcess = 0 - - if(shouldUseDynamicProc) - var/isSeen = 0 - for(var/mob/living/carbon/human/A in orange(12, src)) - if(A.client) - isSeen = 1 - alternateProcessing = isSeen - if(alternateProcessing) - forceProcess = 1 - + set waitfor = FALSE if(IsDeadOrIncap()) reset() return @@ -630,10 +612,13 @@ 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)) @@ -650,6 +635,8 @@ 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() @@ -683,7 +670,7 @@ //proc functions for(var/Proc in functions) if(!IsDeadOrIncap()) - callfunction(Proc) + INVOKE_ASYNC(src, Proc) //target interaction stays hardcoded @@ -697,8 +684,8 @@ 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() - sleep(15) var/turf/T = get_step(get_step(D.loc, dir), dir) //recursion yo tryWalk(T) //THIEVING SKILLS @@ -722,15 +709,8 @@ 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) + dressup(TARGET) update_hands = 1 if(MYPDA in loc) equip_to_appropriate_slot(MYPDA) @@ -787,9 +767,19 @@ TARGET = traitorTarget tryWalk(TARGET) LAST_TARGET = TARGET - if(alternateProcessing) - spawn(processTime) - doProcess() + +/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() @@ -801,10 +791,6 @@ outList = inList return outList -/mob/living/carbon/human/interactive/proc/callfunction(Proc) - 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)))) diff --git a/paradise.dme b/paradise.dme index fdd6b4594c2..3d6be6a5216 100644 --- a/paradise.dme +++ b/paradise.dme @@ -195,7 +195,6 @@ #include "code\controllers\Processes\fast_process.dm" #include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\nano_mob_hunter.dm" -#include "code\controllers\Processes\npcai.dm" #include "code\controllers\Processes\obj.dm" #include "code\controllers\Processes\shuttles.dm" #include "code\controllers\Processes\ticker.dm" @@ -209,6 +208,7 @@ #include "code\controllers\subsystem\mobs.dm" #include "code\controllers\subsystem\nanoui.dm" #include "code\controllers\subsystem\nightshift.dm" +#include "code\controllers\subsystem\npcai.dm" #include "code\controllers\subsystem\npcpool.dm" #include "code\controllers\subsystem\spacedrift.dm" #include "code\controllers\subsystem\sun.dm"