diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 60a0f565f24..61aa9962d6b 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -134,3 +134,26 @@ #define PEN_FONT "Verdana" #define CRAYON_FONT "Comic Sans MS" #define SIGNFONT "Times New Roman" + + +//NPC DEFINES +#define INTERACTING 2 +#define TRAVEL 4 +#define FIGHTING 8 + +//TRAITS + +#define TRAIT_ROBUST 2 +#define TRAIT_UNROBUST 4 +#define TRAIT_SMART 8 +#define TRAIT_DUMB 16 +#define TRAIT_MEAN 32 +#define TRAIT_FRIENDLY 64 +#define TRAIT_THIEVING 128 + +//defines +#define MAX_RANGE_FIND 32 +#define MIN_RANGE_FIND 16 +#define FUZZY_CHANCE_HIGH 85 +#define FUZZY_CHANCE_LOW 50 +#define CHANCE_TALK 15 diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm new file mode 100644 index 00000000000..16326980e2f --- /dev/null +++ b/code/controllers/subsystem/npcpool.dm @@ -0,0 +1,114 @@ +var/datum/subsystem/npcpool/SSbp + +/datum/subsystem/npcpool + name = "NPCPool" + priority = 27 + + 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/subsystem/npcpool/proc/insertBot(var/toInsert) + if(istype(toInsert,/mob/living/carbon/human/interactive)) + botPool_l |= toInsert + else if(istype(toInsert,/obj/machinery/bot)) + botPool_l_non |= toInsert + +/datum/subsystem/npcpool/New() + NEW_SS_GLOBAL(SSbp) + + +/datum/subsystem/npcpool/stat_entry() + stat(name, "[round(cost,0.001)]ds (CPU:[round(cpu,1)]%) (T:[botPool_l.len + botPool_l_non] | D: [needsDelegate.len] | A: [needsAssistant.len + needsHelp_non.len] | U: [canBeUsed.len + canBeUsed_non.len])") + + +/datum/subsystem/npcpool/fire() + //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 + // 2. Bot Health/status: check health with bots in local area, if their health is higher, delegate task to them, else coordinate + // 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 + + //bot handling + for(var/obj/machinery/bot/check in botPool_l_non) + if(!check) + botPool_l_non.Cut(npcCount,npcCount+1) + + if(check.hacked) + needsHelp_non |= check + else if(check.frustration > 5) //average for most bots + needsHelp_non |= check + else if(check.mode == 0) + canBeUsed_non |= check + npcCount++ + + npcCount = 1 //reset the count + + //SNPC handling + for(var/mob/living/carbon/human/interactive/check in botPool_l) + var/checkInRange = view(MAX_RANGE_FIND,check) + if(!check) + botPool_l.Cut(npcCount,npcCount+1) + if(!(locate(check.TARGET) in checkInRange)) + needsDelegate |= check + + else if(check.isnotfunc(FALSE)) + needsDelegate |= check + + else if(check.doing & FIGHTING) + needsAssistant |= check + + else + canBeUsed |= check + npcCount++ + + if(needsDelegate.len) + for(var/mob/living/carbon/human/interactive/check in needsDelegate) + if(canBeUsed.len) + var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed) + var/facCount = 0 + var/helpProb = 0 + for(var/C in check.faction) + if(candidate.faction[facCount] == 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" + + if(needsAssistant.len) + for(var/mob/living/carbon/human/interactive/check in needsAssistant) + if(canBeUsed.len) + var/mob/living/carbon/human/interactive/candidate = pick(canBeUsed) + var/facCount = 0 + var/helpProb = 0 + for(var/C in check.faction) + if(candidate.faction[facCount] == C) + helpProb = min(100,helpProb + 10) + facCount++ + if(facCount == 1 && helpProb > 0) + helpProb = 100 + if(prob(helpProb)) + if(candidate.takeDelegate(check,FALSE)) + needsAssistant -= check + canBeUsed -= candidate + candidate.eye_color = "yellow" + + if(needsHelp_non.len) + for(var/obj/machinery/bot/B in needsHelp_non) + if(canBeUsed_non.len) + var/obj/machinery/bot/candidate = pick(canBeUsed_non.len) + candidate.call_bot(B,get_turf(B),FALSE) + canBeUsed_non -= B + needsHelp_non -= candidate \ No newline at end of file diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index f2bb4d9c38e..19883679181 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -98,6 +98,7 @@ /obj/machinery/bot/New() ..() SSbot.processing += src //Global bot list + SSbp.insertBot(src) botcard = new /obj/item/weapon/card/id(src) set_custom_texts() Radio = new /obj/item/device/radio(src) @@ -439,7 +440,7 @@ obj/machinery/bot/proc/bot_step(var/dest) if(mode != BOT_SUMMON && mode != BOT_RESPONDING) botcard.access = prev_access -/obj/machinery/bot/proc/call_bot(var/caller, var/turf/waypoint) +/obj/machinery/bot/proc/call_bot(var/caller, var/turf/waypoint, var/message=TRUE) bot_reset() //Reset a bot before setting it to call mode. var/area/end_area = get_area(waypoint) @@ -456,12 +457,14 @@ obj/machinery/bot/proc/bot_step(var/dest) if(!on) turn_on() //Saves the AI the hassle of having to activate a bot manually. botcard = all_access //Give the bot all-access while under the AI's command. - calling_ai << "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination." + if(message) + calling_ai << "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination." pathset = 1 mode = BOT_RESPONDING tries = 0 else - calling_ai << "Failed to calculate a valid route. Ensure destination is clear of obstructions and within range." + if(message) + calling_ai << "Failed to calculate a valid route. Ensure destination is clear of obstructions and within range." calling_ai = null path = list() diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/interactive.dm index c7d0cd73725..cd7dd65d019 100644 --- a/code/modules/mob/interactive.dm +++ b/code/modules/mob/interactive.dm @@ -1,24 +1,3 @@ -#define INTERACTING 2 -#define TRAVEL 4 -#define FIGHTING 8 - -//TRAITS - -#define TRAIT_ROBUST 2 -#define TRAIT_UNROBUST 4 -#define TRAIT_SMART 8 -#define TRAIT_DUMB 16 -#define TRAIT_MEAN 32 -#define TRAIT_FRIENDLY 64 -#define TRAIT_THIEVING 128 - -//defines -#define MAX_RANGE_FIND 32 -#define MIN_RANGE_FIND 16 -#define FUZZY_CHANCE_HIGH 85 -#define FUZZY_CHANCE_LOW 50 -#define CHANCE_TALK 15 - /* NPC VAR EXPLANATIONS (for modules and other things) @@ -69,6 +48,7 @@ var/obj/item/other_hand var/TRAITS = 0 var/datum/job/myjob + faction = list("station") //trait vars var/robustness = 50 var/smartness = 50 @@ -79,6 +59,31 @@ //modules var/list/functions = list("nearbyscan","combat","doorscan","shitcurity","chatter") +//botPool funcs +/mob/living/carbon/human/interactive/proc/takeDelegate(var/mob/living/carbon/human/interactive/from,var/doReset=TRUE) + eye_color = "red" + if(from == src) + return FALSE + TARGET = from.TARGET + LAST_TARGET = from.LAST_TARGET + retal = from.retal + retal_target = from.retal_target + doing = from.doing + // + timeout = 0 + inactivity_period = 0 + interest = 100 + // + 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. underwear = random_underwear(gender) @@ -87,7 +92,7 @@ facial_hair_style = random_facial_hair_style(gender) hair_color = random_short_color() facial_hair_color = hair_color - eye_color = random_eye_color() + eye_color = "blue" age = rand(AGE_MIN,AGE_MAX) ready_dna(src,random_blood_type()) //job handling @@ -106,6 +111,12 @@ retal = 1 retal_target = user +/mob/living/carbon/human/interactive/bullet_act(var/obj/item/projectile/P) + var/potentialAssault = locate(/mob/living) in view(2,P.starting) + if(potentialAssault) + attacked_by(P,potentialAssault) + ..() + /mob/living/carbon/human/interactive/New() ..() gender = pick(MALE,FEMALE) @@ -133,29 +144,29 @@ //arms if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/2)) var/obj/item/organ/limb/r_arm/R = locate(/obj/item/organ/limb/r_arm) in organs - del(R) + qdel(R) organs += new /obj/item/organ/limb/robot/r_arm else var/obj/item/organ/limb/l_arm/L = locate(/obj/item/organ/limb/l_arm) in organs - del(L) + qdel(L) organs += new /obj/item/organ/limb/robot/l_arm //legs if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/2)) var/obj/item/organ/limb/r_leg/R = locate(/obj/item/organ/limb/r_leg) in organs - del(R) + qdel(R) organs += new /obj/item/organ/limb/robot/r_leg else var/obj/item/organ/limb/l_leg/L = locate(/obj/item/organ/limb/l_leg) in organs - del(L) + qdel(L) organs += new /obj/item/organ/limb/robot/l_leg //chest and head if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/2)) var/obj/item/organ/limb/chest/R = locate(/obj/item/organ/limb/chest) in organs - del(R) + qdel(R) organs += new /obj/item/organ/limb/robot/chest else var/obj/item/organ/limb/head/L = locate(/obj/item/organ/limb/head) in organs - del(L) + qdel(L) organs += new /obj/item/organ/limb/robot/head for(var/obj/item/organ/limb/LIMB in organs) LIMB.owner = src @@ -220,10 +231,10 @@ toReturn = "Excited" return toReturn //END DEBUG -/mob/living/carbon/human/interactive/proc/isnotfunc() +/mob/living/carbon/human/interactive/proc/isnotfunc(var/checkDead = TRUE) if(!canmove) return 1 - if(health <= 0) + if(health <= 0 && checkDead) return 1 if(restrained()) return 1 @@ -634,12 +645,14 @@ New() TRAITS |= TRAIT_ROBUST TRAITS |= TRAIT_MEAN + faction = list("bot_angry") ..() /mob/living/carbon/human/interactive/friendly New() TRAITS |= TRAIT_FRIENDLY TRAITS |= TRAIT_UNROBUST + faction = list("bot_friendly") ..() /mob/living/carbon/human/interactive/greytide @@ -648,16 +661,6 @@ TRAITS |= TRAIT_MEAN TRAITS |= TRAIT_THIEVING TRAITS |= TRAIT_DUMB + faction = list("bot_grey") graytide = 1 - ..() - -#undef INTERACTING -#undef TRAVEL -#undef FIGHTING -#undef TRAIT_ROBUST -#undef TRAIT_UNROBUST -#undef TRAIT_SMART -#undef TRAIT_DUMB -#undef TRAIT_MEAN -#undef TRAIT_FRIENDLY -#undef TRAIT_THIEVING \ No newline at end of file + ..() \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index 1c8c71dedb4..ada2436efc7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -134,6 +134,7 @@ #include "code\controllers\subsystem\machines.dm" #include "code\controllers\subsystem\mobs.dm" #include "code\controllers\subsystem\nanoUI.dm" +#include "code\controllers\subsystem\npcpool.dm" #include "code\controllers\subsystem\objects.dm" #include "code\controllers\subsystem\pai.dm" #include "code\controllers\subsystem\pipenets.dm"