From 7b9fd7e6fb2b5bb41315f542e6d85eae6ee54dc7 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Sun, 26 Mar 2017 15:24:38 -0400 Subject: [PATCH] SNPC Refactor (#25429) * Move the interactive file to the right spot * Proper scheduling * dOY * Fix shit --- code/controllers/subsystem/npcpool.dm | 188 +++++++++--------- code/modules/admin/admin_verbs.dm | 2 - .../{ => living/carbon/human}/interactive.dm | 119 +++++------ tgstation.dme | 2 +- 4 files changed, 145 insertions(+), 166 deletions(-) rename code/modules/mob/{ => living/carbon/human}/interactive.dm (96%) diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm index c777b683628..51032c44325 100644 --- a/code/controllers/subsystem/npcpool.dm +++ b/code/controllers/subsystem/npcpool.dm @@ -1,39 +1,36 @@ var/datum/controller/subsystem/npcpool/SSnpc +#define PROCESSING_NPCS 0 +#define PROCESSING_DELEGATES 1 +#define PROCESSING_ASSISTANTS 2 + /datum/controller/subsystem/npcpool name = "NPC Pool" - init_order = 17 - flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_NO_TICK_CHECK - priority = 25 + flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND + priority = 20 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 - -/datum/controller/subsystem/npcpool/proc/insertBot(toInsert) - if(istype(toInsert,/mob/living/carbon/human/interactive)) - botPool_l |= toInsert + + var/list/processing = list() + var/list/currentrun = list() + var/stage /datum/controller/subsystem/npcpool/New() NEW_SS_GLOBAL(SSnpc) /datum/controller/subsystem/npcpool/stat_entry() - ..("T:[botPool_l.len + botPool_l_non.len]|D:[needsDelegate.len]|A:[needsAssistant.len + needsHelp_non.len]|U:[canBeUsed.len + canBeUsed_non.len]") + ..("NPCS:[processing.len]|D:[needsDelegate.len]|A:[needsAssistant.len]|U:[canBeUsed.len]") +/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/proc/cleanNull() - //cleanup nulled bots - listclearnulls(botPool_l) - listclearnulls(needsDelegate) - listclearnulls(canBeUsed) - listclearnulls(needsAssistant) - - -/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 @@ -41,87 +38,94 @@ var/datum/controller/subsystem/npcpool/SSnpc // 3. Process delegation: if a bot (or bots) has been delegated, assign them to the task. // 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. - var/npcCount = 1 - cleanNull() + 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.Cut(npcCount,npcCount+1) - continue - var/checkInRange = view(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(FALSE)) - needsDelegate |= check + thing.InteractiveProcess() - else if(check.doing & FIGHTING) - needsAssistant |= check + var/checkInRange = view(MAX_RANGE_FIND,thing) + if(thing.IsDeadOrIncap(FALSE) || !(locate(thing.TARGET) in checkInRange)) + needsDelegate += thing + else if(thing.doing & FIGHTING) + needsAssistant += thing + else + canBeUsed += thing - else - canBeUsed |= check - npcCount++ + if (MC_TICK_CHECK) + return + stage = PROCESSING_DELEGATES + currentrun = needsDelegate //localcache + src.currentrun = currentrun - if(needsDelegate.len) + 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 - 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 + var/helpProb = 0 + var/list/chfac = check.faction + var/list/canfac = candidate.faction + var/facCount = LAZYLEN(chfac) * LAZYLEN(canfac) - npcCount = 1 //reset the count - for(var/mob/living/carbon/human/interactive/check in needsDelegate) - if(!check) - needsDelegate.Cut(npcCount,npcCount+1) - 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.eye_color = "red" - candidate.update_icons() - npcCount++ + for(var/C in chfac) + if(C in canfac) + helpProb = min(100,helpProb + 25) + if(helpProb >= 100) + break - if(needsAssistant.len) + if(facCount == 1 && helpProb) + helpProb = 100 - needsAssistant -= pick(needsAssistant) + if(prob(helpProb) && candidate.takeDelegate(check)) + --canBeUsed.len + candidate.eye_color = "red" + candidate.update_icons() - npcCount = 1 //reset the count - for(var/mob/living/carbon/human/interactive/check in needsAssistant) - if(!check) - needsAssistant.Cut(npcCount,npcCount+1) - 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,FALSE)) - needsAssistant -= check - canBeUsed -= candidate - candidate.eye_color = "yellow" - candidate.update_icons() - npcCount++ + 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.eye_color = "yellow" + 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() - if (istype(SSnpc.botPool_l)) - botPool_l = SSnpc.botPool_l - if (istype(SSnpc.botPool_l_non)) - botPool_l_non = SSnpc.botPool_l_non \ No newline at end of file + processing = SSnpc.processing \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 824e0b1a8a9..6433f127aeb 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -64,7 +64,6 @@ var/list/admin_verbs_admin = list( /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ /client/proc/customiseSNPC, /* Customise any interactive crewmembers in the world */ /client/proc/resetSNPC, /* Resets any interactive crewmembers in the world */ - /client/proc/toggleSNPC, /* Toggles an npc's processing mode */ /client/proc/open_shuttle_manipulator /* Opens shuttle manipulator UI */ ) var/list/admin_verbs_ban = list( @@ -239,7 +238,6 @@ var/list/admin_verbs_hideable = list( /client/proc/debug_huds, /client/proc/customiseSNPC, /client/proc/resetSNPC, - /client/proc/toggleSNPC ) /client/proc/add_admin_verbs() diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/living/carbon/human/interactive.dm similarity index 96% rename from code/modules/mob/interactive.dm rename to code/modules/mob/living/carbon/human/interactive.dm index 0363520f4c8..450e3c413f5 100644 --- a/code/modules/mob/interactive.dm +++ b/code/modules/mob/living/carbon/human/interactive.dm @@ -67,10 +67,7 @@ //modules var/list/functions = list("nearbyscan","combat","shitcurity","chatter") var/restrictedJob = 0 - var/shouldUseDynamicProc = 0 // switch to make the AI control it's own proccessing - var/alternateProcessing = 1 var/forceProcess = 0 - var/processTime = 8 var/lastProc = 0 var/walkdebug = 0 //causes sparks in our path target. used for debugging var/debugexamine = 0 //If we show debug info in our examine @@ -85,6 +82,7 @@ var/traitorScale = 0 // our ability as a traitor var/traitorType = 0 + var/voice_saved = FALSE /// SNPC voice handling @@ -96,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 @@ -146,7 +146,7 @@ ..() -/client/proc/resetSNPC(var/mob/A in SSnpc.botPool_l) +/client/proc/resetSNPC(var/mob/A in SSnpc.processing) set name = "Reset SNPC" set desc = "Reset the SNPC" set category = "Debug" @@ -163,24 +163,7 @@ T.retal = 0 T.doing = 0 -/client/proc/toggleSNPC(var/mob/A in SSnpc.botPool_l) - set name = "Toggle SNPC Proccessing Mode" - set desc = "Toggle SNPC Proccessing Mode" - set category = "Debug" - - if(!holder) - return - - if(A) - if(!istype(A,/mob/living/carbon/human/interactive)) - return - var/mob/living/carbon/human/interactive/T = A - if(T) - T.alternateProcessing = !T.alternateProcessing - T.forceProcess = 1 - to_chat(usr, "[T]'s processing has been switched to [T.alternateProcessing ? "High Profile" : "Low Profile"]") - -/client/proc/customiseSNPC(var/mob/A in SSnpc.botPool_l) +/client/proc/customiseSNPC(var/mob/A in SSnpc.processing) set name = "Customize SNPC" set desc = "Customise the SNPC" set category = "Debug" @@ -390,7 +373,7 @@ doSetup() - SSnpc.insertBot(src) + START_PROCESSING(SSnpc, src) loadVoice() @@ -400,8 +383,9 @@ attitude += rand(-10,10) slyness += rand(-10,10) - doProcess() - +/mob/living/carbon/human/interactive/Destroy() + SSnpc.stop_processing(src) + return ..() /mob/living/carbon/human/interactive/proc/retalTarget(var/target) var/mob/living/carbon/human/M = target @@ -533,12 +517,10 @@ /mob/living/carbon/human/interactive/proc/targetRange(towhere) return get_dist(get_turf(towhere), get_turf(src)) -/mob/living/carbon/human/interactive/Life() - ..() +/mob/living/carbon/human/interactive/proc/InteractiveProcess() if(ticker.current_state == GAME_STATE_FINISHED) saveVoice() - if(!alternateProcessing || forceProcess || world.time > lastProc + processTime) - doProcess() + doProcess() /mob/living/carbon/human/interactive/death() saveVoice() @@ -550,22 +532,7 @@ ..() /mob/living/carbon/human/interactive/proc/doProcess() - set waitfor = 0 - forceProcess = 0 - lastProc = world.time - - if(shouldUseDynamicProc) - var/isSeen = 0 - for(var/mob/living/carbon/human/A in orange(12,src)) - if(A.client) - isSeen = 1 - alternateProcessing = isSeen - if(alternateProcessing) - forceProcess = 1 - - if(IsDeadOrIncap()) - walk(src,0) - return + set waitfor = FALSE //--------------------------- //---- interest flow control if(interest < 0 || inactivity_period < 0) @@ -587,10 +554,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,(100 - smartness)/2) sleep(5) + if(QDELETED(AL)) + return AL.unbolt() if(!AL.wires.is_cut(WIRE_BOLTS)) AL.wires.cut(WIRE_BOLTS) @@ -599,9 +569,15 @@ if(!AL.wires.is_cut(WIRE_POWER2)) AL.wires.cut(WIRE_POWER2) sleep(5) + if(QDELETED(AL)) + return AL.panel_open = 0 AL.update_icon() - D.open() + D.open(2) //crowbar force + else + D.open() + else + D.open() if(update_hands) var/obj/item/l_hand = get_item_for_held_index(1) @@ -633,7 +609,7 @@ //proc functions for(var/Proc in functions) if(!IsDeadOrIncap()) - callfunction(Proc) + INVOKE_ASYNC(src, Proc) //target interaction stays hardcoded @@ -649,8 +625,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 @@ -672,15 +648,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) - dropItemToGround(I) - spawn(5) - equip_to_appropriate_slot(C) + dressup(TARGET) update_hands = 1 if(MYPDA in src.loc || MYID in src.loc) if(MYPDA in src.loc) @@ -738,8 +707,19 @@ TARGET = traitorTarget tryWalk(TARGET) LAST_TARGET = TARGET - if(alternateProcessing) - addtimer(CALLBACK(src, .proc/doProcess), processTime) + +/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) + dropItemToGround(I) + sleep(5) + if(!QDELETED(src) && !QDELETED(C)) + equip_to_appropriate_slot(C) /mob/living/carbon/human/interactive/proc/favouredObjIn(var/list/inList) var/list/outList = list() @@ -751,11 +731,6 @@ outList = inList return outList -/mob/living/carbon/human/interactive/proc/callfunction(Proc) - set waitfor = 0 - spawn(0) - call(src,Proc)(src) - /mob/living/carbon/human/interactive/proc/tryWalk(turf/inTarget, override = 0) if(restrictedJob && !override) // we're a job that has to stay in our home if(!(get_turf(inTarget) in get_area_turfs(job2area(myjob)))) @@ -1143,7 +1118,8 @@ for(var/obj/item/I in allContents) if(istype(I,/obj/item/weapon/restraints)) I.attack(TARGET,src) // go go bluespace restraint launcher! - sleep(25) + inactivity_period = 25 + break /mob/living/carbon/human/interactive/proc/clowning(obj) if(shouldModulePass()) @@ -1225,7 +1201,7 @@ if(get_dist(src,C) <= 2) src.say("Wait, [C], let me heal you!") M.attack(C,src) - sleep(25) + inactivity_period = 25 else tryWalk(get_turf(C)) else if(shouldTryHeal == 2) @@ -1237,7 +1213,7 @@ if(get_dist(src,C) <= 2) src.say("Wait, [C], let me heal you!") HPS.attack(C,src) - sleep(25) + inactivity_period = 25 else tryWalk(get_turf(C)) @@ -1265,7 +1241,7 @@ tryWalk(TC) else S.afterattack(TC,src) - sleep(25) + inactivity_period = 25 /mob/living/carbon/human/interactive/proc/customEmote(var/text) visible_message("[text]") @@ -1354,7 +1330,7 @@ var/choice = pick(1,2) if(choice == 1) tryWalk(get_turf(D)) - sleep(get_dist(src,D)) + inactivity_period = get_dist(src,D) D.attackby(RP,src) else cookingwithmagic(D) @@ -1364,7 +1340,7 @@ var/choice = pick(1,2) if(choice == 1) tryWalk(get_turf(D)) - sleep(get_dist(src,D)) + inactivity_period = get_dist(src,D) FD.attackby(KK,src) else cookingwithmagic(FD) @@ -1374,7 +1350,7 @@ var/choice = pick(1,2) if(choice == 1) tryWalk(get_turf(D)) - sleep(get_dist(src,D)) + inactivity_period = get_dist(src,D) CB.attackby(RP,src) else cookingwithmagic(CB) @@ -1384,7 +1360,7 @@ var/choice = pick(1,2) if(choice == 1) tryWalk(get_turf(D)) - sleep(get_dist(src,D)) + inactivity_period = get_dist(src,D) PD.attackby(KK,src) else cookingwithmagic(PD) @@ -1533,6 +1509,7 @@ G.attack_self(src) if(prob(smartness)) npcDrop(G,1) + inactivity_period = 15 sleep(15) throw_item(TARGET) diff --git a/tgstation.dme b/tgstation.dme index 4a0965d22ee..385566fb208 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1404,7 +1404,6 @@ #include "code\modules\mining\lavaland\necropolis_chests.dm" #include "code\modules\mining\lavaland\ruins\gym.dm" #include "code\modules\mob\death.dm" -#include "code\modules\mob\interactive.dm" #include "code\modules\mob\inventory.dm" #include "code\modules\mob\login.dm" #include "code\modules\mob\logout.dm" @@ -1510,6 +1509,7 @@ #include "code\modules\mob\living\carbon\human\human_defines.dm" #include "code\modules\mob\living\carbon\human\human_helpers.dm" #include "code\modules\mob\living\carbon\human\human_movement.dm" +#include "code\modules\mob\living\carbon\human\interactive.dm" #include "code\modules\mob\living\carbon\human\inventory.dm" #include "code\modules\mob\living\carbon\human\life.dm" #include "code\modules\mob\living\carbon\human\say.dm"