Text Vision Awareness Judgement Description Library for LLMs in Video Games [Open Source]

This module initializing itself, in the code it has a directory of objects which should be organized into categories. The one function getsurroundingobjects utilizes all of the functions.
This is the 3rd iteration of my Text-Vision Awareness module I use to give LLMs text vision in ROBLOX by synthesizing natural language descriptions of the environment. It judges sizes, terrain, floor material, bodies of water, and generalizes multiple duplicate objects into concise descriptions.

create.roblox.com/store/asset/17580211477

The code has been cleaned up from previous versions.

This module is set up to describe object categories but most of the things it does are the same across categories. It mainly requires that you have natural language names for your objects.
"It is obvious that, the ecosystem hosts a handful of grass, a dash of ground, a trace of mud, a touch of leafy grass, a trace of basalt, a touch of cracked lava, and quite a lot of rock, and I am standing on wooden planks. "
I would recommend using this for giving textual hints to a player such as navigating a maze or finding loot, or using it to give a large language model the ability to understand its surrounding via a truth grounded text description of the various objects in the surroundings.

Updated version of this Text-Vision Awareness LLM Utility Luau [OPEN SOURCE] now Judges Terrain, Water, Floor Material and More - Resources / Community Resources - Developer Forum | Roblox

Candyland Observations

                    [1] = "I notice, a medium-small plant called upside down Mint Chocolate cone is kind of near to the west.",
                    [2] = "I glimpse a Grape Lollipop is extremely near behind me to the right, and their are a quartet of trees that are carved or decorated.",
                    [3] = "I perceive, a piece of tiny rubble embedded with a Halloween Cupcake with Sprinkles is kind of near to the northwest.",
                    [4] = "So I notice, a medium-small plant called upside down Mint Chocolate cone is kind of near to the west, and a Grape Lollipop is very near behind me to the right. .",
                    [5] = "I am walking on a cherry heart cake, and a chunk of mini rock embedded with a Halloween Cupcake with Sprinkles is kind of not far to the northwest.",
                    [6] = "Their are a quartet of trees that form the scene.",
                    [7] = "I glimpse a medium-small plant called upside down Mint Chocolate cone is somewhat near westward, a Grape Lollipop is very close behind me to the right, and their are a quartet of trees that are carved or decorated. A piece of tiny rubble embedded with a Halloween Cupcake with Sprinkles is somewhat near to the northwest, I notice, a medium-small plant called upside down Mint Chocolate cone is somewhat near westward, and a Grape Lollipop is very close behind me to the right.  I also am aware, I am walking on a cherry heart cake, and a chunk of tiny rock embedded with a Halloween Cupcake with Sprinkles is somewhat near to the northwest. ",
                    [8] = "A medium-small plant called upside down Mint Chocolate cone is pretty near to the west",
                    [9] = "I am walking on a cherry heart cake. What I notice is a medium-small plant called upside down Mint Chocolate cone is kind of close to the west, a Grape Lollipop is very close behind me to the right, a quartet of trees that form the scene, and a chunk of tiny rock embedded with a Halloween Cupcake with Sprinkles is kind of close to the northwest. "
                 }  -  Client - Awareness:3509 ]]

Here is a video demonstration using this module as a data source for a lua code based chatbot.

The code is available for anything to use freely.

8 Likes

Back at it again, bringing some of the best resources onto Roblox. I wonder if people will dismiss it again as a

which is essentially what a neural network is.

I strongly support your many AI projects, and they’re extremely valuable being natively in LUAU without third-party requests at runtime. Realistically, you should be getting compensated a reasonable amount of money/RBX for spending time making these. Just know that I love seeing more and more of these projects available for the public, and maybe eventually they will finally get their rightfully deserved integration into some of the best Roblox games. These could SERIOUSLY help with immersion and such.

4 Likes

Thanks for the positive feedback. I think this is a good framework for other projects utilizing AI in video games without using an external neural network API for Text-Vision (which isn’t very practical for ROBLOX currently). I port what I can from projects I’m working on so this is a pleasure to share as an open source resource.

2 Likes

Full Open Sourced Code Excluding Phrase Module Libraries located in the model linked above

--Designed to created textual observations of labeled surroundings and return a table of observations.
--Can Be used to inform an LLM agent of its surroundings in a video game

--Declare global variables for all observed variables.
local closestPlant, numPlants, plantsize, plantdist --= aware.near.plant(root, 40)
local closestTree, numTrees, treesize, treedist --= aware.near.tree(root, 80)
local closestStructure, numStructures, structuresize, strucdist
local closestEnemy, numEnemies, enemysize, enemydist
local closestNPC, numNPCs, npcsize, npcdist,npcarray
local closestPlayer, numPlayers, plrsize, plrdist 
local closestRubble, numRubble, rubblesize, rubbledist 
local closestChest, numChests, chestsize, chestdist
local closestGroundItem, numGroundItems, itemsize, itemdist 
local closestHouse, numHouses, housesize, housedist
local closestDungeon, numDungeons, dungsize, dungdist,Dungeonarray 
local closestFish, numFish, Fishsize, Fishdist 
local closestFurn, numFurn, Furnsize, Furndist,Furnarray
local closestBoid, numBoid, boidsize, boiddist,boidarr 
local plantarr,treearr,strucarr,npcarr,enemyarr,plrarr,chestarr,itemarr,fisharr,rubbarr
--Time used to limit updating of tables
local optime=os.time()
local terrain=workspace.Terrain
local phraselib=require(script.PhraseLibrary)
local DescriptionModule = require(script.JudgementLibrary)
--Load All of these as local variables for the judgement library
local phrases = DescriptionModule.phrases
local judgeheightmatrixSizes = DescriptionModule.judgeHeightMatrix.sizes
local judgehmatrixStrings = DescriptionModule.judgeHeightMatrix.strings
local judgewidthmatrixSizes = DescriptionModule.judgeWidthMatrix.sizes
local judgewidthmatrixStrings = DescriptionModule.judgeWidthMatrix.strings
local judgethicknessmatrixSizes = DescriptionModule.judgeThicknessMatrix.sizes
local judgethicknessmatrixStrings = DescriptionModule.judgeThicknessMatrix.strings
local jmatrixSizes = DescriptionModule.judgeSizeMatrix.sizes
local judgehsizematrixStrings = DescriptionModule.judgeSizeMatrix.strings
local judgeamntdistributio = DescriptionModule.judgeAmountDistribution.sizes
local judgeamntstrings = DescriptionModule.judgeAmountDistribution.strings
local toomany = DescriptionModule.tooMany
local emotiondesc = DescriptionModule.emotionDesc -- Assuming this is an empty table as per your original variable
local judgematrixSizes = DescriptionModule.judgeMatrix.sizes
local judgematrixStrings = DescriptionModule.judgeMatrix.strings
local rockjudgematrixSizes = DescriptionModule.rockJudgeMatrix.sizes
local rockpiece = DescriptionModule.rockJudgeMatrix.pieces
local heightmatrixSizes = DescriptionModule.heightMatrix.sizes
local heightmatrixstrings = DescriptionModule.heightMatrix.strings
local heightmatrixSizes = {-1, -0.67, -0.33, 0, 0.33, 0.67, 1} -- This seems to be a duplicate, ensure to use the correct one from the module if needed
local judgepowerSizes = DescriptionModule.judgePowerMatrix.sizes
local judgepowerStrings = DescriptionModule.judgePowerMatrix.strings
local furthersubject=DescriptionModule.Furthersubject

--Used For String Matching considering Filter words.
local RunService = game:GetService("RunService")
local isLocal = RunService:IsClient()
if isLocal and game.Players.LocalPlayer.PlayerGui:FindFirstChild("Chatbot") then	
	processor=game.Players.LocalPlayer.PlayerGui.Chatbot.LocalProcessor	
elseif game.ReplicatedStorage:FindFirstChild("GlobalSpells") then 
	processor=game.ReplicatedStorage.GlobalSpells.BindableFunction 
end	

local aware = {}
aware["get"]={}
aware["judge"]={}
aware["near"]={}
aware.judge.human={}

local previousroot=nil 
local objecttable
local range = 80
-- Define the raycast parameters

local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include
params.FilterDescendantsInstances = {workspace.Terrain}
params.IgnoreWater = false
local waterdirections = {
	Vector3.new(0, -5, range), -- forward
	Vector3.new(0, -5, -range), -- backward
	Vector3.new(range, -5, 0), -- right
	Vector3.new(-range, -5, 0), -- left
	Vector3.new(0, range, 0), -- up
	Vector3.new(0, -range, 0) -- down
}
-- Rewriting the variables using the DescriptionModule
local globalrng=Random.new(os.time())
local newtable = {"MapObjects",--structures
    "Crystals",--crystals
    "Plants",
    "Enemys",
    "Rubble",
    "Trees",
    "Chests",
    "GroundItems",--loots
    "Houses",--house type
    "AmbientAreas",--Zoned Areas
    "NPCS",
    "Furniture",
	"Fish",
	"Boids"
}
for i,v in newtable do --generate directories if their is none
if workspace:FindFirstChild(v)==nil then
local f=Instance.new("Folder")
f.Name=v
f.Parent=workspace
end
end
local tablekeys = {["mapobject"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.MapObjects},
    ["crystal"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Crystals},
    ["plants"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Plants},
    ["enemys"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Enemys},
    ["rubble"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Rubble},
    ["trees"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Trees},
    ["chests"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Chests},
    ["grounditems"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1},workspace.GroundItems},
    ["houses"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Houses},
    ["players"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, game.Players},
    ["dungeons"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1},workspace.AmbientAreas},
    ["npcs"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.NPCS},
    ["furniture"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Furniture},
	["fish"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Fish},
	["boid"] = {{["datatable"] = nil, ["writetime"] = optime, ["refreshrate"] = 1}, workspace.Boids},
}
local awarekeys = {["observations"] = {["datatable"] = nil, ["writetime"] = -60, ["refreshrate"] = 60}
}
local matsolutions={["LeafyGrass"]="leafy grass",
["WoodPlanks"]="wooden planks",
["CrackedLava"]="cracked lava",
["ground"]="dirt"
}
local grid = Vector3.new(10, 20, 10) -- grid size
-- grid members

local function query(query,key)
	if processor then
		return processor:Invoke("SingleQuery",{query,key,nil,nil,true})
	else
		return string.gmatch(query,key)()
	end
end

local function has_punctuation(text)
	-- Define a pattern that matches any punctuation character
	local punctuation = "[.,;:!?]"
	-- Get the length of the text
	local length = string.len(text)
	-- Get the last character of the text
	local last = string.sub(text, length, length)
	-- Get the second last character of the text
	local second_last = string.sub(text, length - 1, length - 1)
	-- Check if the last character is a punctuation
	if string.match(last, punctuation) then
		-- Check if the second last character is a punctuation and the last character is a space
		-- Return true
		return true
	elseif string.match(second_last, punctuation) and last == " " then
		-- Return true
		return true
	else
		-- Return false
		return false
	end
end
local function observearray(root,pos,numFurn,closestFurn,Furnarray,a)
	local FurnitureText=""
	if a==nil then
		a=""
	end
	if Furnarray~=nil and #Furnarray>0 then	
		
	if numFurn >= 1 and closestFurn and Furnarray then
			local iterations=0
			local groups={}--group duplicate names to generalize multiple objects 
			local groupiter=0
			for i,closeFurniture in Furnarray do  
				--group by distance,direction and name.
				local dist, dir = aware.judge.distance(root,closeFurniture.distance, pos, aware.get.root2(closeFurniture.maininstance).Position, 80)
				local id =aware.judge.object(closeFurniture.maininstance)
				if groups[dir..id]==nil then--initalize the subtable
					groupiter+=1
					groups[dir..id]={dist,dir,id,[4]=1}
				else 
					groups[dir..id][4]+=1--increment the value
				end
			end
			local idhash={}--hash table of ids 
			local maxiterations=math.min(groupiter,3)-- only observe 3 objects name groups
			local amntjudged=0
			table.sort(groups,function(a,b) return a[4]>b[4] end)
			for i,closeFurniture in groups do   
				iterations+=1
				--grammar rules
				if iterations==maxiterations-1 then  FurnitureText=FurnitureText.." and  "
				elseif iterations>=2 and iterations~=maxiterations then FurnitureText=FurnitureText..", " end
				--unpack the distance and direction.
				local dist,dir=closeFurniture[1],closeFurniture[2]				
				--judge the amount of objects.
				local id=closeFurniture[3]
				--local totalamnt=idgroups[id][1]
				amntjudged+=closeFurniture[4]
				local amnt=a if closeFurniture[4]>1 then amnt=aware.judge.amnt(closeFurniture[4]).." " end	
				if closeFurniture[4]>1 then
				id=id.."s"
				end
				FurnitureText = FurnitureText..amnt..id .. " " .. dist .. "" .. dir
				if iterations==maxiterations then break end
			end
			local maxiterations=amntjudged-- only observe 3 objects name groups
			if #Furnarray-maxiterations>=2 then--later code will generalize the rest if conditions not met.
			FurnitureText..=", "	
			else 
				FurnitureText..=". "
			end
		return FurnitureText,maxiterations
	end	
	end
	return "",0	
end
local function modify_string(input_string)
	local modified_words = {}

	for word in input_string:gmatch("[A-Z][^A-Z]*") do
		local modified_word = word:gsub("^%l", string.upper)
		table.insert(modified_words, modified_word)
	end

	-- Replace multiple spaces with a single space
	local modified_string = table.concat(modified_words, " "):gsub("%s+", " ")

	return modified_string
end
local function tablehandler(location)
	return location:GetChildren()
end
local function gettime()
	return os.time()
end
local function getinvent(npc,plr)
	local invent =npc:FindFirstChild("Inventory")--npc inventory
	if invent==nil then--check if a party member
		print("Attempting to get party member")
		--local plr=npc:FindFirstChild("Owner2")
		if plr==nil then
			plr=game.Players:GetPlayerFromCharacter(npc)
		end
		if plr then
			local partym=plr.Levels.PartyS1.Value
			if partym==npc.Name or npc.Humanoid.DisplayName==partym then
				print("Found party member")
				local partydata=nil
				local index=nil
				for i=1, 9 do 
					if plr.Inventory["CustomCharacter"..i].Value==partym  then --if the party member is found get data index
						index=i
						break
					end

				end

				invent = {
					Armor = plr.Levels.PartyS1Armor,
					Amulet = plr.Levels.PartyS1Amulet,
					Boots = plr.Levels.PartyS1Boots,
					Book = plr.Levels.PartyS1Book,
					CustomCharacter = plr.Inventory["CustomCharacter" .. index],--Custom character name
					TopClothes = plr.Inventory["TopClothes" .. index],--custom clothes
					PantSkirtDress = plr.Inventory["PantSkirtDress" .. index],
					Cape = plr.Levels.PartyS1Cape,
					Helmet = plr.Levels.PartyS1Halo,
					Shield = plr.Levels.PartyS1Shield,
					Sword = plr.Levels.PartyS1Weapon,
					--Gun = plr.Levels.PartyS1Gun,
					Wand = plr.Levels.PartyS1Staff,
					--	Bracelet = plr.Levels.PartyS1Bracelet
				}
				print("Created party meta data.")
				print(invent)
				return invent
			end	
		end
	end
	return invent
end

function aware.ConstructEmotions(nam,get)
	local emotiondesc=require(script.Other).ConstructEmotions(nam,get)
	if get==true then
		return emotiondesc[aware.mathrandom(1,#emotiondesc)]
	end
	return emotiondesc
end
function aware.Updatetable(a, b, c, d)    --a=key b=arraylocation c=refreshrate d=array of b

	local e, f
	local b = b
	local c = c
	local d = d
	if tablekeys[a] then
		e, b = tablekeys[a][1], tablekeys[a][2]
		c = e["refreshrate"]
		f = e["datatable"]
	end
	tablekeys[a] = {{["datatable"] = tablehandler(b), ["writetime"] = os.time(), ["refreshrate"] = c}, b}

	if d == nil then
		return tablekeys[a][1]["datatable"]
	end
end
function aware.uptable(a)
	if tablekeys[a] then
		local b, c = tablekeys[a][1], tablekeys[a][2]
		local d = tonumber(b["writetime"])
		local e = b["refreshrate"]
		local f = b["datatable"]

		tablekeys[a] = {{["datatable"] = tablehandler(c), ["writetime"] = os.time(), ["refreshrate"] = e}, c}
		return tablekeys[a][1]["datatable"]

	else
		--   print("No table to return")
		return nil
	end
end
function aware.Gettable(a)
	if tablekeys[a] then
		local b, c = tablekeys[a][1], tablekeys[a][2]
		local d = tonumber(b["writetime"])
		local e = b["refreshrate"]
		local f = b["datatable"]
		if d + e < os.time() and f ~= nil then
			return f
		else
			tablekeys[a] = {{["datatable"] = tablehandler(c), ["writetime"] = os.time(), ["refreshrate"] = e}, c}
			return tablekeys[a][1]["datatable"]
		end
	else
		--  print("No table to return")
		return nil
	end
end
function aware.mathrandom(min,max)

	if min==nil then
		----print("Min Integer is nil converted to 0")
		min=0

	end
	if max==nil then
	--	--print("Max Integer is nil converted to 1")
		max=1
	end
	return 	globalrng:NextInteger(min, max)
end
function aware.cap(str)
	-- Check if the input is a valid string
	if type(str) ~= "string" then
		return str
	end
	-- Get the first character and the rest of the string
	local first = str:sub(1, 1)
	local rest = str:sub(2)
	-- Return the capitalized string
	return first:upper() .. rest

end
function aware.randomizeStringLight(str,interphrases,randomize,once)    
    local newS = str
    local s=str
        for j, phrases in ipairs(interphrases) do
            for k, phrase in ipairs(phrases) do
                if s:lower():find(phrase) then
                    if phrase:lower():find(s:lower())==nil then
                        -- Pick a random phrase from the same group
                        local randomPhrase
                        if randomize==nil then
                            randomPhrase = phrases[aware.mathrandom(#phrases)]
                        else 
                            randomPhrase= phrases[randomize]
                        end			
                        newS = newS:gsub(phrase, randomPhrase)	
                        if once==true then break end
                    end	
                end
            end
   end 

    return newS
end

function aware.get.CombatDescription(Char)
 return require(script.Other).CombatDescription(Char)
end

function aware.get.QuestData(player)
if player.PlayerGui:FindFirstChild("Bars") then
local dataloc=player.PlayerGui.Bars.Quest
local qdata=player.Quest
local v="Item"
local datatable={}
for i=1, 27 do
local item=dataloc:FindFirstChild("Item"..i) 
if item then
local questtext=dataloc["Item"..i].Description.Text
if questtext~=""  and questtext:gmatch("%w+") then
local goal=qdata["Item"..i].Value
datatable[goal]=questtext
end
end

end
return datatable
end
return nil

end
function aware.get.root(instance, itself)
    if instance ~= nil then
        local selfrecog = nil       
        if instance:FindFirstChild("HumanoidPart") ~= nil then
            return instance.HumanoidRootPart
        elseif instance:IsA("folder") ~= nil then
            return instance:FindFirstChildOfClass("Model").PrimaryPart
        elseif instance:IsA("BasePart") then
            return instance
            
        elseif instance:IsA("Model") then
if instance.PrimaryPart then
            return instance.PrimaryPart
else 
return instance:FindFirstChildOfClass("BasePart")
end
        end
    end
end
function aware.get.root2(instance)
	if instance ~= nil then
		if instance:IsA("BasePart") then 
			return instance
		elseif instance.Parent==workspace.AmbientAreas then
			return instance:FindFirstChild("Part")
		elseif instance:FindFirstChild("HumanoidRootPart") ~= nil then
			return instance.HumanoidRootPart
		elseif instance.Parent==workspace.Fish then
			return instance.PrimaryPart
		elseif instance:IsA("Folder") then
			if instance:FindFirstChildOfClass("BasePart")==nil then 
				if instance:FindFirstChildOfClass("Model") then
					if instance:FindFirstChildOfClass("Model").PrimaryPart~=nil then
						return instance:FindFirstChildOfClass("Model").PrimaryPart
					elseif instance:FindFirstChildOfClass("Model") :FindFirstChildOfClass("BasePart") then 
						return instance:FindFirstChildOfClass("Model") :FindFirstChildOfClass("BasePart")
					end
					return instance:FindFirstChildOfClass("Model"):FindFirstChild("Handle")
				end
			else return instance:FindFirstChildOfClass("BasePart") 
			end            
		elseif instance:IsA("Model") then
			if instance.PrimaryPart then
				return instance.PrimaryPart
			else 
				return instance:FindFirstChildOfClass("BasePart")
			end
		end
	end
end
function aware.get.nearest(list, root, dist, getone, mode)
    local a = root.Position
    local b = nil
    --local c = nil
    --local d = nil
    --local e = nil
    local f = 0
    local g = nil
    local range=dist
    --	local list=list
    local arealist={}
    local root_forward = root.CFrame.LookVector -- get the root's forward vector
    local root_forwardX =root_forward.X
    local root_forwardY=root_forward.Y  
    local root_forwardZ=root_forward.Z        
    if list ~= nil then
        for h = 1, #list do
           -- e = list[h]
          local c=  aware.get.root2(list[h])  
          --  if e.Parent==plan then if c:FindFirstChild("Species") then c=nil end end
            if c and root ~= c then
                local root_to_object = (c.Position - a)   
                local calc = root_to_object.Magnitude                
                if calc< range then
                    if getone=="array" then
                      table.insert(arealist,{maininstance=list[h],instance=c,size=g,distance=calc}) 
                    end
					if getone=="chatgpt" then
						--local judgeobj=list[h]
						local judgeobj= game.ReplicatedStorage.Items.Plants:FindFirstChild(tostring(list[h]))
						if judgeobj then
						else 
							judgeobj=list[h]
						end
                      table.insert(arealist,{model=list[h],primary=c,name=aware.judge.object(judgeobj),position=c.Position,distance=calc}) 
                    end                                 
                if calc < dist then --and dot_product > 0 then -- check if the object is in front of the root variable                 
                 -- get the vector from the root to the objec
       
             local dot_product = root_forwardX * root_to_object.X + root_forwardY * root_to_object.Y + root_forwardZ * root_to_object.Z -- calculate the dot product
                if dot_product >0 then
                     f = f + 1
                    if mode==nil or mode==false then
                        b = c
                    elseif mode==true then
                    b = list[h]
                    elseif mode.Query~=nil and query(mode.Query,aware.judge.object(list[h]):lower())~=nil then
                   print("Got match"..mode.Query..aware.judge.object(list[h]):lower())
                      b = list[h]
                    end
                    dist = calc
                    g = c.Size
                    if getone == true then
                        return b, g, calc                  
                    end
                end
                end               
            end
        end
    end
    end
    if #list > 30 then
       task.wait()
   -- if #list > 30 then
       -- task.wait(.6)
  --  end
    end
    if getone=="array" then
    table.sort(arealist,function(a,b) return a.distance>b.distance end)
    end
    return b, f, g, dist,arealist
end
function aware.get.nearestModels(root,radius,getone,mode)--get the nearest object of each type 
	local objectmegaarray={}
	--local numberofobjects=0
	local numberofclasses=0
	for i,v in aware.near do

		local _,_,_,_,objectarray=aware.near[i](root,radius,getone,mode)
		if objectarray then
			local num=#objectarray
			if num>=1 then

				numberofclasses+=1
			end
		end	
		--	numberofobjects+=num

		objectmegaarray[i]=objectarray 
	end
	local numberclass=math.min(1,7/numberofclasses)
	local organizedobjects={}
	--table.sort(organizedobjects,function(a,b)return a.distance<b.distance end)	
	for i,objectarray in objectmegaarray do
		for t,o in objectarray do 
			if t<=numberclass then --get 3 objects max				
				table.insert(organizedobjects,o)
			else 
				break
			end
		end
	end
	table.sort(organizedobjects,function(a,b) return a.distance<b.distance end)
	return organizedobjects
end
function aware.get.terrain(root,radius,str)
	local phrases = {
		"The environment has",
		"The terrain consists of",
		"The surroundings a characterized by",
		"The landscape features",
		"The ecosystem hosts",
	}
	if radius~=true then
		if str~="" and string.gmatch(str, "%w+") and string.len(str)>4 then
			--rewrite the table in the first person context
			return phrases[aware.quoterandom(1,#phrases)].." "..str..". "
		end
		local terrianjudge=aware.judge.terrain(root,radius)
		if terrianjudge~=nil and terrianjudge~=""  and string.gmatch(terrianjudge, "%w+") and string.len(terrianjudge)>4 then
			return phrases[aware.quoterandom(1,#phrases)].." "..terrianjudge..". "
		else 
			return nil
		end	
	elseif radius==true then
		return  phrases[aware.quoterandom(1,#phrases)]:lower().." "..str..""
	end
end
function aware.get.walking(root,player,walkings)
	local hum
	if root.Parent:FindFirstChild("Humanoid") then   
		hum=root.Parent.Humanoid
	else 
		hum=player.Character.Humanoid
	end
	local floormat = hum.FloorMaterial
	local walking="standing" if root.Velocity.Magnitude>1 then walking="walking" end 
	if not floormat then floormat = 'Air'
		return nil    
	end
	local matstring = string.split(tostring(floormat),'Enum.Material.')[2]
	--
	if matstring~='Air' and matstring~='Plastic' and matstring~="SmoothPlastic" and matstring~="Neon" then
		if matsolutions[matstring]~=nil then
			matstring= matsolutions[matstring]
		end
		local material = "I am "..walking.." on "..matstring:lower()..""
		return material
	else
		if matstring=="Plastic" or matstring=="SmoothPlatstic" then
			local matstring=player.PlayerGui.Chatbot.FloorPlatform.Value
			if matstring~="" then       
				return "I am "..walking.." on a "..matstring:lower()..""
			else 
				if walking then
					return "I am "..walking..""
				end
			end
		end     
		return ""
	end
end
function aware.get.objectsdata(root,key,mode,getone)
	if key==nil then 
		if  awarekeys["objective"]["datatable"] == nil or
			awarekeys["objective"]["writetime"] + awarekeys["observations"]["refreshrate"] < os.time() or root~=previousroot
		then      
			closestPlant, numPlants, plantsize, plantdist = aware.near.plant(root, 40,getone)
			closestTree, numTrees, treesize, treedist = aware.near.tree(root, 80,getone)
			closestStructure, numStructures, structuresize, strucdist = aware.near.structure(root, 160,getone)
			closestEnemy, numEnemies, enemysize, enemydist = aware.near.enemys(root, 60,getone)
			closestNPC, numNPCs, npcsize, npcdist = aware.near.npcs(root, 80,getone)
			closestPlayer, numPlayers, plrsize, plrdist = aware.near.player(root, 80,getone)
			closestRubble, numRubble, rubblesize, rubbledist = aware.near.rubble(root, 20,getone)
			closestChest, numChests, chestsize, chestdist = aware.near.chest(root, 30,getone)
			closestGroundItem, numGroundItems, itemsize, itemdist = aware.near.loot(root, 40,getone)
			closestHouse, numHouses, housesize, housedist = aware.near.house(root, 100,getone)
			closestDungeon, numDungeons, dungsize, dungdist = aware.near.dungeons(root, 200,getone)
			closestFish, numFish, Fishsize, Fishdist = aware.near.fish(root, 120,getone)
			closestFurn, numFurn, Furnsize, Furndist,Furnarray = aware.near.furniture(root, 80,getone)
			objecttable={
				Plant={Close=closestPlant,Amount=numPlants,Size=plantsize,Distance=plantdist},
				Tree={Close=closestTree,Amount=numTrees,Size=treesize,Distance=treedist},
				Structure={Close=closestStructure,Amount=numStructures,Size=structuresize,Distance=strucdist},
				Enemy={Close=closestEnemy,Amount=numEnemies,Size=enemysize,Distance=enemydist},
				NPC={Close=closestNPC,Amount=numNPCs,Size=npcsize,Distance=npcdist},
				Player={Close=closestPlayer,Amount=numPlayers,Size=plrsize,Distance=plrdist},
				Rubble={Close=closestRubble,Amount=numRubble,Size=rubblesize,Distance=rubbledist},
				Chest={Close=closestChest,Amount=numChests,Size=chestsize,Distance=chestdist},
				Item={Close=closestGroundItem,Amount=numGroundItems,Size=itemsize,Distance=itemdist},
				House={Close=closestHouse,Amount=numHouses,Size=housesize,Distance=housedist},
				Area={Close=closestDungeon,Amount=numDungeons,Size=dungsize,Distance=dungdist},
				Fish={Close=closestFish,Amount=numFish,Size=Fishsize,Distance=Fishdist},
				Furniture={Close=closestFurn,Amount=numFurn,Size=Furnsize,Distance=Furndist,Array=Furnarray},
			}
			awarekeys["objective"] = {["datatable"] = nil, ["writetime"] = os.time(), ["refreshrate"] = 10}
		end
	else 
		if mode==nil then mode=false end
		if key=="plant" then return aware.near.plant(root, 40,getone,mode)
		elseif key=="tree" then return aware.near.tree(root, 80,getone,mode)
		elseif key=="structure" then return aware.near.structure(root, 160,getone,mode)
		elseif key=="enemy" then return aware.near.enemy(root, 60,getone,mode)
		elseif key=="npcs" then return aware.near.npcs(root, 80,getone,mode)
		elseif key=="players" then return aware.near.player(root, 80,getone,mode)
		elseif key=="rubble" then return aware.near.rubble(root, 20,getone,mode)
		elseif key=="chests" then return aware.near.chest(root, 30,getone,mode)
		elseif key=="loot" then return aware.near.loot(root, 40,getone,mode)
		elseif key=="houses" then return aware.near.house(root, 100,getone,mode)
		elseif key=="dungeons" then return aware.near.dungeons(root, 200,getone,mode)
		elseif key=="fish" then return aware.near.fish(root, 240,getone,mode) 
		elseif key=="furniture" then return aware.near.furniture(root, 60,getone,mode) end
	end
	return objecttable
end

function aware.judge.amnt(amnt,judgeme,judgeamntdistribution)
	if judgeamntdistribution==nil then judgeamntdistribution=judgeamntdistributio end
	--print(amnt)
	local index = 1
	repeat
		if amnt <= judgeamntdistribution[index] then
			if judgeme then return judgeme[index][aware.quoterandom(1,#judgeme[index])] else return judgeamntstrings[index][1] end -- do not duplicate the table
		end
		index = index + 1
	until index >= #judgeamntdistribution

	return toomany[aware.quoterandom(1,3)]
end
function aware.judge.thing(size, bigSize, judgeSizes, judgeStrings)
	local index = 1
	local sizeJudge = ""
	if typeof(size) == "Vector3" then
		for i, judge in ipairs(judgeSizes) do
			if size <= bigSize * judge then
				local sizeJudge2 = judgeStrings[i]
				sizeJudge = sizeJudge2[aware.mathrandom(1, #sizeJudge)]
				break
			end
		end
	else 
		for i, judge in ipairs(judgeSizes) do
			if size <= bigSize * judge then
				local sizeJudge2 = judgeStrings[i]
				sizeJudge = sizeJudge2[aware.mathrandom(1, #sizeJudge)]
				break
			end
		end
	end
	return sizeJudge
end
function aware.judge.size(size, bigSize)
	local size = size.X + size.Y + size.Z
	local bigSize = bigSize.X + bigSize.Y + bigSize.Z
	local sizeJudge = aware.judge.thing(size, bigSize, judgematrixSizes, judgematrixStrings)
	return sizeJudge
end
function aware.judge.rubble(size, bigSize)
	if size and bigSize then
		local size = size.X + size.Y + size.Z
		local bigSize = bigSize.X + bigSize.Y + bigSize.Z
		local sizeJudge = aware.judge.thing(size, bigSize, rockjudgematrixSizes, rockpiece)
		return sizeJudge
	else return rockpiece[aware.quoterandom(1,#rockpiece)]	
	end	
end
function aware.judge.height(size, bigSize)
	return aware.judge.thing(size, bigSize, heightmatrixSizes , heightmatrixstrings)
end
function aware.judge.power(power, bigpower)
	local sizeJudge = aware.judge.thing(power, bigpower, judgepowerSizes, judgepowerStrings)
	return sizeJudge
end
function aware.judge.object(instance, itself)--implementation of a custom naming system

	if instance ~= nil then
		if instance.Parent then
			if instance.Parent==workspace.Rubble then
				return aware.judge.rubble(Instance.Size, Vector3.new(10,10,10)) 
		--	elseif
			end
		end	
		local s = instance:FindFirstChild("Species")  
		if s then return s.Value end
		local selfrecog = nil
		if instance == itself then
			selfrecog = "I am"
		end
		if instance:FindFirstChild("Humanoid") ~= nil then
			return instance.Humanoid.DisplayName
		elseif instance:IsA("BasePart") then
			local s = instance:FindFirstChild("Species")
			
			if s ~= nil then
				return s.Value

			elseif instance.Parent and instance.Parent:FindFirstChild("Humanoid") ~= nil then
				return instance.Parent.Humanoid.DisplayName 
			elseif string.find(instance.Name,"Rock") then
				return rockpiece[aware.quoterandom(1,#rockpiece)]
			end
		--elseif instance:IsA("Folder") ~= nil then
		--	--  return instance.Name            
		--elseif instance:IsA("Model") then
			--  return instance.Name
		end
		--return instance.Name
		--  end
	end
	return tostring(instance)
end
function aware.judge.item(instance)
	if instance ~= nil then
		if instance.Parent then
			local selfrecog = nil
			if instance:FindFirstChild("Humanoid") ~= nil then
				return instance.Humanoid.DisplayName
			elseif instance:IsA("BasePart") then
				local s = instance:FindFirstChild("Species")
				if s ~= nil then
					return s.Value
				elseif instance.Parent:FindFirstChild("Humanoid") ~= nil then
					return instance.Parent.Humanoid.DisplayName 
				else return instance.Name
				end
			elseif instance:IsA("Folder") ~= nil then
				return instance.Name            
			elseif instance:IsA("Model") then
				return instance.Name
			end
		end
	end
	return nil
end
function aware.judge.distance(root, magnitude, position, position2, maxDist)
	local dirName = ""
	local distanceJudge = ""
	if position ~= position2 then
		local distVector = magnitude

		local judgedDist = {0.2, 0.4, 0.6, 0.8, 1, 1.5, 2}
		local judgeStrings = {
			{"very close", "quite nearby", "within reach", "pretty close", "a stone's throw away"}, 
			{"close", "nearby", "a short distance away", "close by", "not far off"},
			{"kind of close", "not too far", "moderately near", "fairly close", "somewhat near"}, 
			{"not far", "within sight", "a reasonable distance away", "not too distant"},
			{"kinda far", "some distance away", "somewhat distant", "a bit far"},
			{"far", "a long distance away", "quite some ways away", "far away"}, 
			{"very far", "very distant", "quite far"} 
		}

		local index = 1
		if maxDist~=nil then
			repeat
				if index<= #judgedDist then if distVector <= maxDist * judgedDist[index] then
						if distVector > 1 then
							distanceJudge = judgeStrings[index][1]
						else
							distanceJudge = "right here"
						end
						break
					end end
				index = index + 1
			until index >= #judgedDist
		else 
			maxDist=50
			distanceJudge="Distance Error"
			return "Distance Error" ,"Error"
		end
		-- Get direction
		--local rootfront=root.CFrame:ToWorldSpace(CFrame.new(0,0,))  
		local dif=(position2 - position)
		local tolerance = 10 -- define the tolerance value
		local ydifference = position2.Y - position.Y
		if distanceJudge~="" and distanceJudge~=nil and ydifference~=nil then
			if ydifference > tolerance or ydifference < -tolerance then -- compare with the tolerance value
				local heightjudge=aware.judge.height(ydifference, 80)  
				if heightjudge then 
					distanceJudge = distanceJudge .. " "..heightjudge.."me"       
				end
			end
		end
		local dirVector = dif.Unit -- Unit vector pointing to position2
		local angle = math.atan2(dirVector.Z, dirVector.X) -- Angle in radians
		--local dirName = ""
		local leftright=maxDist*.15
		if magnitude>=leftright then
			if distanceJudge ~= "right here" then
				if angle > math.rad(157.5) or angle < math.rad(-157.5) then
					dirName = "south"
				elseif angle > math.rad(112.5) then
					dirName = "southwest"
				elseif angle > math.rad(67.5) then
					dirName = "west"
				elseif angle > math.rad(22.5) then
					dirName = "northwest"
				elseif angle > math.rad(-22.5) then
					dirName = "north"
				elseif angle > math.rad(-67.5) then
					dirName = "northeast"
				elseif angle > math.rad(-112.5) then
					dirName = "east"
				else
					dirName = "southeast"
				end
				dirName=" to the "..dirName
			else
				dirName = " at the current position"
			end

		else dirName=" "..aware.judge.rightfront(root,position2)
		end

	else
		dirName = " at the current position"
		distanceJudge = " right here"
	end
	if dirName==nil then
		dirName="" 
		distanceJudge=""
	end
	if distanceJudge==nil then
		distanceJudge=""
	end
	return distanceJudge, dirName
end
function aware.judge.rightfront(obj1, position2)
	-- First, we need to convert the position2object space of obj1
	-- This means that we will get a new Vector3 value that is relative to the center and orientation of obj1
	-- We can use the ToObjectSpace method of the CFrame class to do this
	local relativePosition = obj1.CFrame:ToObjectSpace(CFrame.new(position2)).Position

	-- Next, we need to get the half size of obj1 along each axis
	-- This will help us determine if the position2 is inside or outside the bounding box of obj1
	local halfSize = obj1.Size * 0.5

	-- Now, we can use some simple logic to classify the relative position
	-- We will use four variables to store the possible directions: left, right, front, and back
	local left, right, front, back = false, false, false, false

	-- We will check each axis separately and set the corresponding variables to true if the condition is met
	-- For the x-axis, we will use the left and right directions
	-- If the relative position is less than the negative half size, it means it is to the left of obj1
	-- If the relative position is greater than the positive half size, it means it is to the right of obj1
	if relativePosition.X < -halfSize.X then
		left = true
	elseif relativePosition.X > halfSize.X then
		right = true
	end

	-- For the z-axis, we will use the front and back directions
	-- If the relative position is less than the negative half size, it means it is behind obj1
	-- If the relative position is greater than the positive half size, it means it is in front of obj1
	if relativePosition.Z < halfSize.Z then
		back = true
	elseif relativePosition.Z > -halfSize.Z then
		front = true
	end

	-- For the y-axis, we will ignore it for now, since we are only interested in the horizontal directions
	-- However, if you want to include the up and down directions, you can use a similar logic as above

	-- Finally, we will construct the output string based on the variables we set
	-- We will use a table to store the possible directions and concatenate them with commas
	local output = {}

	-- We will use a simple if-else statement to check each variable and add the corresponding direction to the table
	-- We will also use the plural form if there are more than one direction
	if back then
		table.insert(output, "behind me")
	elseif front then
		table.insert(output, "in front of me")
	end
	if left then
		table.insert(output, " to the left")
	elseif right then
		table.insert(output, " to the right")
	end



	-- If the output table is empty, it means that the position2 is inside or on the edge of the bounding box of obj1
	-- In that case, we will return a special message
	if #output == 0 then
		return "before me"--"The position is inside or on the edge of the object"
	end

	-- Otherwise, we will join the table elements with commas and return the final string
	return table.concat(output, "")
end
function aware.judge.terrain(root,radius)

	local function detecter(material)
		local materel={}
		--print(material)
		local nummats=0
		for i,v in material do 
			if material[i] then
				if i~="Size" then
					--if material[i][1] then
					for t,o in material[i] do 
						for c,p in material[i][t] do 
							--if --material[i][t][c]~=Enum.Material.Water and
							if material[i][t][c]~=Enum.Material.Air then --count all of the terrain
								local matstring = string.split(tostring(material[i][t][c]),'Enum.Material.')[2]
								if matsolutions[matstring]~=nil then
									matstring= matsolutions[matstring]
								end
								if materel[matstring]==nil then
									nummats+=1
									materel[matstring]=1
								else 
									materel[matstring]+=1
									--table.sort(materel,function(a,b)return a>b end)--sort greatest to 
								end

								--return true
							end
						end 
					end
				end
			end
		end
		--least
		--print(materel)
		--create an array with the keys
		local keys = {}
		for k in pairs(materel) do
			table.insert(keys, k)
		end

		--sort the array using a custom comparison function
		table.sort(keys, function(a, b) return materel[a] < materel[b] end)

		--print the sorted table


		--table.sort(materel,function(a,b)return a>b end)--sort greatest to 


		--table.sort(materel,function(a,b)return a>b end)--sort greatest to least
		local judgeamntstrings = {
			{"a handful of", "a few", "a smattering of", "a sprinkling of"},
			{"a little bit of", "a trace of", "a touch of", "a dash of"},
			{"a sparse amount of", "a scant amount of", "a meager amount of", "a minimal amount of"},
			{"bunches of", "clusters of", "groups of", "packs of"},
			{"a lot of", "heaps of", "a ton of", "loads of"},
			{"a multitude of", "a plethora of", "hordes of", "heaps of"},
			{"a huge quantity of", "a massive amount of", "a colossal amount of", "a prodigious amount of"},
			{"a staggering number of", "an astonishing number of", "a phenomenal number of", "a mind-blowing number of"}
		}

		local judgementstring=""
		local index=0
		--{1, 2, 3, 4, 5, 6, 8}
		local judgmatrix={1,radius,radius*2,radius*3,radius*4,radius*4.5,radius*4.75,radius*5}
		--for i, k in ipairs(keys) do
		--  print(k,)
		--end
		for i,k in keys do 
			index=index+1
			if index==nummats and index>1 then
				judgementstring..="and "
			end

			judgementstring..=aware.judge.amnt(materel[k],judgeamntstrings,judgmatrix).." "..k:lower()
			if index~= nummats then
				judgementstring..=", "
			end
		end

		return judgementstring
	end
	if root then
		local region = Region3.new(root.Position-Vector3.new(radius,8+root.Size.Y,radius),root.Position+Vector3.new(radius,radius,radius))
		local material = terrain:ReadVoxels(region, 4)            
		-- detecter(material) 
		--phraselib.opener[aware.mathrandom(1,#phraselib.opener)]
		return  detecter(material) 
	end		
end
function aware.judge.water(root)
-- Loop through the directions and cast rays
local origin=root.CFrame:ToWorldSpace(CFrame.new(0,5,0)).Position--go above the part to get a better angle
for i, dir in ipairs(waterdirections) do
    local result = workspace:Raycast(origin, dir, params)
    -- Check if the ray hit anything
    if result then
        -- Check if the hit part is water terrain
        if result.Instance:IsA("Terrain") and result.Material == Enum.Material.Water then
             local magn=(origin-result.Position).Magnitude
             local dist, dir = aware.judge.distance(root,magn, origin, result.Position, range)
           
            return phraselib.waterdescription[aware.quoterandom(1,#phraselib.waterdescription)] .. dist .. " to the " .. dir.."",magn
        end
    end

end
return "",nil
end
function aware.judge.distribution(number,matrixSizes,matrixStrings)
	-- Loop through the matrix of height distributions
	for i = 1, #matrixSizes do
		-- Find the index where the number is less than or equal to the matrix value
		if number <= matrixSizes[i] or  i==#matrixSizes then
			-- Return the string at that index
			return matrixStrings[i][1]
		end
	end
end
function aware.judge.human.thickness(number)
	return aware.judge.distribution(number,judgethicknessmatrixSizes,judgethicknessmatrixStrings)
end
function aware.judge.human.size(number)
	return aware.judge.distribution(number,jmatrixSizes,judgehsizematrixStrings)
end
function aware.judge.human.width(number)
	return aware.judge.distribution(number,jmatrixSizes,judgewidthmatrixStrings)
end
function aware.judge.human.height(number)
	return aware.judge.distribution(number, judgeheightmatrixSizes , judgehmatrixStrings)
end
function aware.judge.human.description(humanoid,completeresponse,tenses)
	if humanoid:FindFirstChild("BodyHeightScale") then
		local vars={
			humanoid["BodyTypeScale"].Value,
			humanoid["BodyProportionScale"].Value,
			humanoid["BodyWidthScale"].Value,
			humanoid["BodyHeightScale"].Value,
			humanoid["BodyDepthScale"].Value,
			humanoid["HeadScale"].Value
		}
		local Skincolor=humanoid.Parent:FindFirstChild("Inventory")
		if Skincolor then
			Skincolor=Skincolor.SkinColor.Value
			if tenses==nil then
				Skincolor="My skin is "..Skincolor.." in color, "
			else 
				Skincolor="Your skin is "..Skincolor.." in color, "	
			end	
		end
		if tenses==nil then tenses={"I am ","I have a "} end

		local descguide= {
			-- ["BodyTypeScale"],
			-- ["BodyProportionScale"],
			["BodyWidthScale"]=function () return tenses[1],aware.judge.human.width(vars[3]).." in the hips" end,
			["BodyHeightScale"]=function () return tenses[1],aware.judge.human.height(vars[4]).." in height" end,
			["BodyDepthScale"]=function () return tenses[1],aware.judge.human.thickness(vars[5]).." in the waist" end,
			["HeadScale"]=function () return tenses[2],aware.judge.human.size(vars[6]).." head" end,
		}
		local response={[1]=""}

		if completeresponse==nil then completeresponse="If I were to describe my figure I would say," end
		for i,v in descguide do 
			local v1,v2=descguide[i]() 
			table.insert(response, v1..v2..".")
			if v1=="I am " then
				completeresponse=completeresponse.." "..v2..","
			else
				completeresponse=completeresponse.." "..v1..v2.."."
			end
		end
		response[1]=completeresponse
		if Skincolor then
			response[1]=Skincolor..completeresponse
		end
		return response
	else 
		return {[1]=""}
	end
end
function aware.judge.human.outfit(npc,tense,player)
	--aware.judge.human.Equipment(npc)
	if tense==nil then tense="I am wearing a" end
	local str=tense
	local invent=getinvent(npc,player)
	if invent then
		local customc=invent.CustomCharacter
		local topclothes=invent.TopClothes
		local bottomclothes=invent.PantSkirtDress
		if topclothes.Value~=customc.Value and string.len(topclothes.Value)>3 then -- would imply not wearing an outfit
			str=str.." "..topclothes.Value
			if bottomclothes.Value~=customc.Value and string.len(bottomclothes.Value)>3 then -- would imply not wearing an outfit
				str=str.." and a "..bottomclothes.Value..". "
			else 
				str=str..". "
			end

		elseif  bottomclothes.Value~=customc.Value and string.len(bottomclothes.Value)>3 then
			str=str.." "..bottomclothes.Value..". "

		end
	end
	if str~=tense then
		return str
	else 
		return ""
	end
end
function aware.judge.human.Equipment(npc,player,reflect)
if player:FindFirstChild("Inventory")~=nil then
	local equipmentarray={
		["Armor"]={"my armor is called "},
		["Amulet"]={"I'm wearing a "," around my neck"},
		["Book"]={"I have this magic tome called "},
		["Cape"]={"I have a cape called "," on my back"},
		["Boots"]={"I'm wearing "," on my feet"},
		["Helmet"]={"I have a "," over my head"},
		["Shield"]={"my shield is called "},
		["Sword"]={"my sword is called the "},
		["Gun"]={"I own a "},
		["Wand"]={"my magic wand is called the "},
		["Bracelet"]={"I'm wearing a "," on my wrist"}
	}	
	local theirequipmentarray={
		["Armor"]={"their armor is called "},
		["Amulet"]={"they are wearing a "," around their neck"},
		["Book"]={"they have this magic tome called "},
		["Cape"]={"they have a cape called "," on their back"},
		["Boots"]={"they're wearing "," on their feet"},
		["Helmet"]={"they have a "," over their head"},
		["Shield"]={"their shield is called "},
		["Sword"]={"their sword is called the "},
		["Gun"]={"they own a "},
		["Wand"]={"their magic wand is called the "},
		["Bracelet"]={"they are wearing a "," on their wrist"}
	}
	local yourequipmentarray={
		["Armor"]={"your armor is called "},
		["Amulet"]={"you are wearing a "," around your neck"},
		["Book"]={"you have that magic tome called "},
		["Cape"]={"you have a cape called "," on your back"},
		["Boots"]={"you're wearing "," on your feet"},
		["Helmet"]={"you have a "," over your head"},
		["Shield"]={"your shield is called "},
		["Sword"]={"your sword is called the "},
		["Gun"]={"you own a "},
		["Wand"]={"your magic wand is called the "},
		["Bracelet"]={"you are wearing a "," on your wrist"}
	}	
	local equipmentdescriptions={}	
	local str="I have an array of equipment"
	local invent =getinvent(npc,player)
	local invent2=player.Inventory	
	local theirstr="I can see that "..tostring(player).." has equipment"	
	local gotequipment=false
	if reflect then
		equipmentarray=theirequipmentarray
		str=theirstr
	end	
	if invent then
		--local c=0
		for i,v in equipmentarray do 
			--	c+=1
			if invent[i]~=nil then
				local item=invent[i].Value

				if item~="" and item~=nil and string.len(item)>3 then
					if i=="Wand" or i=="Shield" then
						item=modify_string(item)
					end
					gotequipment=true
					if #v==2 then
						str=str..", "..v[1]..item..""..v[2]
						table.insert(equipmentdescriptions,aware.cap(v[1])..item..""..v[2]..".")
					else 
						str=str..", "..v[1]..item..""
						table.insert(equipmentdescriptions,aware.cap(v[1])..item..".")
					end
				end
			end
		end
		if gotequipment then
			str=str..". "
			table.insert(equipmentdescriptions,str)
			return 	equipmentdescriptions,str
		end	
	end
end	
	return {},""	
end

function aware.near.boid(root, dist, getone,mode)
	if mode==nil then mode=true end
	return aware.get.nearest(aware.Gettable("boid"), root, dist, getone, mode)
end
function aware.near.furniture(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("furniture"), root, dist, getone, mode)
end
function aware.near.rubble(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("rubble"), root, dist, getone, mode)
end
function aware.near.plant(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("plants"), root, dist, getone, mode)
end
function aware.near.crystal(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("crystal"), root, dist, getone, mode)
end
function aware.near.tree(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("trees"), root, dist, getone, mode)
end
function aware.near.house(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("houses"), root, dist, getone, mode)
end
function aware.near.dungeons(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("dungeons"), root, dist, getone, mode)
end
function aware.near.chest(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("chests"), root, dist, getone, mode)
end
function aware.near.mapobj(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("mapobject"), root, dist, getone, mode)
end
function aware.near.loot(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("grounditems"), root, dist, getone, mode)
end
function aware.near.NPC(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("npcs"), root, dist, getone, mode)
end
function aware.near.Enemy(root, dist, getone,mode)
if mode==nil then mode=true end
    --local	enemys =
    return aware.get.nearest(aware.Gettable("enemys"), root, dist, getone, mode)
end
function aware.near.player(root, dist, getone,mode)
if mode==nil then mode=true end
    return aware.get.nearest(aware.Gettable("players"), root, dist, getone, mode)
end
function aware.near.fish(root, dist, getone,mode)
if mode==nil then mode=true end
    if root.Position.Y<=-16 then--if root is lower than the water line
    return aware.get.nearest(aware.Gettable("fish"), root, dist, getone, mode)
    else return nil,0,nil,nil
    end
end

local ranges={}
function aware.quoterandom(min,max)--tries not to repeat concurrent rolls 
	if max==nil then
		max=min
		min=1
	end
	if max>=3 then
	local key=tostring(min..","..max)
	if ranges[key]==nil then
		ranges[key]=math.random(min,max)
	else 
		local previous=ranges[key]
		local roll=math.random(min,max)
		if roll==previous then
			roll=math.random(min,max)
			if roll==previous then
				roll=math.random(min,max)
			end	
		end
		ranges[key]=roll
	end
	return ranges[key]
	else 
		return math.random(min,max)
	end
end

–Excluding Main Function to not exceed post character limit

1 Like

a Function Implementing this library to create a table of observations of every aspect of the environment and combine them in novel ways.

function aware.getsurroundingobjects(root, player,mode,observe,objectmode)
	local data
	--throttle updating the variables

	if root -- observe~=nil or
		--  awarekeys["observations"]["datatable"] == nil or
		-- awarekeys["observations"]["writetime"] + awarekeys["observations"]["refreshrate"] < os.time()
	then --or prevroot~=root
		previousroot=root
		--prevroot=root
		if observe==nil then     
			closestPlant, numPlants, plantsize, plantdist,plantarr = aware.near.plant(root, 80,"array")--plants
			closestBoid, numBoid, boidsize, boiddist,boidarr = aware.near.boid(root, 80,"array")--plants
			closestTree, numTrees, treesize, treedist,treearr = aware.near.tree(root, 160,"array")--trees
			closestStructure, numStructures, structuresize, strucdist,strucarr = aware.near.mapobj(root, 240,"array")
			closestEnemy, numEnemies, enemysize, enemydist,enemyarr = aware.near.Enemy(root, 120,"array")
			closestNPC, numNPCs, npcsize, npcdist,npcarray,npcarr = aware.near.NPC(root, 120,"array")
			closestPlayer, numPlayers, plrsize, plrdist,plrarr = aware.near.player(root, 160,"array")
			closestRubble, numRubble, rubblesize, rubbledist,rubbarr = aware.near.rubble(root, 80,"array")
			closestChest, numChests, chestsize, chestdist,chestarr = aware.near.chest(root, 80,"array")
			closestGroundItem, numGroundItems, itemsize, itemdist,itemarr = aware.near.loot(root, 60,"array")
			closestHouse, numHouses, housesize, housedist = aware.near.house(root, 200)--houses
			closestDungeon, numDungeons, dungsize, dungdist,Dungeonarray = aware.near.dungeons(root, 200,"array")
			closestFish, numFish, Fishsize, Fishdist,fisharr = aware.near.fish(root, 240,"array")
			closestFurn, numFurn, Furnsize, Furndist,Furnarray = aware.near.furniture(root, 80,"array")
			awarekeys["observations"] = {["datatable"] = data, ["writetime"] = os.time(), ["refreshrate"] = 10}--update refresh rate
		else
			--observe={"plants","trees","mapobject","enemys","npcs","players","rubble","chests","grounditems","houses,"dungeons"}
			for i,observ in observe do
				if observ=="plants" then 
					closestPlant, numPlants, plantsize, plantdist = aware.near.plant(root, 80,"array")
				elseif observ=="trees" then
					closestTree, numTrees, treesize, treedist = aware.near.tree(root, 160,"array")
				elseif observ=="mapobject" then
					closestStructure, numStructures, structuresize, strucdist = aware.near.mapobj(root, 240,"array")
				elseif observ=="enemys" then
					closestEnemy, numEnemies, enemysize, enemydist = aware.near.Enemy(root, 120,"array")
				elseif observ=="npcs" then
					closestNPC, numNPCs, npcsize, npcdist = aware.near.NPC(root, 120,"array")
				elseif observ=="players" then
					closestPlayer, numPlayers, plrsize, plrdist = aware.near.player(root, 120,"array")
				elseif observ=="rubble" then
					closestRubble, numRubble, rubblesize, rubbledist = aware.near.rubble(root, 80,"array")
				elseif observ=="chests" then
					closestChest, numChests, chestsize, chestdist = aware.near.chest(root, 80,"array")
				elseif observ=="grounditems" then
					closestGroundItem, numGroundItems, itemsize, itemdist = aware.near.loot(root, 60,"array")
				elseif observ=="houses" then
					closestHouse, numHouses, housesize, housedist = aware.near.house(root, 200,"array")
				elseif observ=="dungeons" then
					closestDungeon, numDungeons, dungsize, dungdist = aware.near.dungeons(root, 200,"array")  
				elseif observ=="fish" then
					closestFish, numFish, Fishsize, Fishdist = aware.near.fish(root, 240,"array")
				elseif observ=="furniture" then
					closestFurn, numFurn, Furnsize, Furndist,Furnarray = aware.near.furniture(root, 80,"array")
				end
			end
		end
	end
	--print({ --debug code to make sure everything is working
	--	closestPlant = closestPlant,
	--	numPlants = numPlants,
	--	plantsize = plantsize,

	--	closestTree = closestTree,
	--	numTrees = numTrees,

	--	closestStructure = closestStructure,
	--	numStructures = numStructures,
	--	structuresize = structuresize,

	--	closestEnemy = closestEnemy,
	--	numEnemies = numEnemies,

	--	closestNPC = closestNPC,
	--	numNPCs = numNPCs,

	--	closestPlayer = closestPlayer,
	--	numPlayers = numPlayers,

	--	closestRubble = closestRubble,
	--	numRubble = numRubble,

	--	closestChest = closestChest,
	--	numChests = numChests,

	--	closestGroundItem = closestGroundItem,
	--	numGroundItems = numGroundItems,

	--	closestHouse = closestHouse,
	--	numHouses = numHouses,
	--	housesize,

	--	closestDungeon = closestDungeon,
	--	numDungeons = numDungeons,
	--	dungsize = dungsize
	--})
	local CompleteObservation
	local pos = root.Position
	--task.wait()--cooldown after getting data
	--print( closestDungeon)
--these functions generalize
	local function describeTrees()
		local treeText=""
		if numTrees > 1 then
			local FurnitureText=treeText
			local FurnitureText,maxiterations=observearray(root,pos,numTrees,closestTree,treearr,"a ")
			--  end
			if numFurn-maxiterations>=2 then
				local Text =
					aware.judge.amnt(numFurn-maxiterations) .. " " .. phraselib.treedesc[aware.quoterandom(1, #phraselib.treedesc)]
				FurnitureText = FurnitureText..", "..Text	
			end
			treeText=FurnitureText
			--end
		end
		return treeText
	end

	local function describePlants()
		local plantText=""
		if numPlants > 1 then
			local FurnitureText=plantText

			if numFurn > 1 and closestFurn and Furnarray then
				--table.sort(Furnarray,function(a,b) return a.Ma)
				--local length=3
				local FurnitureText,maxiterations=observearray(root,pos,numPlants,closestPlant,plantarr,"a ")
				--  end
				if numFurn-maxiterations>=2 then
					local Text =
						aware.judge.amnt(numFurn-maxiterations) .. " " .. phraselib.plantdesc[aware.quoterandom(1, #phraselib.plantdesc)]
					FurnitureText = FurnitureText..", "..Text	
				end
				plantText=FurnitureText
			end
		end
		return plantText
	end
	-- A table that stores different endings for describing rubble
	-- A function that returns a description of the rubble
	local function describeRubble()
		if numRubble > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numRubble,closestRubble,rubbarr,"a ")
			--  end
			if numRubble-maxiterations>=2 then
				local rubbleText = FurnitureText..", "..aware.judge.amnt(numRubble-maxiterations) .. " " .. phraselib.rubbledesc[aware.quoterandom(1, #phraselib.rubbledesc)]
				return rubbleText
			else return FurnitureText		
			end
		end
	end

	-- A table that stores different endings for describing enemies

	-- A function that returns a description of the enemies
	local function describeEnemies()
		if numEnemies > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numEnemies,closestEnemy,enemyarr)
			--  end
			if numEnemies-maxiterations>=2 then
				local enemyText = FurnitureText.. ", "..aware.judge.amnt(numEnemies-maxiterations) .. " " .. phraselib.enemydesc[aware.quoterandom(1, #phraselib.enemydesc)]
				return enemyText
			else return FurnitureText	
			end	
		end
	end

	-- A function that returns a description of the NPCs
	local function describeNPCs()
		if numNPCs > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numNPCs,closestNPC,npcarr)
			--  end
			if numNPCs-maxiterations>=2 then
				local npcText = FurnitureText.. ", "..aware.judge.amnt(numNPCs-maxiterations) .. " " .. phraselib.npcdesc[aware.quoterandom(1, #phraselib.npcdesc)]
				return npcText
			else return FurnitureText	
			end	
		end
	end

	-- A table that stores different endings for describing players

	-- A function that returns a description of the players
	local function describePlayers()
		if numPlayers > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numPlayers,closestPlayer,plrarr)
			--  end
			if numNPCs-maxiterations>=2 then
				local playerText =  FurnitureText.. ", "..aware.judge.amnt(numPlayers-maxiterations) .. " " .. phraselib.playerdesc[aware.quoterandom(1, #phraselib.playerdesc)]
				return playerText
			else return FurnitureText	
			end	
		end
	end

	-- A table that stores different endings for describing chests
	-- A function that returns a description of the chests
	local function describeChests()
		if numChests > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numChests,closestChest,chestarr,"a ")
			--  end
			if numNPCs-maxiterations>=2 then
				local chestText =  FurnitureText.. ", "..aware.judge.amnt(numChests-maxiterations) .. " " .. phraselib.chestdesc[aware.quoterandom(1, #phraselib.chestdesc)]
				return chestText
			else return FurnitureText	
			end	
		end
	end 
	
	local function describeBoids()
		if numChests > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numBoid,closestBoid,boidarr,"a ")
			--  end
			if numBoid-maxiterations>=2 then
				local chestText =  FurnitureText.. ", "..aware.judge.amnt(numChests-maxiterations) .. " " .. phraselib.chestdesc[aware.quoterandom(1, #phraselib.chestdesc)]
				return chestText
			else return FurnitureText	
			end	
		end
	end

	-- A table that stores different endings for describing ground items

	-- A function that returns a description of the ground items
	local function describeGroundItems()
		if numGroundItems > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numGroundItems,closestGroundItem,itemarr,"a ")
			--  end
			if numNPCs-maxiterations>=2 then
				local groundItemText = FurnitureText.. ", "..aware.judge.amnt(numGroundItems-maxiterations) .. " " .. phraselib.grounditemdesc[aware.quoterandom(1, #phraselib.grounditemdesc)]
				return groundItemText
			else return FurnitureText	
			end	
		end
	end
	-- A table that stores different endings for describing houses

	-- A function that returns a description of the houses
	local function describeHouses()
		if numHouses > 1 then
			local houseText = aware.judge.amnt(numHouses) .. " " .. phraselib.housedesc[aware.quoterandom(1, #phraselib.housedesc)]
			return houseText
		end
	end


	local function describeDungeons()--describes the closest 3 furnitures that are not the closest one.
		local FurnitureText = ""
		if numDungeons > 1 and closestDungeon and Dungeonarray then
			--table.sort(Furnarray,function(a,b) return a.Ma)
			--local length=3
			local iterations=0
			local maxiterations=math.min(#Dungeonarray,3)
			for i,closeFurniture in Dungeonarray do  
				if closeFurniture.maininstance~=closestDungeon then    
					iterations+=1
					-- table.insert(arealist,{maininstance=list[h],instance=c,size=g,distance=calc}) 
					if iterations>=2 then FurnitureText=FurnitureText..", " end
					local dist, dir = aware.judge.distance(root,closeFurniture.distance, pos, aware.get.root2(closeFurniture.maininstance).Position, 200)
					FurnitureText = FurnitureText..aware.judge.object(closeFurniture.maininstance) .. " is " .. dist .. "" .. dir
					if iterations>=maxiterations then break end
				end
			end
			--  end
		end
		return FurnitureText
	end
	-- A table that stores different endings for describing structures
	local function describestructures()
		if numStructures > 1 then
			local FurnitureText,maxiterations=observearray(root,pos,numStructures,closestStructure,strucarr,"a ")
			--  end
			if numNPCs-maxiterations>=2 then
				local structureText =FurnitureText.. ", "..aware.judge.amnt(numStructures) .. " " .. phraselib.structuredesc[aware.quoterandom(1, #phraselib.structuredesc)]
				return structureText
			else 
				return FurnitureText
			end	
		end
	end
	
	local function describeFishes()
		local FishText=""

		if numFish~=nil and numFish > 1 then
			local FurnitureText=FishText
			local numFurn=numFish
			local closestFurn=closestFish
			local Furnarray=fisharr
			if numFurn > 1 and closestFurn and Furnarray then
				--table.sort(Furnarray,function(a,b) return a.Ma)
				--local length=3
				local iterations=0
				local maxiterations=math.min(#Furnarray,3)
				for i,closeFurniture in Furnarray do  
					if closeFurniture.maininstance~=closestFurn then    
						iterations+=1
						-- table.insert(arealist,{maininstance=list[h],instance=c,size=g,distance=calc}) 
						if iterations>=2 and iterations~=maxiterations then FurnitureText=FurnitureText..", " end
						local dist, dir = aware.judge.distance(root,closeFurniture.distance, pos, aware.get.root2(closeFurniture.maininstance).Position, 80)
						FurnitureText = FurnitureText..aware.judge.object(closeFurniture.maininstance) .. " " .. dist .. "" .. dir
						if iterations>=maxiterations then break end
					end
				end
				--  end
				if numFish-maxiterations>2 then
					local Text =
						aware.judge.amnt(numFish-maxiterations) .. " " .. phraselib.fishdesc[aware.quoterandom(1, #phraselib.fishdesc)]

					FurnitureText = FurnitureText..", "..Text	
				end	
			end

			return FishText
		end
		return FishText
	end
	
	local function describeFurniture()--describes the closest 3 furnitures that are not the closest one.
		local FurnitureText = ""
		if numFurn >= 1 and closestFurn and Furnarray then
			--table.sort(Furnarray,function(a,b) return a.Ma)
			--local length=3
			local iterations=0
			local maxiterations=math.min(#Furnarray,3)
			for i,closeFurniture in Furnarray do  
				if closeFurniture.maininstance~=closestFurn then    
					iterations+=1
					-- table.insert(arealist,{maininstance=list[h],instance=c,size=g,distance=calc}) 
					if iterations>=2 and iterations~=maxiterations then FurnitureText=FurnitureText..", " end
					local dist, dir = aware.judge.distance(root,closeFurniture.distance, pos, aware.get.root2(closeFurniture.maininstance).Position, 80)
					FurnitureText = FurnitureText..aware.judge.object(closeFurniture.maininstance) .. " " .. dist .. "" .. dir
					if iterations>=maxiterations then break end
				end
			end
			--  end
		end
		return FurnitureText
	end

	local descFurn = describeFurniture()
--call generalize function
	local function describeSurroundings(pos)
		local descStrings = {}

		local descTrees = describeTrees()
		local descPlants = describePlants()
		local descRubble = describeRubble()
		local descEnemies = describeEnemies()
		local descNPCs = describeNPCs()
		local descPlayers = describePlayers()
		local descChests = describeChests()
		local descGroundItems = describeGroundItems()
		local descHouses = describeHouses()
		local descDungeons = describeDungeons()
		local descFish = describeFishes()
		if descFurn then
			table.insert(descStrings, "" .. descFurn)
		end
		if descFish then
			table.insert(descStrings, "" .. descFish)
		end
		if descTrees then
			table.insert(descStrings, "" .. descTrees)
		end
		if descPlants then
			table.insert(descStrings, " " .. descPlants)
		end
		if descRubble then
			table.insert(descStrings, "" .. descRubble)
		end
		if descEnemies then
			table.insert(descStrings, "" .. descEnemies)
		end
		if descNPCs then
			table.insert(descStrings, "" .. descNPCs)
		end
		if descPlayers then
			table.insert(descStrings, "" .. descPlayers)
		end
		if descChests then
			table.insert(descStrings, "" .. descChests)
		end
		if descGroundItems then
			table.insert(descStrings, "" .. descGroundItems)
		end
		if descHouses then
			table.insert(descStrings, "" .. descHouses)
		end
		if descDungeons then
			table.insert(descStrings, "" .. descDungeons)
		end

		-- Remove any nil values
		local finalStrings = {}
		local paragraphstring = ""
		for i, str in ipairs(descStrings) do
			if str ~= "" then
				--table.insert(finalStrings, phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..str..".")
				paragraphstring = paragraphstring .. str .. ", "
			end
		end
		if paragraphstring ~= "" then
			paragraphstring = phraselib.opener[aware.mathrandom(1, #phraselib.opener)] .. paragraphstring .. ". "
			table.insert(finalStrings, paragraphstring)
		end
		-- Join the strings together

		return finalStrings
	end
	
	local function describeSurroundings2(pos)
		local piece = {"piece", "chunk"}
		local rubbleis = {"rubble", "rock"}
		--local tothe={
		local answertable={}
		--local plantarr,treearr,strucarr,npcarr,enemyarr,plrarr,chestarr,itemarr,fisharr,rubbarr
		local function describeRubble2(context)
			local rubbleText = ""

			if closestRubble then


				if closestRubble.Name~="SpawnRoom" then
					local magn = rubbledist
					local dist, dir = aware.judge.distance(root,magn, pos, closestRubble.Position, 20)
					local size = aware.judge.size(closestRubble.Size, Vector3.new(40, 40, 40))
					if dir and dist and size then 
						local crystal=closestRubble:FindFirstChild("Motor6D")
						if crystal then 
							if crystal.Part1 then
								crystal="embedded with a "..crystal.Part1.Name.." is" 
							else crystal="is"end                
						else crystal="is"end 
						rubbleText =
							piece[aware.quoterandom(1, #piece)] ..
							" of " .. size .." ".. rubbleis[aware.quoterandom(1, #rubbleis)].." "..crystal.." ".. dist .. "" .. dir
					end end

			end


			if numRubble > 1 then
				if context == nil then
					return rubbleText, describeRubble()
				else
					rubbleText = rubbleText .. context .. describeRubble()
				end
			end

			return rubbleText
		end
		local function describeChests2(context)
			local chestText = ""

			if closestChest then
				if closestChest.PrimaryPart then
					local magn = chestdist
					local dist, dir = aware.judge.distance(root,magn, pos, closestChest.PrimaryPart.Position, 30)
					--local size = aware.judge.size(closestChest.Size)
					chestText = "chest is " .. dist .. "" .. dir
				end
			end

			if numChests > 1 then
				if context == nil then
					return chestText, describeChests()
				else
					chestText = chestText .. context .. describeChests()
				end
			end

			return chestText
		end
		local function describeGroundItems2(context)
			local groundItemText = ""

			if closestGroundItem then
				local obj = closestGroundItem.Item:FindFirstChildOfClass("BasePart")
				if obj then
					local magn = itemdist
					local dist, dir = aware.judge.distance(root,magn, pos, obj.Position, 40)
					--	local size = aware.judge.size(closestGroundItem.Size,Vector3.new(40,40,40))
					groundItemText = aware.judge.object(closestGroundItem) " is " .. dist .. "" .. dir
				end
			end

			if numGroundItems > 1 then
				if context == nil then
					return groundItemText, describeGroundItems()
				else
					groundItemText = groundItemText .. context .. describeGroundItems()
				end
			end

			return groundItemText
		end
		local function describeHouses2(context)
			local houseText = ""

			if closestHouse then
				local magn = housedist
				local dist, dir = aware.judge.distance(root,magn, pos, closestHouse.PrimaryPart.Position, 100)
				local size = aware.judge.size(closestHouse.PrimaryPart.Size, Vector3.new(100, 100, 100))
				if size==nil then size="" end if dist==nil then dist="someways" end if dir==nil then dir="somewhere around here."  end
				houseText = "" 
					.. size .. 
					" house is "
					.. dist .. ""
					.. dir
			end

			if numHouses > 1 then
				if context == nil then
					return houseText, describeHouses()
				else
					houseText = houseText .. context .. describeHouses()
				end
			end

			return houseText
		end

		local function describeFishes2(context)
			local FishText = ""
			if closestFish then
				-- if closestStructure.PrimaryPart then
				local magn = Fishdist
				local dist, dir = aware.judge.distance(root,magn, pos, closestFish.PrimaryPart.Position, 200)
				local fishdesc=closestFish:GetChildren()
				local amntoffish=#phraselib.fishdesc-1
				local amnt= aware.judge.amnt(amntoffish)
				local fishref= closestFish.PrimaryPart
				local fishname=""
				for i,v in fishdesc do 
					if v.Name~="Primary" and (v:IsA("BasePart") or v:IsA("MeshPart")) then
						fishname=v.Name 
						fishref=v
						break
					end end
				local con=""
				if amntoffish>2 then
					con="School of "
				end

				local size = aware.judge.size(fishref.Size, Vector3.new(6, 6, 6))
				if con==nil then con="" end if amnt==nil then amnt="" end
				if fishname==nil then fishname="" end if dist==nil then dist="" end if dir ==nil then dir="" end  
				if size==nil then size="" else size=size.." " end

				FishText = con..
					amnt.." "..
					size..""..
					fishname .. " are " ..
					dist .. ""..dir.."."--School of Several medium small Blue Tang are far above me to the west,
				--  end
				print(FishText)
			end

			if numFish > 1 then
				if context == nil then
					return FishText, describeFishes()
				else
					FishText = FishText .. context .. describeFishes()
				end
			end
			return FishText
		end

		local function describestructures2(context)
			local dungeonText = ""
			if closestStructure then
				-- if closestStructure.PrimaryPart then
				local magn = strucdist
				local dist, dir = aware.judge.distance(root,magn, pos, closestStructure.PrimaryPart.Position, 200)
				local size = aware.judge.size(closestStructure.PrimaryPart.Size, Vector3.new(200, 100, 200))
				dungeonText = aware.judge.object(closestStructure) .. " is " .. dist .. "" .. dir
				--  end
			end

			if numStructures > 1 then
				if context == nil then
					return dungeonText, describestructures()
				else
					dungeonText = dungeonText .. context .. describestructures()
				end
			end
			return dungeonText
		end

		local function describeFurniture2(context)
			local FurnitureText = ""
			if closestFurn then
				local dist, dir = aware.judge.distance(root,Furndist, pos, aware.get.root2(closestFurn).Position, 200)
				--   local size = aware.judge.size(closestStructure.PrimaryPart.Size, Vector3.new(200, 100, 200))
				FurnitureText = aware.judge.object(closestFurn) .. " " .. dist .. "" .. dir
				--  end
			end

			if numFurn > 1 then
				if context == nil then
					return FurnitureText,descFurn
				else
					FurnitureText = FurnitureText .. context .. descFurn
				end
			end
			return FurnitureText
		end

		local function describeDungeons2(context)
			local dungeonText = ""

			if closestDungeon then
				local strut = {
					"We are in a place called " .. aware.judge.object(closestDungeon) .. "",
					"I believe, we are in an area called " .. aware.judge.object(closestDungeon) .. "",
					"" .. aware.judge.object(closestDungeon) .. "... I believe that's what this place is called",
					"This area is called " .. aware.judge.object(closestDungeon) .. "",
					"If I recall correctly this place is known as " .. aware.judge.object(closestDungeon) .. "",
					"If my navigation skills are correct, this area is called " ..
						aware.judge.object(closestDungeon) .. "",
					"This place is known as " .. aware.judge.object(closestDungeon) .. "",
					"" .. aware.judge.object(closestDungeon) .. " is the name of this land",
					"According to my map, this place is called " .. aware.judge.object(closestDungeon) .. "",
					"I have heard that this place is called " .. aware.judge.object(closestDungeon) .. "",
					"" .. aware.judge.object(closestDungeon) .. ", that's the name of this place",
					"This location is called " .. aware.judge.object(closestDungeon) .. "",
					"From what I know, this place is known as " .. aware.judge.object(closestDungeon) .. "",
					"My compass tells me that this area is called " .. aware.judge.object(closestDungeon) .. "",
					"I have learned that this place is called " .. aware.judge.object(closestDungeon) .. "",
					"" .. aware.judge.object(closestDungeon) .. ", that's the name of this area",
					"This spot is called " .. aware.judge.object(closestDungeon) .. "",
					"Based on my information, this place is known as " .. aware.judge.object(closestDungeon) .. "",
					"My guidebook says that this area is called " .. aware.judge.object(closestDungeon) .. "",
					"I have been told that this place is called " .. aware.judge.object(closestDungeon) .. ""
				}  local obj = closestDungeon:FindFirstChild("Part")
				--  if closestDungeon:FindFirstChildOfClass("BasePart") then
				local dist, dir                      local magn = dungdist
				if obj then                       
					dist, dir = aware.judge.distance(root,magn, pos, obj.Position, 200)
				else 
					dist, dir = "somehwhere ","around here"
				end
				--   if obj then
				-- size = aware.judge.size(obj.Size, Vector3.new(360, 20, 360))
				--end
				dungeonText = strut[aware.quoterandom(1,#strut)]..", the center is " .. dist .. "" .. dir
				-- end
			end

			if numDungeons > 1 then
				if context == nil then
					return dungeonText, describeDungeons()
				else
					dungeonText = dungeonText .. context .. describeDungeons()
				end
			end

			return dungeonText
		end

		local function describeTrees2(context)
			local treeText = ""

			if closestTree then
				if closestTree.PrimaryPart then
					local magn = treedist
					local dist, dir = aware.judge.distance(root,magn, pos, closestTree.PrimaryPart.Position, 160)
					treeText =  aware.judge.object(closestTree) .. " is " .. dist .. "" .. dir
				end
			end

			if numTrees > 1 then
				if context == nil then
					return treeText, describeTrees()
				else
					treeText = treeText .. context .. describeTrees()
				end
			end

			return treeText
		end

		local function describePlants2(context)
			local plantText = ""

			if closestPlant then
				-- if closestPlant:IsA("BasePart") then
				--print(closestPlant) 
				local size = aware.judge.size(closestPlant.Size, Vector3.new(6, 10, 6))

				local magn = plantdist
				local plantid=aware.judge.object(closestPlant)   
				if closestPlant:FindFirstChild("Species")==nil then
					local objnam={"mysterious plant","unidentified plant","uncatalogued plant"}
					plantid=objnam[aware.quoterandom(1,#objnam)]
					if size and size~="" then size=size.." "end 
				else  plantid=" plant called "..plantid   
				end

				local dist, dir = aware.judge.distance(root,magn, pos, closestPlant.Position, 40)                        
				if size==nil then size="" end
				if dir==nil then dir="" end if dist==nil then dist="" end if plantid==nil then plantid="" end
				plantText = size ..  plantid .. 
					" is " .. dist.. dir
			end

			if numPlants > 1 then
				if context == nil then
					return plantText, describePlants()
				else
					plantText = plantText .. context .. describePlants()
				end
			end

			return plantText
		end

		local function describeEnemies2(context)
			local enemyText = ""

			if closestEnemy then
				--   if closestEnemy:FindFirstChild("HumanoidRootPart") then
				local magn = enemydist
				local dist, dir = aware.judge.distance(root,magn, pos, closestEnemy.HumanoidRootPart.Position, 60)
				enemyText = aware.judge.object(closestEnemy, root.Parent) .. " is " .. dist .. "" .. dir
				-- end
			end

			if numEnemies > 1 then
				if context == nil then
					return enemyText, describeEnemies()
				else
					enemyText = enemyText .. context .. aware.judge.amnt(numEnemies) .. " enemies are lurking nearby"
				end
			end

			return enemyText
		end

		local function describePlayers2(context)
			local enemyText = ""

			--	if closestPlayer and closestPlayer~=player then
			if (closestPlayer and closestPlayer ~= player) then
				local magn = plrdist
				local dist, dir = aware.judge.distance(root,magn, pos, closestPlayer.Character.HumanoidRootPart.Position, 80)
				enemyText =
					aware.judge.object(closestPlayer, game.Players:GetPlayerFromCharacter(root.Parent)) ..
					" is " .. dist .. "" .. dir
			elseif mode==1 then
				local magn = (root.Position-player.Character.HumanoidRootPart.Position).Magnitude
				local dist, dir = aware.judge.distance(root,magn, pos, player.Character.HumanoidRootPart.Position, 80)
				enemyText =
					player.Name ..
					" is " .. dist .. "" .. dir
			elseif closestPlayer ~= nil and closestPlayer == player and closestPlayer.Character.HumanoidRootPart~=root and mode==nil then --and closestPlayer==player then
				local plrinter = {
					"I see you before me now.",
					"I'm aware of your presence.",
					"You stand before me.",
					"I see you now.",
					"You are in my sight.",
					"I have you in my view.",
					"You are here with me.",
					"I can sense you.",
					"I can spot you " .. player.Name .. ".",
					"" .. player.Name .. " is that your name?",
					"I can see you " .. player.Name .. "",
					"" .. player.Name .. ", I know who you are.",
					"I can sense you " .. player.Name .. "",
					"" .. player.Name .. ", do you know who I am?",
					"I can observe you " .. player.Name .. "",
					"" .. player.Name .. ", what are you doing here?",
					"I can notice you " .. player.Name .. "",
					"" .. player.Name .. ", do you have a purpose here?",
					"I can hear you " .. player.Name .. ".",
					"" .. player.Name .. ", are you listening to me?",
					"I can feel you " .. player.Name .. ".",
					"I can read you " .. player.Name .. ", do you have a mind?",
					"I can understand you " .. player.Name .. ", do you have a heart?",
					"I can trust you " .. player.Name .. ".",
					"" .. player.Name .. ", do you have a soul?",
					"I can love you " .. player.Name .. "",
					"" .. player.Name .. ", do you have a friend?"
				}


				local interest = plrinter[aware.mathrandom(1, #plrinter)]

				enemyText = interest
			end

			if numPlayers > 1 then
				if context == nil then
					return enemyText, describePlayers()
				else
					enemyText = enemyText .. context .. describePlayers()
				end
			end

			return enemyText
		end

		local function describeNPCs2(context)
			local npcText = ""

			if closestNPC then
				--   if closestNPC:FindFirstChild("HumanoidRootPart")  then
				local magn = npcdist
				local dist, dir = aware.judge.distance(root,magn, pos, closestNPC.HumanoidRootPart.Position, 80)
				npcText = aware.judge.object(closestNPC, root.Parent) .. " is " 
					.. dist .. ""
					.. dir
				-- end
			end

			if numNPCs > 1 then
				if context == nil then
					return npcText, describeNPCs()
				else
					npcText = npcText .. context .. describeNPCs()
				end
			end

			return npcText
		end
		local function describeBoid2(context)
			local npcText = ""

			if closestBoid then
				--   if closestNPC:FindFirstChild("HumanoidRootPart")  then
				local magn = npcdist
				local dist, dir = aware.judge.distance(root,magn, pos, closestBoid.Position, 80)
				npcText = aware.judge.object(closestBoid, root.Parent) .. " is " 
					.. dist .. ""
					.. dir
				-- end
			end


			if numBoid > 1 then
				if context == nil then
					return npcText, describeBoids()
				else
					npcText = npcText .. context ..describeBoids()
				end
			end

			return npcText
		end
		local descStrings = {}

		local descPlayers2 = describePlayers2(", and their are ")
		local descNPCs2 = describeNPCs2(", and their are ")           
		local descEnemies2 = describeEnemies2(", and their are ")           
		local descTrees2 = describeTrees2(", and their are ")
		local descPlants2 = describePlants2(", and their are ")
		local descChests2 = describeChests2(", and their are ")
		local descGroundItems2 = describeGroundItems2(", and their are ")
		local descStructures2=describestructures2(", and their are ")
		local descRubble2 = describeRubble2(", and their are ")                    
		local descHouses2 = describeHouses2(", and their are ")
		local descDungeons2 = describeDungeons2(", and their is ")
		local descFishes2 = describeFishes2(", and their are ")
		local descFurn2 = describeFurniture2(", and their are ")
		local descBoid2 = describeBoid2(", and their are ")
		local flooridentify= aware.get.walking(root,player)

		if root.Parent:FindFirstChild("Humanoid") and root~=player.Character.HumanoidRootPart and mode==nil then
			local Person = root.Parent.Humanoid.DisplayName
			local selfrecognition = "I am " .. Person .. "."
			--local Greetings=personalities.CallPersonality(Person)

			table.insert(descStrings, selfrecognition)
		end

		local function compareDistance(a, b)
			return a[1] > b[1]
		end
		local waterstr,watermagn=aware.judge.water(root)
		local terrainstr=aware.judge.terrain(player.Character.HumanoidRootPart,40)
		local terrainsent		
		if string.len(terrainstr)>3 then		
			terrainsent=aware.get.terrain(nil,nil,terrainstr)
			terrainstr=aware.get.terrain(true,true,terrainstr)
		else terrainsent=nil			
		end			
		local distanceTable = {
			plant = {plantdist, descPlants2},
			terrain = {math.random(1,80), terrainsent},
			tree = {treedist, descTrees2},
			structure = {strucdist, descStructures2},
			enemy = {enemydist, descEnemies2},
			npc = {npcdist, descNPCs2},
			player = {plrdist, descPlayers2},
			rubble = {rubbledist, descRubble2},
			chest = {chestdist, descChests2},
			groundItem = {itemdist, descGroundItems2},
			house = {housedist, descHouses2},
			dungeon = {dungdist, descDungeons2},
			fish = {Fishdist, descFishes2},
			furniture = {Furndist, descFurn2},
			water={watermagn,waterstr},
			floor={math.random(1,30),flooridentify},
			boid={boiddist,descBoid2}		
		}
		--print(distanceTable)
		local descTable = {
			plant = {"a ", descPlants2},
			terrain = {"", terrainstr},
			furniture = {"a ", descFurn2},
			tree = {"a ", descTrees2},
			structure = {"a ", descStructures2},
			enemy = {"", descEnemies2},
			npc = {"", descNPCs2},
			player = {"", descPlayers2},
			rubble = {"a ", descRubble2},
			chest = {"a ", descChests2},
			groundItem = {"a ", descGroundItems2},
			house = {"a ", descHouses2},
			dungeon = {"", descDungeons2},
			fish = {"a ", descFishes2},
			bird = {"a ", descBoid2},		
			water = {"", waterstr},
			floor = {"",flooridentify}   

		}
		--local descStrings2 = {}
		local tre, tree2 = describeTrees2()
		local plan, plan2 = describePlants2()
		local rub, rub2 = describeRubble2()
		local enem, enem2 = describeEnemies2()
		local npc1, npc2 = describeNPCs2()
		local plr1, plr2 = describePlayers2()
		local chest, ches2 = describeChests2()
		local g1, g2 = describeGroundItems2()
		local hous, house = describeHouses2()
		local dung, dungeon = describeDungeons2()
		local struc, struc2 = describestructures2()
		local fishe, fishe2 = describeFishes2()
		local furn, furn2 = describeFurniture2()
		local bird, bird2 = describeBoid2()
		local phraseTable=  { 
			plant = {plan, plan2},
			tree = {tre, tree2},
			structure = {struc, struc2},
			enemy = {enem, enem2},
			npc = {npc1, npc2},
			player = {plr1, plr2},
			rubble = {rub, rub2},
			chest = {chest, ches2},
			groundItem = {g1, g2},
			house = {hous, house},
			dungeon = {dung, dungeon},
			fish = {fishe, fishe2},
			furniture = {furn, furn2},
			boid = {bird, bird2},
			water = {waterstr, ""},  
			floor = {flooridentify, ""},
			terrain = {terrainstr, ""}                  
		}
		local descriptionTable={}
		table.sort(distanceTable, compareDistance)
		local descStrings = {}
		for k, v in pairs(distanceTable) do
			if v[1]~=nil and v[2]~="" then
				table.insert(descStrings, v[2])
			end
		end
		CompleteObservation=""

		local o=0
		local t=0
		local previous=nil
		for i,v in distanceTable do --count number of observations
			if phraseTable[i][1]~="" and phraseTable[i][1]~=nil then
				t=t+1
			end
		end
		local combined={}
		for i,v in distanceTable do  --apply punctuation logic
			if phraseTable[i][1]~="" and phraseTable[i][1]~=nil then--if not blank
				o=o+1
				if previous==nil then
					previous=descTable[i][1]:lower()..phraseTable[i][1]
					--print(previous)
				elseif previous~="" and string.len(previous)>10 then 
					--print(previous..descTable[i][1]:lower()..".")
					table.insert(combined,phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..previous..", and "..descTable[i][1]:lower()..phraseTable[i][1]..". ")
					previous=flooridentify
				end

				if o==1  then--if the first string then
					local sep=", "
					local endin=". "
					if t==1 then --if their is only one string next seperator is and
						sep=", and "
					else --if not last string endin is comma
						endin=", "
					end

					if phraseTable[i][2]~="" and phraseTable[i][2]~=nil then--do both
						CompleteObservation..=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]:lower()..phraseTable[i][1]..sep..phraseTable[i][2]..endin --rng phraselib.opener desc table lower, 


					elseif phraseTable[i][1]~="" and phraseTable[i][1]~=nil then  --do only one
						CompleteObservation..=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]:lower()..phraseTable[i][1]..endin
					end
				elseif o~=t  then --if not the last string
					if phraseTable[i][2]~=""  and phraseTable[i][2]~=nil then--if their is a second string do both
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "..phraseTable[i][2]..", "
					elseif phraseTable[i][1]~="" and phraseTable[i][1]~=nil then --if only first string do one
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "--..phraseTable[i][2]..", "
					end
				else --if the last string
					local begin=""
					if t>1 then -- if more then one element then concatate with and
						begin="and "
					end
					if phraseTable[i][2]~=""  and phraseTable[i][2]~=nil then -- do both strings 
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "..begin..phraseTable[i][2]..". "
					elseif  phraseTable[i][1]~="" and phraseTable[i][1]~=nil then  --do only first string 
						if has_punctuation(phraseTable[i][1]) == false then
							CompleteObservation..=begin..descTable[i][1]:lower()..phraseTable[i][1]..". "
						else 
							CompleteObservation..=begin..descTable[i][1]:lower()..phraseTable[i][1].." "
						end
					end
				end
				--if descTable[i][1]~="" and descTable[i][2]~="" then -- do both strings 

				--descStrings2[o]=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]..descTable[i][2]
				--elseif descTable[i][1]~="" and descTable[i][1]~="a " then
				----and descTable[i][2]~="" then  --do only first string 
				--descStrings2[o]=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]--..descTable[i][2]
				--end

				--descStrings[o]=descTable[i][1]..descTable[i][2]
				descStrings[o]=descTable[i][1]..descTable[i][2]
				descriptionTable[i]=descStrings[o]
				--print(descStrings[t+o])
			end
		end
		if objectmode==true then
			objecttable={
				Plant={Close=closestPlant,Amount=numPlants,Size=plantsize,Distance=plantdist},
				Tree={Close=closestTree,Amount=numTrees,Size=treesize,Distance=treedist},
				Structure={Close=closestStructure,Amount=numStructures,Size=structuresize,Distance=strucdist},
				Enemy={Close=closestEnemy,Amount=numEnemies,Size=enemysize,Distance=enemydist},
				NPC={Close=closestNPC,Amount=numNPCs,Size=npcsize,Distance=npcdist},
				Player={Close=closestPlayer,Amount=numPlayers,Size=plrsize,Distance=plrdist},
				Rubble={Close=closestRubble,Amount=numRubble,Size=rubblesize,Distance=rubbledist},
				Chest={Close=closestChest,Amount=numChests,Size=chestsize,Distance=chestdist},
				Item={Close=closestGroundItem,Amount=numGroundItems,Size=itemsize,Distance=itemdist},
				House={Close=closestHouse,Amount=numHouses,Size=housesize,Distance=housedist},
				Area={Close=closestDungeon,Amount=numDungeons,Size=dungsize,Distance=dungdist},
				Fish={Close=closestFish,Amount=numFish,Size=Fishsize,Distance=Fishdist},
				Furniture={Close=closestFurn,Amount=numFurn,Size=Furnsize,Distance=Furndist},
			}
			return descriptionTable,objecttable
		else


			local function DetermineGoal()
				local interest = ""
				local playeronly = false
				if closestPlayer ~= "" then
					--if player.Name~=closestPlayer then

					--interest=interest.." I can see that "..plr1..""
					--else

					if player ~= nil and root ~= player.Character.HumanoidRootPart and mode==nil then
						playeronly = true
						local plrinter = {
							"I see you before me now.",
							"I'm aware of your presence.",
							"You stand before me.",
							"I see you now.",
							"You are in my sight.",
							"I have you in my view.",
							"You are here with me.",
							"I can sense you.",
							"I can spot you " .. player.Name .. ",",
							"" .. player.Name .. " is that your name?",
							"I can see you " .. player.Name .. ",",
							"" .. player.Name .. ", I know who you are.",
							"I can sense you " .. player.Name .. ",",
							"" .. player.Name .. ", do you know who I am?",
							"I can observe you " .. player.Name .. ".",
							"" .. player.Name .. ", what are you doing here?",
							"I can notice you " .. player.Name .. ".",
							"" .. player.Name .. ", do you have a purpose here?"
						}

						interest = interest .. plrinter[aware.mathrandom(1, #plrinter)]
					end
				end
				if enem ~= "" and enem ~= nil then
					playeronly = false
					local enemt = {
						" Watch out, there is " .. enem .. "",
						"" .. enem .. "",
						" There is " .. enem .. "",
						" I notice " .. enem .. "",
						" I believe there is " .. enem .. "",
						" Be careful, " .. enem .. "",
						" I see " .. enem .. "",
						" I suspect there is " .. enem .. "",
						" Beware of " .. enem .. "."
					}

					interest = interest .. enemt[aware.mathrandom(1, #enemt)]
				end
				if npc1 ~= "" and npc1 ~= nil then
					playeronly = false
					if closestPlayer and interest ~= "" and  has_punctuation(interest) == false  then
						interest = interest .. ", and"
					end
					local npct = {
						" I'm aware of my peer, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. "",
						" I notice that " .. npc1 .. "",
						" I can see my colleague, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. " in my view",
						" I observe that " .. npc1 .. "",
						" I can sense my ally, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. " within my range",
						" I detect that " .. npc1 .. "",
						" I can spot another adventurer, " .. aware.judge.object(closestNPC) .. ""
					}

					interest = interest .. npct[aware.mathrandom(1, #npct)]
				end
				if closestDungeon then
					playeronly = false
					--if not npc1 and interest~="" then
					--	interest=interest..", we "
					--else
					--	interest=interest.." We "
					--end
					if interest ~= "" then
						interest = interest .. "."
					end
					local strut = {
						" We are in a place called " .. aware.judge.object(closestDungeon) .. "",
						" I believe, we are in an area called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. "... I believe that's what this place is called",
						" This area is called " .. aware.judge.object(closestDungeon) .. "",
						" If I recall correctly this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" If my navigation skills are correct, this area is called " ..
							aware.judge.object(closestDungeon) .. "",
						" This place is known as " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. " is the name of this land",
						" According to my map, this place is called " .. aware.judge.object(closestDungeon) .. "",
						" I have heard that this place is called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. ", that's the name of this place",
						" This location is called " .. aware.judge.object(closestDungeon) .. "",
						" From what I know, this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" My compass tells me that this area is called " .. aware.judge.object(closestDungeon) .. "",
						" I have learned that this place is called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. ", that's the name of this area",
						" This spot is called " .. aware.judge.object(closestDungeon) .. "",
						" Based on my information, this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" My guidebook says that this area is called " .. aware.judge.object(closestDungeon) .. "",
						" I have been told that this place is called " .. aware.judge.object(closestDungeon) .. ""
					}

					interest = interest .. strut[aware.mathrandom(1, #strut)]
				end
				if struc ~= "" and struc ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " Their is a " .. struc
				end
				if chest ~= "" and chest ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " I notice a " .. chest .. ""
				end
				if g1 ~= "" and g1 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ","
					end
					interest = interest .. g1
				end
				if hous ~= "" and hous ~= nil then
					playeronly = false
					if struc and interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " I can see a " .. hous .. ""
				end
				if tree2 and tree2 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ". Additionally, t"
					else
						interest = interest .. "T"
					end
					interest = interest .. "heir are " .. tree2
				end
				if plan2 and plan2 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ","
					else
						interest = interest .. " Their are "
					end
					interest = interest .. "" .. plan2 .. ""
				end
				if interest ~= "" and playeronly == false then
					interest = interest .. "."
				end
				if interest~="" then  
					--print(interest) 
				end
				return interest
			end
			--example 	enemyText = aware.judge.object(closestEnemy.Parent).. " is " ..dist.. "" ..dir
			--return enemyText,aware.judge.amnt(numPlayers).." of players are nearby"
			--	enemyText = enemyText ..context.. aware.judge.amnt(numPlayers).." of players are nearby"
			-- Remove any nil values

			local questable=aware.get.QuestData(player)
			if #descStrings>0 then
				--if cm==nil then
				--cm=require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.ChatModule)
				--end
				if questable then
					local questrelevance=processor:Invoke("QueryKeybase",{CompleteObservation,questable,false,false})
					if questrelevance then
						print("Got Quest Relevant Observation!")
						CompleteObservation=CompleteObservation.." "..questrelevance 
					end      
				end 
			end
			local finalStrings = {}
			local paragraphstring = phraselib.opener[aware.mathrandom(1,#phraselib.opener)]
			for i, str in ipairs(descStrings) do
				if str ~= "" and string.len(str)>3 then
					table.insert(finalStrings, phraselib.opener[aware.mathrandom(1, #phraselib.opener)] .. str .. ".")
					if i ~= #descStrings and has_punctuation(str) == false then
						paragraphstring = paragraphstring .. str .. ", "
					elseif has_punctuation(str) == false then
						paragraphstring = paragraphstring .. str .. ". "
					else
						paragraphstring = paragraphstring .. str.." "

					end
				end
			end
			local goal=DetermineGoal()

			if goal~="" then and goatable.insert(finalStrings, goal) end
			if paragraphstring ~= "" then
				if has_punctuation(paragraphstring) == false then
					paragraphstring = paragraphstring .. ". "
				else
					paragraphstring = paragraphstring
				end

				table.insert(finalStrings, paragraphstring)
			end
			print(paragraphstring)
			  print(finalStrings)
			-- Join the strings together
			if dung~="" then        
				finalStrings[#finalStrings+1]= dung
			elseif plan~="" then
				finalStrings[#finalStrings+1]= plan
			elseif tre~="" then
				finalStrings[#finalStrings+1]= tre

			end
			return finalStrings
		end

	end 

	local outfitstr=aware.judge.human.outfit(root.Parent,nil,player)
	local equipmentdesc=aware.judge.human.Equipment(root.Parent,player)
	local equipmentdesc2=nil
	local plroutfitstr=nil
	if root.Parent~=player.Character then
		plroutfitstr=aware.judge.human.outfit(player.Character,tostring(player).." is wearing a",player)
		equipmentdesc2=aware.judge.human.Equipment(player.Character,player,true)
	end

	local d1 = describeSurroundings(pos)
	local d2 = describeSurroundings2(pos)
	local syntheticdata = function()

		for i, str in ipairs(d1) do
			if str ~= "" then
				table.insert(d2, modify_string(str))
			end
		end
		for i, str in ipairs(equipmentdesc) do
			if str ~= "" then
				table.insert(d2, modify_string(str))
			end
		end
		if equipmentdesc2 then
			for i, str in ipairs(equipmentdesc2) do
				if str ~= "" then
					table.insert(d2, modify_string(str))
				end
			end
		end	
		if outfitstr==nil then
			outfitstr=""
		end
		if equipmentdesc~={} and equipmentdesc~=nil and #equipmentdesc>1 then 

			outfitstr=outfitstr..equipmentdesc[#equipmentdesc]
		end
		if equipmentdesc2~={} and equipmentdesc2~=nil and #equipmentdesc2>1 then 
			outfitstr=outfitstr..equipmentdesc2[#equipmentdesc2]
		end
		if plroutfitstr~="" and plroutfitstr~=nil then
			outfitstr=outfitstr..plroutfitstr
		end
		--local powerstr=aware.get.npcdescription(root.Parent)
		--if powerstr~="" then
		--	table.insert(d2, powerstr)
		--	end
		if outfitstr~="" and outfitstr~=nil then
			table.insert(d2, outfitstr)
		end	

		for i, str in ipairs(d2) do
			if str ~= "" then
				d2[i] = modify_string(aware.randomizeStringLight(str, phraselib.syntheticdatasynonms))
			end
		end

		if CompleteObservation~="" and CompleteObservation~="."  and CompleteObservation~=". " then table.insert(d2,CompleteObservation) end
		print(d2)
		if CompleteObservation~="" and CompleteObservation~="." and outfitstr~=nil  and CompleteObservation~=". " then  table.insert(d2,CompleteObservation..outfitstr) end
		print(d2)
		--  print(#d2.." Complete Obersation Index")

		return d2
	end     
	data = syntheticdata()

	return data
end
 
return aware
1 Like

I’m going to have to agree with “bringing some of the best resources onto Roblox.”

For future reference to people reading this, check this creators work out. Quite a bite of on-the-edge ‘Roblox innovation’ happening on this profile’s posts as of writing.

EDIT: Last 3 words

3 Likes

Thank you! If I were to reference some of my favorite recent open source things related to this it would be.

Roleplaying Zephyr 7B Luau API Documentation (Free API) System Message - Resources / Community Resources - Developer Forum | Roblox
All together these components can make for a really cool AI R15 NPC connected to a chatbot.
You put them together you would get something like this.

More example output from the aforementioned Awareness module.

                    [2] = "I can tell that, From what I know, this place is known as Ocean of Morgan, the center is near to the south.",
                    [3] = "It is obvious that, the environment has a smattering of snow, a handful of slate, a touch of ice, bunches of grass, heaps of leafy grass, too several ground, quite a lot of sand, too several basalt, quite a lot of water, and too several rock.",
                    [4] = "If my eyes don't deceive me, a Crystal is close slight below me southwardwest.",
                    [5] = "I am seeing a chunk of small rubble embedded with a Blue Quartz Crystal is kind of near southward, and there are some rocks close southward and a pebble kind of near at the current elevation as me southwardeast a pebble extremely near behind me to the left, .",
                    [6] = "I see It looks like the water is kind of close to the to the west.",
                    [7] = "I am seeing a School of so very many small Bocaccio Rockfish are near slight below me to the south.",
                    [8] = "If I recall correctly this place is known as Ocean of Morgan.",
                    [9] = "I perceive, a Bone Horn close at the current elevation as me to the south, and their are Vertebrae bone close to the southeast, From what I know, this place is known as Ocean of Morgan, the center is close to the south, the environment has a smattering of snow, a handful of slate, a touch of ice, bunches of grass, heaps of leafy grass, too numerous ground, quite a lot of sand, too numerous basalt, quite a lot of water, and too numerous rock, a Crystal is close slight below me to the southwest, a chunk of small rubble embedded with a Blue Quartz Crystal is kind of close to the south, and their are some rocks close to the south and a pebble kind of close at the current elevation as me to the southeast a pebble extremely close behind me to the left, It looks like the water is kind of close to the westward, a School of so very numerous small Bocaccio Rockfish are close slight below me to the south. ",
                    [10] = "Ocean of Morgan is the name of this land, the center is close at the current elevation as me to the south",
                    [11] = "My instinct tells me, Vertebrae bone close southwardeast, , a pebble close above me southward and a rock somewhat near southwardeast a boulder close at the current elevation as me northwardwest, , . ",
                  
       
                 }

[12] = "There is a Bone Horn close to the south, Vertebrae bone not far to the southeast, Ocean of Morgan is the name of this land, the center is close at the current elevation as me to the south, the environment has a smattering of snow, a handful of slate, a touch of ice, bunches of grass, heaps of leafy grass, too many ground, quite a lot of sand, too many basalt, quite a lot of water, and too many rock, a Crystal is not far to the southwest, a chunk of small rubble embedded with a Blue Quartz Crystal is kind of close to the south, a pebble not far to the south and a rock not far to the south a couple of pebbles kind of close to the southeast, It looks like the water is kind of close to the to the west, and a School of quite a lot of Bocaccio Rockfish are close slight below me to the south. ",

That being said I have updated the modules code after reviewing it and also added a new function that handles edge cases for when the objects in the array no longer exist.


function correctPunctuation(inputString)
	-- Replace double commas with a space in between with a single comma
	local correctedString = inputString:gsub(', ,', ',')

	-- Replace double commas with a single comma
	correctedString = correctedString:gsub(',,', ',')

	-- Replace a comma followed by a period with just a period
	correctedString = correctedString:gsub(',%.', '.')

	-- Fix spaces before commas
	correctedString = correctedString:gsub(' ,', ',')

	-- Fix multiple spaces into a single space
	correctedString = correctedString:gsub('%s+', ' ')

	return correctedString
end
2 Likes

Published a new update to this module correcting grammar and potential punctuation issues.
image
[1] = “It is apparent that, my compass tells me that this area is called Ocean of Avalon, the center is very not far behind me.”,
[2] = “I can tell that, the surroundings a characterized by quite a lot of sand, and soo very numerous water.”,
[3] = “It is obvious that, I can see the water is very near to the behind me.”,
[4] = “This spot is called Ocean of Avalon.”,
[5] = "I am observing my compass tells me that this area is called Ocean of Avalon, the center is quite near behind me, the surroundings a characterized by quite a lot of sand, and soo very numerous water, I can see the water is quite near to the behind me. ",
[6] = “Ocean of Avalon, the center is quite near behind me”,
[7] = "If my eyes don’t decieve me. ",
[8] = "What I see is this spot is called Ocean of Avalon, the center is quite not far behind me, the surroundings a characterized by quite a lot of sand, and soo very many water, and I can see the water is quite not far to the behind me. ",
[9] = "What I see is this spot is called Ocean of Avalon, the center is extremely not far behind me, the surroundings are characterized by quite a lot of sand, and soo very many water, and I can see the water is extremely not far to the behind me. "–

After reading this post I corrected the case “to the behind me”

If anyone finds any mistakes let me know!

1 Like

Hey! I really love your project. I also do AIs in Roblox. I have done mnist classifier, and atm I’m planning on making a sentiment analyzer that can tell if your input is negative or positive. It will use a simple Neural Network that will output a number from 0 to 1. If the number is less than 0.5, it will detect your sentence as negative, but if it is 0.5 or bigger, it will detect it as positive. Later on, I’ll add emotion detection. Then I will probably make a Neural Network for a chatbot. I will put it all together, and an AI Chatbot will be born. Hope it goes good.

I hope your project ends up really good!

Best wishes,
tbhrobloxer

1 Like

These are the kinds of cool projects I open community resources once in a blue moon in hope to encounter

1 Like

It’s really amazing. And I love how this guy shows part of the code, explains it and even gives screenshots on the modules etc. Just amazing!

1 Like

Yours too! Your meshVox plugin is a godsend for developers I have gotten such amazing use out of it I’ve been hoping for support for that kind of thing for a while! I’ll be improving this resource soon with a new reformatted version soon that will focus on general usage and short form factor! I made this intentionally complicated to make sure each new object category was working properly but now I want to make it more elegant and pass variables rather the current code which has become redundant over time.

Another system I created is focused on Actions built using the Awareness Library.
Currently not completely useful as open source due to execution relying on interactions and features from a large codebase.

--[[
This Lua code is designed for use within Roblox Studio and involves complex interactions with game objects, NPCs (Non-Player Characters), and spells. It's structured to handle various actions such as navigation, interaction, and spell casting based on textual commands or queries. The code is modular, leveraging multiple tables and functions to process and execute commands within a game environment. Here's a breakdown of its functionality:

Initial Setup
queryspace: A table containing keywords associated with different game elements like enemies, NPCs, chests, etc. Each category has a list of related actions or descriptors.
RunService and isLocal: Determines if the script is running on the client-side.
actions: A table structured to hold various sub-tables for handling objects, navigation, interaction, word models, and spells.
aware, dfg, commands, actionmod: These lines import various modules required for the script to function, such as awareness algorithms, global spells, command processing, and action modules.
SpellCommands and Spells: These sections prepare the script to handle spell commands by loading them into tables for easy access.

Functions Overview
MagicSpell: A function to cast a spell, checking if the character has a tool equipped and using it as the spell's source if present.
querywordspace, keywordspace, querykeys, queryspells: Functions designed to search through the queryspace and SpellsQuery for matches based on the input query. They are used to identify actions or spells related to the query.
awareresponse: Generates a response based on navigation towards a target, including details like distance and direction.
Contextbl: A table of functions that return context-based strings for interactions with different game elements (e.g., enemies, chests, NPCs).
actions.objects, actions.navigate, actions.interact: These sub-tables within actions define functions for object handling, navigation, and interaction based on the game environment and player commands.
actions.spells.query and actions.spells.Cast: Functions for querying available spells based on the input and casting the identified spell.
actions.navigate.navinteract: Handles navigation and interaction with a target based on a query, potentially invoking spell casting if relevant.
actions.navigate.query: The main function that processes a query, identifies the relevant action (navigation, interaction, spell casting), and executes it.

Execution Flow
Initialization: Sets up the environment, loads necessary modules, and prepares spell commands.
Query Processing: When a query is received, it's processed to identify the relevant action - whether it's moving towards an object, interacting with it, or casting a spell.
Action Execution: Based on the query's context, the script executes the appropriate action. This could involve navigating the player towards a target, interacting with game objects, or casting spells.
Response Generation: After executing an action, the script can generate a descriptive response based on the action's outcome, providing feedback to the player.

Key Concepts
Modularity: The script is structured into distinct sections and functions, each handling a specific aspect of the game's interaction model.
Data-Driven: Actions and responses are driven by the queryspace and other data tables, allowing for flexible command processing.
Dynamic Interaction: The script dynamically handles interactions with the game world, allowing players to navigate, interact, and cast spells based on textual commands.
This code snippet is an example of how complex game logic can be implemented in Roblox Studio, leveraging Lua's capabilities for dynamic and interactive game development.
]]
local queryspace={   
    ["Enemy"] = {"readying to assault", "striking", "aiming at","focus","assault","preparing to attack", "attacking", "targeting","target","attack","fight"}, 
    ["NPC"] = {"approaching", "greeting", "following","follow","coming near", "saluting", "trailing","pursue","approach"}, 
    ["chest"] = {"opening", "looting", "unlocking","open","treasure","unsealing", "plundering", "unfastening","unlatch","booty"}, 
    ["crystal"] = {"examining", "admiring", "touching","inspecting", "appreciating", "feeling"}, 
    ["dungeons"] = {"exploring", "investigating", "solving","scouting", "probing", "cracking"}, 
    ["fish"] = {"catching", "fishing", "catch fish","snaring", "angling", "hook fish","fish"}, 
    ["house"] = {"entering", "searching", "leaving","penetrating", "rummaging", "departing"},
    ["loot"] = {"lifting", "gathering", "keeping","plunder","lift","picking up", "collecting", "storing","loot","pick up"}, 
    ["mapobj"] = {"interacting", "ignoring", "destroying","examine","investigate"}, 
    ["plant"] = {"reaping", "gather","pluck","snatch","cultivate","reap","amassing","harvesting", "collect","pick","pick-up","farm","harvest","collecting"}, 
    ["player"] = {"approaching", "greeting", "following"}, 
    ["rubble"] = {"mining", "clearing", "mine rock", "removing", "excavate rock"}, 
    ["tree"] = {"cutting tree", "cut tree","chop tree","woodcut","woodcutting","lumberjack","slicing tree", "fell tree","hew tree","timber","logging","woodsman"}
	
}
local RunService = game:GetService("RunService")
local isLocal = RunService:IsClient()
local actions = {}
actions.objects = {}
actions.navigate = {}
actions.interact = {}
actions.wordmodel = {}
actions.spells={}
--import libraries awareness global spells
local aware = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.Awareness)
local player=game.Players.LocalPlayer
local dfg = require(game.ReplicatedStorage.GlobalSpells)
--subject,target
local commands = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.Commands)
local actionmod = require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.ActionModule)
--local Remote=game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.APICallsLearnData.APIData.RemoteEvent
if isLocal then 
cm=game.Players.LocalPlayer.PlayerGui.Chatbot.LocalProcessor
else  
	cm=game.ReplicatedStorage.GlobalSpells.BindableFunction 
end	
	--dfg.FindPath(Subject,Targ)
local Controller = dfg.LocalController()
local SpellCommands=game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.SpellCommands:GetChildren()
local Spells={}--spells require a humanoid?
local SpellRemote=game.ReplicatedStorage.GlobalSpells:WaitForChild("RemoteEvent")
for i,v in SpellCommands do
Spells[v.Name]=v
end
local SpellsQuery={}
for i,v in SpellCommands do
SpellsQuery[i]=v.Name--:lower()
end

function actions.MagicSpell(Character,player,Type,Target)
if Character:FindFirstChildOfClass("Tool")==nil  then
		Controller.MagicSpell(Character.RightHand,Type,Target,nil,1,player)
	else	
		Controller.MagicSpell(Character:FindFirstChildOfClass("Tool").Handle,Type,Target,nil,1,player)
end	
end

--for i,v in commands do
--Controller[i]=v
--end
--for i,v in commands do
--local i=i
--Controller[i]=function(args) Remote:FireServer(args,i) end
--end

local near = aware.near
local navigation = {""}

local worldmodel = {}

local path = Controller.FindPath
local pathingdebounce = {}
--action.ConductAlchemy(Character,root,Herb)
--action.PickUpObject(Character,Object)
local function querywordspace(query)--query entire word space
for i,c in queryspace do
for t,v in c do
if string.gmatch(query,v)() then
print("Found pattern "..v.." inside "..query)
return v
end
end
end
end

local function keywordspace(query,key)--query key word space
for i,v in queryspace[key] do
if string.gmatch(query,v)() then
print("Found pattern "..v.." inside "..query)
return v
end
end
end


local function querykeys(query)--there are not many of these so i lower is fine.
for i,_ in queryspace do
if string.gmatch(query,i:lower())() then
print("Found pattern "..i.." inside "..query)
return i
end
end
end



local function queryspells(query)
for i,v in SpellsQuery do
if string.gmatch(query,v:lower())() then
print("Found Spell pattern "..v.." inside "..query)
return v
end
end
end

function actions.wordmodel.awareresponse(root, navigationtarget, magnitude, navroot, verb)
    local res = ""
    if navigationtarget then
        local pos = root.CFrame.Position
        if navigationtarget then
            local magn = magnitude
            local dist, dir = aware.judge.distance(root, magn, pos, navroot.Position, 80)
            --local size = aware.judge.size(closestChest.Size)
            if dir ==nil then dir="around here" end  if dist==nil then dist="somewhere" end
            local objstr=aware.judge.object(navigationtarget)
            print(objstr)
            if objstr==nil then objstr=navigationtarget.Name end 
           if verb==nil then verb="walking towards the" end
          print(verb)
        print(objstr)
        print(dist)
        print(dir)
              return "I am " .. verb .. 
                                " " .. objstr .. 
                                            " that is " .. dist ..
                                                                     "" .. dir
        end
    end
end

local Contextbl = {
    --target attack the enemy
    ["Enemy"] = function(root, obj, key)
        return "preparing to attack", aware.get.NPCDescription(obj.Parent)
    end, --walk towards the npc
    ["NPC"] = function(root, obj, key)
        return nil, ""
    end,
     --do nothing just navigate to
    --walk towards and open the chest
    ["chest"] = function(root, obj, key)
        return "walking towards the lock of the", ""
    end, --navigate to the animpoint inside the chest
    --walk towards and examine the crystal
    ["crystal"] = function(root, obj, key)
        return "checking out this", ""
    end,
    ["dungeons"] = function(root, obj, key)
        return "trying to find the center of this", ""
    end,
    ["fish"] = function(root, obj, key)
          if obj then Controller.PickUpObject({root.Parent, obj}) end
        return "swimming towards the", ""
    end,
    ["house"] = function(root, obj, key)
        return "walking towards the door of the", ""
    end,
    ["loot"] = function(root, obj, key)
       if obj then Controller.PickUpObject({root.Parent, obj}) end
        return "attempting to loot the", actionmod.PickUpObject(root.Parent, obj) 
    end,
    ["mapobj"] = function(root, obj, key)
        return nil, ""
    end,
    ["plant"] = function(root, obj, key)
         if obj then Controller.PickUpObject({root.Parent, obj}) end
        return nil, ""
    end,
    ["player"] = function(root, obj, key)
        return nil, ""
    end,
    ["rubble"] = function(root, obj, key, Player)
        local key = "mine rock"
        commands[key](Player, root.Parent)
        return nil, commands.commandresponse(key)
    end,
    ["tree"] = function(root, obj, key, Player)
        commands["cut tree"](Player, root.Parent)
        return nil, commands.commandresponse("cut tree")
    end
}


local keytable= {
   [1] = "crystal",
   [2] = "plant",
   [3] = "tree",
   [4] = "mapobj",
   [5] = "rubble",
   [6] = "chest",
   [7] = "player",
   [8] = "loot",
   [9] = "fish",
   [10] = "NPC",
   [11] = "Enemy",
   [12] = "house",
   [13] = "dungeons"
}

for key, v in near do
    worldmodel[key] = {}
    --get the object with a query
    actions.objects[key] = function(root, player, var, query) --get closest object and query the surroundings
        local closestObject, NumObjects, ObjectSize, ObjectDistance = aware.get.objectsdata(root, key, query)
         --query the array with a string
       -- print(closestObject)
      --  print(query)
        if closestObject~=nil then
        worldmodel[key] = {Close = closestObject, Amount = NumObjects, Size = ObjectSize, Magnitude = ObjectDistance}
        else 
        worldmodel[key] = {Close = nil, Amount = NumObjects, Size = ObjectSize, Magnitude = ObjectDistance}       
        end
         --rebuild the observation
        if var then
            return worldmodel[key][var]
        end
        return worldmodel[key] --return the variable or the table
    end

    actions.navigate[key] = function(root, player, query, verb,navigation) --navigate to the request place/object and return string
        if pathingdebounce[root.Parent.Humanoid.DisplayName] == nil then
            pathingdebounce[root.Parent.Humanoid.DisplayName] = false
        end
        if pathingdebounce[root.Parent.Humanoid.DisplayName] == false then
            if query~=nil then query={Query=query} end
          if navigation==nil then navigation = actions.objects[key](root, player, nil, query) end
             --query the object array with a string with no var to recieve full array of data

            if navigation.Close~=nil then -- if there is a navigate close target return the target and do pathing
                print("Successful Environment Navigation Search") -- The object has beenn found
                print(navigation)
                Controller.WalkTween({root, root.Parent.Humanoid, navigation.Magnitude, 4})
                 --Calculate acceleration based on distance

                local navroot = aware.get.root2(navigation.Close)
                 --get the navigation root

                pathingdebounce[root.Parent.Humanoid.DisplayName] = true
                path({root.Parent, navroot}) --navigate to object

                task.delay(
                    3,
                    function()
                        pathingdebounce[root.Parent.Humanoid.DisplayName] = false
                    end
                )
                 --delay and trigger debounce
               local resultant
                  if verb == nil then
                     verb, resultant = Contextbl[key](root, nil, key, player)   
                    if verb==nil then verb = "walking towards the" end
                end
                return actions.wordmodel.awareresponse(root, navigation.Close, navigation.Magnitude, navroot, verb), navigation,verb,resultant
             --return a string describing the object and its position
            end
        end
        return nil --no result found
    end
    --always returns a string
    actions.interact[key] = function(root, player, query,navigation,destination,verb,resultant) -- navigate and interact with the object
      if verb or resultant==nil then verb, resultant = Contextbl[key](root, nil, key, player) end
      if navigation or destination==nil then destination, navigation = actions.navigate[key](root, player, query, verb) end
        if destination ~= nil then
            Contextbl[key](root, navigation.Close, key, player)
            Controller[key](root, navigation.Close)
            return destination .. " " .. resultant
        end
    return destination
    end

end
local resultcache={}
function actions.spells.query(root,player,query)
local spellkey
--if resultcache[query]==nil then resultcache[query]=queryspells(query) end
--if resultcache[query]~=nil then spellkey=resultcache[query] else 
spellkey= queryspells(query) --end
if spellkey then
--if resultcache[query]==nil then resultcache[query]=spellkey end
local spell=require(Spells[spellkey])
return spell[math.random(1,#spell)],spellkey
end
return nil
end
function actions.spells.Cast(root,player,Target,query)
local spell,Type= actions.spells.query(root,player,query)
if spell then
actions.MagicSpell(root.Parent,player,Type,Target)
return 'I am casting '..Type..". "..spell,Type
end
return nil
end



function actions.navigate.navinteract(root,player,query,key,query2)
        local navigation=actions.objects[key](root, player, nil, query)   --query the namespace and return the navigation result   
  
        if navigation.Close ~= nil then --if close entry is not nil then we got a direct result
        local Result= querywordspace(query) -- if we get a result confirm with different context words which would imply navigation
         if Result then
         local destination,navigation,verb,resultant = actions.navigate[key](root, player, query2,nil,navigation) --navigate and return a string destination, navigation table, the verb and the resultant string
        print("Navigating to target")
        if destination then--if destination string is not nil then we are 
        local actiontoken=  keywordspace(query,key)--search the key word space to determine if interaction
             print("Got Interaction Result")  
        local spellcontext,SpellKey,interaction=nil,nil,nil       
            if actiontoken==nil then --if no action token found in the keyword space search the spells 
            spellcontext,SpellKey=actions.spells.Cast(root,player,navigation.Close,query)                    
            interaction=destination
         
         elseif actiontoken~=nil then --if we have a action token then we should interact with the object
 --  repeat task.wait(.15) until root.Parent.PathingTag:GetAttribute("Complete")==true   --wait for pathing to complete
 interaction=actions.interact[key](root, player, query,navigation,destination,verb,resultant) end
            --return the results as a string 
            if spellcontext==nil and interaction~="" then --no spell casted and interaction was successful
             return interaction,key
           elseif spellcontext~=nil then --spell was cast describe the spell and the navigation string.
         return spellcontext..interaction,SpellKey
         end 
        end
        return destination --return  just the navigation string if nothing else passed.
        end
        end
return nil
end
--this funcion generates 78 commands
function actions.navigate.query(root, player, query)--this function takes a query and executes a action command based on the 
local query=query:lower()
 local result=nil
 for key, v in near do
   local res=actions.navigate.navinteract(root,player,query,key,query)
    if res then return res end
  end
local explicitkey=  querykeys(query)
if explicitkey~=nil then
result=actions.navigate.navinteract(root,player,query,explicitkey,nil)
end
if result==nil then result=actions.spells.Cast(root,player,navigation.Close,query)  end      
resultcache=nil 
   return result
end
--local actions=require(game.ReplicatedStorage.GlobalSpells.ActionModule2)
--actions.navigate.query(root, player, query)
return actions



The Code has been refactored to now have a ‘describe’, and ‘description’ library. This makes the code a lot neater and readable as well as potentially increasing its performance and increasing the versatility of the current code.

It was quite a breeze because I had Bing automatically refactoring the code while making sure their are no issues.

These functions replace the local functions that were located within this snippet.

function aware.getsurroundingobjects(root, player,mode,observe,objectmode)
	local data
	--throttle updating the variables

	if root -- observe~=nil or
		--  awarekeys["observations"]["datatable"] == nil or
		-- awarekeys["observations"]["writetime"] + awarekeys["observations"]["refreshrate"] < os.time()
	then --or prevroot~=root
		previousroot=root
		--prevroot=root
		if observe==nil then     
			closestPlant, numPlants, plantsize, plantdist,plantarr = aware.near.plant(root, 80,"array")--plants
			closestBoid, numBoid, boidsize, boiddist,boidarr = aware.near.boid(root, 80,"array")--plants
			closestTree, numTrees, treesize, treedist,treearr = aware.near.tree(root, 160,"array")--trees
			closestStructure, numStructures, structuresize, strucdist,strucarr = aware.near.mapobj(root, 240,"array")
			closestEnemy, numEnemies, enemysize, enemydist,enemyarr = aware.near.Enemy(root, 120,"array")
			closestNPC, numNPCs, npcsize, npcdist,npcarray,npcarr = aware.near.NPC(root, 120,"array")
			closestPlayer, numPlayers, plrsize, plrdist,plrarr = aware.near.player(root, 160,"array")
			closestRubble, numRubble, rubblesize, rubbledist,rubbarr = aware.near.rubble(root, 80,"array")
			closestChest, numChests, chestsize, chestdist,chestarr = aware.near.chest(root, 80,"array")
			closestGroundItem, numGroundItems, itemsize, itemdist,itemarr = aware.near.loot(root, 60,"array")
			closestHouse, numHouses, housesize, housedist,housearray = aware.near.house(root, 200,"array")--houses
			closestDungeon, numDungeons, dungsize, dungdist,Dungeonarray = aware.near.dungeons(root, 200,"array")
			closestFish, numFish, Fishsize, Fishdist,fisharr = aware.near.fish(root, 240,"array")
			closestFurn, numFurn, Furnsize, Furndist,Furnarray = aware.near.furniture(root, 80,"array")
			awarekeys["observations"] = {["datatable"] = data, ["writetime"] = os.time(), ["refreshrate"] = .6}--update refresh rate
		else
			--observe={"plants","trees","mapobject","enemys","npcs","players","rubble","chests","grounditems","houses,"dungeons"}
			for i,observ in observe do
				if observ=="plants" then 
					closestPlant, numPlants, plantsize, plantdist = aware.near.plant(root, 80,"array")
				elseif observ=="trees" then
					closestTree, numTrees, treesize, treedist = aware.near.tree(root, 160,"array")
				elseif observ=="mapobject" then
					closestStructure, numStructures, structuresize, strucdist = aware.near.mapobj(root, 240,"array")
				elseif observ=="enemys" then
					closestEnemy, numEnemies, enemysize, enemydist = aware.near.Enemy(root, 120,"array")
				elseif observ=="npcs" then
					closestNPC, numNPCs, npcsize, npcdist = aware.near.NPC(root, 120,"array")
				elseif observ=="players" then
					closestPlayer, numPlayers, plrsize, plrdist = aware.near.player(root, 120,"array")
				elseif observ=="rubble" then
					closestRubble, numRubble, rubblesize, rubbledist = aware.near.rubble(root, 80,"array")
				elseif observ=="chests" then
					closestChest, numChests, chestsize, chestdist = aware.near.chest(root, 80,"array")
				elseif observ=="grounditems" then
					closestGroundItem, numGroundItems, itemsize, itemdist = aware.near.loot(root, 60,"array")
				elseif observ=="houses" then
					closestHouse, numHouses, housesize, housedist = aware.near.house(root, 200,"array")
				elseif observ=="dungeons" then
					closestDungeon, numDungeons, dungsize, dungdist = aware.near.dungeons(root, 200,"array")  
				elseif observ=="fish" then
					closestFish, numFish, Fishsize, Fishdist = aware.near.fish(root, 240,"array")
				elseif observ=="furniture" then
					closestFurn, numFurn, Furnsize, Furndist,Furnarray = aware.near.furniture(root, 80,"array")
				end
			end
		end
	end
	--print({ --debug code to make sure everything is working
	--	closestPlant = closestPlant,
	--	numPlants = numPlants,
	--	plantsize = plantsize,

	--	closestTree = closestTree,
	--	numTrees = numTrees,

	--	closestStructure = closestStructure,
	--	numStructures = numStructures,
	--	structuresize = structuresize,

	--	closestEnemy = closestEnemy,
	--	numEnemies = numEnemies,

	--	closestNPC = closestNPC,
	--	numNPCs = numNPCs,

	--	closestPlayer = closestPlayer,
	--	numPlayers = numPlayers,

	--	closestRubble = closestRubble,
	--	numRubble = numRubble,

	--	closestChest = closestChest,
	--	numChests = numChests,

	--	closestGroundItem = closestGroundItem,
	--	numGroundItems = numGroundItems,

	--	closestHouse = closestHouse,
	--	numHouses = numHouses,
	--	housesize,

	--	closestDungeon = closestDungeon,
	--	numDungeons = numDungeons,
	--	dungsize = dungsize
	--})
	local CompleteObservation
	local pos = root.Position
	--task.wait()--cooldown after getting data
	--print( closestDungeon)
	--these functions generalize

local descFurn =  aware.describe.furniture(root, pos, Furnarray, closestFurn, numFurn)
	--call generalize function
	local function describeSurroundings(pos)
		local descStrings = {}
local descStructures=aware.describe.mapobj(root, pos, strucarr, closestStructure, numStructures)
local descTrees = aware.describe.tree(root, pos, treearr, closestTree, numTrees)
local descPlants = aware.describe.plant(root, pos, plantarr, closestPlant, numPlants)
local descRubble = aware.describe.rubble(root, pos, rubbarr, closestRubble, numRubble)
local descEnemies = aware.describe.Enemy(root, pos, enemyarr, closestEnemy, numEnemies)
local descNPCs = aware.describe.NPC(root, pos, npcarr, closestNPC, numNPCs)
local descPlayers = aware.describe.player(root, pos, plrarr, closestPlayer, numPlayers)
local descChests = aware.describe.chest(root, pos, chestarr, closestChest, numChests)
local descGroundItems = aware.describe.loot(root, pos, itemarr, closestGroundItem, numGroundItems)
local descHouses = aware.describe.house(root, pos, housearray, closestHouse, numHouses)
local descDungeons = aware.describe.dungeons(root, pos, Dungeonarray, closestDungeon, numDungeons)
local descFish = aware.describe.fish(root, pos, fisharr, closestFish, numFish)
if descStructures then
	table.insert(descStrings, "" .. descStructures)
end
		if descFurn then
			table.insert(descStrings, "" .. descFurn)
		end
		if descFish then
			table.insert(descStrings, "" .. descFish)
		end
		if descTrees then
			table.insert(descStrings, "" .. descTrees)
		end
		if descPlants then
			table.insert(descStrings, " " .. descPlants)
		end
		if descRubble then
			table.insert(descStrings, "" .. descRubble)
		end
		if descEnemies then
			table.insert(descStrings, "" .. descEnemies)
		end
		if descNPCs then
			table.insert(descStrings, "" .. descNPCs)
		end
		if descPlayers then
			table.insert(descStrings, "" .. descPlayers)
		end
		if descChests then
			table.insert(descStrings, "" .. descChests)
		end
		if descGroundItems then
			table.insert(descStrings, "" .. descGroundItems)
		end
		if descHouses then
			table.insert(descStrings, "" .. descHouses)
		end
		if descDungeons then
			table.insert(descStrings, "" .. descDungeons)
		end

		-- Remove any nil values
		local finalStrings = {}
		local paragraphstring = ""
		for i, str in ipairs(descStrings) do
			if str ~= "" then
				--table.insert(finalStrings, phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..str..".")
				paragraphstring = paragraphstring .. str .. ", "
			end
		end
		if paragraphstring ~= "" then
			paragraphstring = phraselib.opener[aware.mathrandom(1, #phraselib.opener)] .. paragraphstring .. ". "
			table.insert(finalStrings, paragraphstring)
		end
		-- Join the strings together

		return finalStrings
	end

	local function describeSurroundings2(pos)
	
		--local tothe={
		local answertable={}
		--local plantarr,treearr,strucarr,npcarr,enemyarr,plrarr,chestarr,itemarr,fisharr,rubbarr	
		local descStrings = {}
		local descPlayers2 = aware.description.player(root, pos, closestPlayer, plrdist, numPlayers, player, mode, ", and there is ")
		local descNPCs2 = aware.description.NPC(root, pos, closestNPC, npcdist, numNPCs, ", and there is ")
		local descEnemies2 = aware.description.enemy(root, pos, closestEnemy, enemydist, numEnemies, ", and there is ")
		local descTrees2 = aware.description.tree(root, pos, closestTree, treedist, numTrees, ", and there is ")
		local descPlants2 = aware.description.plant(root, pos, closestPlant, plantdist, numPlants, ", and there is ")
		local descChests2 = aware.description.chest(root, pos, closestChest, chestdist, numChests, ", and there is ")
		local descGroundItems2 = aware.description.loot(root, pos, closestGroundItem, itemdist, numGroundItems, ", and there is ")
		local descStructures2 = aware.description.structure(root, pos, closestStructure, strucdist, numStructures, ", and there is ")
		local descRubble2 = aware.description.rubble(root, pos, closestRubble, rubbledist, numRubble, ", and there is ")
		local descHouses2 = aware.description.house(root, pos, closestHouse, housedist, numHouses, ", and there is ")
		local descDungeons2 = aware.description.dungeon(root, pos, closestDungeon, dungdist, numDungeons, ", and their is ")
		local descFishes2 = aware.description.fish(root, pos, closestFish, Fishdist, numFish, ", and there is ")
		local descFurn2 = aware.description.furniture(root, pos, closestFurn, Furndist, numFurn, ", and there is ")
		local descBoid2 = aware.description.boid(root, pos, closestBoid, boiddist, numBoid, ", and there is ")


		local flooridentify= aware.get.walking(root,player)

		if root.Parent:FindFirstChild("Humanoid") and root~=player.Character.HumanoidRootPart and mode==nil then
			local Person = root.Parent.Humanoid.DisplayName
			local selfrecognition = "I am " .. Person .. "."
			--local Greetings=personalities.CallPersonality(Person)

			table.insert(descStrings, selfrecognition)
		end

		local function compareDistance(a, b)
			return a[1] > b[1]
		end
		local waterstr,watermagn=aware.judge.water(root)
		local terrainstr=aware.judge.terrain(player.Character.HumanoidRootPart,40)
		local terrainsent		
		if string.len(terrainstr)>3 then		
			terrainsent=aware.get.terrain(nil,nil,terrainstr)
			terrainstr=aware.get.terrain(true,true,terrainstr)
		else terrainsent=nil			
		end			
		local distanceTable = {
			plant = {plantdist, descPlants2},
			terrain = {math.random(1,80), terrainsent},
			tree = {treedist, descTrees2},
			structure = {strucdist, descStructures2},
			enemy = {enemydist, descEnemies2},
			npc = {npcdist, descNPCs2},
			player = {plrdist, descPlayers2},
			rubble = {rubbledist, descRubble2},
			chest = {chestdist, descChests2},
			groundItem = {itemdist, descGroundItems2},
			house = {housedist, descHouses2},
			dungeon = {dungdist, descDungeons2},
			fish = {Fishdist, descFishes2},
			furniture = {Furndist, descFurn2},
			water={watermagn,waterstr},
			floor={math.random(1,30),flooridentify},
			boid={boiddist,descBoid2}		
		}
		--print(distanceTable)
		local descTable = {
			plant = {"a ", descPlants2},
			terrain = {"", terrainstr},
			furniture = {"a ", descFurn2},
			tree = {"a ", descTrees2},
			structure = {"a ", descStructures2},
			enemy = {"", descEnemies2},
			npc = {"", descNPCs2},
			player = {"", descPlayers2},
			rubble = {"a ", descRubble2},
			chest = {"a ", descChests2},
			groundItem = {"a ", descGroundItems2},
			house = {"a ", descHouses2},
			dungeon = {"", descDungeons2},
			fish = {"a ", descFishes2},
			boid = {"a ", descBoid2},		
			water = {"", waterstr},
			floor = {"",flooridentify}   

		}
		--local descStrings2 = {}
		local tre, tree2 = aware.description.tree(root, pos, closestTree, treedist, numTrees)
		local plan, plan2 = aware.description.plant(root, pos, closestPlant, plantdist, numPlants)
		local rub, rub2 = aware.description.rubble(root, pos, closestRubble, rubbledist, numRubble)
		local enem, enem2 = aware.description.enemy(root, pos, closestEnemy, enemydist, numEnemies)
		local npc1, npc2 = aware.description.NPC(root, pos, closestNPC, npcdist, numNPCs)
		local plr1, plr2 = aware.description.player(root, pos, closestPlayer, plrdist, numPlayers, player, mode)
		local chest, ches2 = aware.description.chest(root, pos, closestChest, chestdist, numChests)
		local g1, g2 = aware.description.loot(root, pos, closestGroundItem, itemdist, numGroundItems)
		local hous, house = aware.description.house(root, pos, closestHouse, housedist, numHouses)
		local dung, dungeon = aware.description.dungeon(root, pos, closestDungeon, dungdist, numDungeons)
		local struc, struc2 = aware.description.structure(root, pos, closestStructure, strucdist, numStructures)
		local fishe, fishe2 = aware.description.fish(root, pos, closestFish, Fishdist, numFish)
		local furn, furn2 = aware.description.furniture(root, pos, closestFurn, Furndist, numFurn)
		local bird, bird2 = aware.description.boid(root, pos, closestBoid, boiddist, numBoid)

		local phraseTable=  { 
			plant = {plan, plan2},
			tree = {tre, tree2},
			structure = {struc, struc2},
			enemy = {enem, enem2},
			npc = {npc1, npc2},
			player = {plr1, plr2},
			rubble = {rub, rub2},
			chest = {chest, ches2},
			groundItem = {g1, g2},
			house = {hous, house},
			dungeon = {dung, dungeon},
			fish = {fishe, fishe2},
			furniture = {furn, furn2},
			boid = {bird, bird2},
			water = {waterstr, ""},  
			floor = {flooridentify, ""},
			terrain = {terrainstr, ""}                  
		}
		local descriptionTable={}
		table.sort(distanceTable, compareDistance)
		local descStrings = {}
		for k, v in pairs(distanceTable) do
			if v[1]~=nil and v[2]~="" then
				table.insert(descStrings, v[2])
			end
		end
		CompleteObservation=""

		local o=0
		local t=0
		local previous=nil
		for i,v in distanceTable do --count number of observations
			if phraseTable[i][1]~="" and phraseTable[i][1]~=nil then
				t=t+1
			end
		end
		local combined={}
		for i,v in distanceTable do  --apply punctuation logic
			if phraseTable[i][1]~="" and phraseTable[i][1]~=nil then--if not blank
				o=o+1
				if previous==nil then
					previous=descTable[i][1]:lower()..phraseTable[i][1]
					--print(previous)
				elseif previous~="" and string.len(previous)>10 then 
					--print(previous..descTable[i][1]:lower()..".")
					table.insert(combined,phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..previous..", and "..descTable[i][1]:lower()..phraseTable[i][1]..". ")
					previous=flooridentify
				end

				if o==1  then--if the first string then
					local sep=", "
					local endin=". "
					if t==1 then --if their is only one string next seperator is and
						sep=", and "
					else --if not last string endin is comma
						endin=", "
					end

					if phraseTable[i][2]~="" and phraseTable[i][2]~=nil then--do both
						CompleteObservation..=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]:lower()..phraseTable[i][1]..sep..phraseTable[i][2]..endin --rng phraselib.opener desc table lower, 


					elseif phraseTable[i][1]~="" and phraseTable[i][1]~=nil then  --do only one
						CompleteObservation..=phraselib.opener[aware.mathrandom(1,#phraselib.opener)]..descTable[i][1]:lower()..phraseTable[i][1]..endin
					end
				elseif o~=t  then --if not the last string
					if phraseTable[i][2]~=""  and phraseTable[i][2]~=nil then--if their is a second string do both
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "..phraseTable[i][2]..", "
					elseif phraseTable[i][1]~="" and phraseTable[i][1]~=nil then --if only first string do one
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "--..phraseTable[i][2]..", "
					end
				else --if the last string
					local begin=""
					if t>1 then -- if more then one element then concatate with and
						begin="and "
					end
					if phraseTable[i][2]~=""  and phraseTable[i][2]~=nil then -- do both strings 
						CompleteObservation..=descTable[i][1]:lower()..phraseTable[i][1]..", "..begin..phraseTable[i][2]..". "
					elseif  phraseTable[i][1]~="" and phraseTable[i][1]~=nil then  --do only first string 
						if has_punctuation(phraseTable[i][1]) == false then
							CompleteObservation..=begin..descTable[i][1]:lower()..phraseTable[i][1]..". "
						else 
							CompleteObservation..=begin..descTable[i][1]:lower()..phraseTable[i][1].." "
						end
					end
				end

				descStrings[o]=descTable[i][1]..descTable[i][2]
				descriptionTable[i]=descStrings[o]
				--print(descStrings[t+o])
			end
		end
		if objectmode==true then
			objecttable={
				Plant={Close=closestPlant,Amount=numPlants,Size=plantsize,Distance=plantdist},
				Tree={Close=closestTree,Amount=numTrees,Size=treesize,Distance=treedist},
				Structure={Close=closestStructure,Amount=numStructures,Size=structuresize,Distance=strucdist},
				Enemy={Close=closestEnemy,Amount=numEnemies,Size=enemysize,Distance=enemydist},
				NPC={Close=closestNPC,Amount=numNPCs,Size=npcsize,Distance=npcdist},
				Player={Close=closestPlayer,Amount=numPlayers,Size=plrsize,Distance=plrdist},
				Rubble={Close=closestRubble,Amount=numRubble,Size=rubblesize,Distance=rubbledist},
				Chest={Close=closestChest,Amount=numChests,Size=chestsize,Distance=chestdist},
				Item={Close=closestGroundItem,Amount=numGroundItems,Size=itemsize,Distance=itemdist},
				House={Close=closestHouse,Amount=numHouses,Size=housesize,Distance=housedist},
				Area={Close=closestDungeon,Amount=numDungeons,Size=dungsize,Distance=dungdist},
				Fish={Close=closestFish,Amount=numFish,Size=Fishsize,Distance=Fishdist},
				Furniture={Close=closestFurn,Amount=numFurn,Size=Furnsize,Distance=Furndist},
			}
			return descriptionTable,objecttable
		else


			local function DetermineGoal()
				local interest = ""
				local playeronly = false
				if closestPlayer ~= "" then
					--if player.Name~=closestPlayer then

					--interest=interest.." I can see that "..plr1..""
					--else

					if player ~= nil and root ~= player.Character.HumanoidRootPart and mode==nil then
						playeronly = true
						local plrinter = {
							"I see you before me now.",
							"I'm aware of your presence.",
							"You stand before me.",
							"I see you now.",
							"You are in my sight.",
							"I have you in my view.",
							"You are here with me.",
							"I can sense you.",
							"I can spot you " .. player.Name .. ",",
							"" .. player.Name .. " is that your name?",
							"I can see you " .. player.Name .. ",",
							"" .. player.Name .. ", I know who you are.",
							"I can sense you " .. player.Name .. ",",
							"" .. player.Name .. ", do you know who I am?",
							"I can observe you " .. player.Name .. ".",
							"" .. player.Name .. ", what are you doing here?",
							"I can notice you " .. player.Name .. ".",
							"" .. player.Name .. ", do you have a purpose here?"
						}

						interest = interest .. plrinter[aware.mathrandom(1, #plrinter)]
					end
				end
				if enem ~= "" and enem ~= nil then
					playeronly = false
					local enemt = {
						" Watch out, there is " .. enem .. "",
						"" .. enem .. "",
						" There is " .. enem .. "",
						" I notice " .. enem .. "",
						" I believe there is " .. enem .. "",
						" Be careful, " .. enem .. "",
						" I see " .. enem .. "",
						" I suspect there is " .. enem .. "",
						" Beware of " .. enem .. "."
					}

					interest = interest .. enemt[aware.mathrandom(1, #enemt)]
				end
				if npc1 ~= "" and npc1 ~= nil then
					playeronly = false
					if closestPlayer and interest ~= "" and  has_punctuation(interest) == false  then
						interest = interest .. ", and"
					end
					local npct = {
						" I'm aware of my peer, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. "",
						" I notice that " .. npc1 .. "",
						" I can see my colleague, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. " in my view",
						" I observe that " .. npc1 .. "",
						" I can sense my ally, " .. aware.judge.object(closestNPC) .. "",
						" " .. npc1 .. " within my range",
						" I detect that " .. npc1 .. "",
						" I can spot another adventurer, " .. aware.judge.object(closestNPC) .. ""
					}

					interest = interest .. npct[aware.mathrandom(1, #npct)]
				end
				if closestDungeon then
					playeronly = false
					--if not npc1 and interest~="" then
					--	interest=interest..", we "
					--else
					--	interest=interest.." We "
					--end
					if interest ~= "" then
						interest = interest .. "."
					end
					local strut = {
						" We are in a place called " .. aware.judge.object(closestDungeon) .. "",
						" I believe, we are in an area called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. "... I believe that's what this place is called",
						" This area is called " .. aware.judge.object(closestDungeon) .. "",
						" If I recall correctly this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" If my navigation skills are correct, this area is called " ..
							aware.judge.object(closestDungeon) .. "",
						" This place is known as " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. " is the name of this land",
						" According to my map, this place is called " .. aware.judge.object(closestDungeon) .. "",
						" I have heard that this place is called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. ", that's the name of this place",
						" This location is called " .. aware.judge.object(closestDungeon) .. "",
						" From what I know, this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" My compass tells me that this area is called " .. aware.judge.object(closestDungeon) .. "",
						" I have learned that this place is called " .. aware.judge.object(closestDungeon) .. "",
						" " .. aware.judge.object(closestDungeon) .. ", that's the name of this area",
						" This spot is called " .. aware.judge.object(closestDungeon) .. "",
						" Based on my information, this place is known as " .. aware.judge.object(closestDungeon) .. "",
						" My guidebook says that this area is called " .. aware.judge.object(closestDungeon) .. "",
						" I have been told that this place is called " .. aware.judge.object(closestDungeon) .. ""
					}

					interest = interest .. strut[aware.mathrandom(1, #strut)]
				end
				if struc ~= "" and struc ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " There is a " .. struc
				end
				if chest ~= "" and chest ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " I notice a " .. chest .. ""
				end
				if g1 ~= "" and g1 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ","
					end
					interest = interest .. g1
				end
				if hous ~= "" and hous ~= nil then
					playeronly = false
					if struc and interest ~= "" then
						interest = interest .. "."
					end
					interest = interest .. " I can see a " .. hous .. ""
				end
				if tree2 and tree2 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ". Additionally, t"
					else
						interest = interest .. "T"
					end
					interest = interest .. "heir are " .. tree2
				end
				if plan2 and plan2 ~= nil then
					playeronly = false
					if interest ~= "" then
						interest = interest .. ","
					else
						interest = interest .. " There is "
					end
					interest = interest .. "" .. plan2 .. ""
				end
				if interest ~= "" and playeronly == false then
					interest = interest .. "."
				end
				if interest~="" then  
					--print(interest) 
				end
				return interest
			end
			--example 	enemyText = aware.judge.object(closestEnemy.Parent).. " is " ..dist.. "" ..dir
			--return enemyText,aware.judge.amnt(numPlayers).." of players are nearby"
			--	enemyText = enemyText ..context.. aware.judge.amnt(numPlayers).." of players are nearby"
			-- Remove any nil values

			local questable=aware.get.QuestData(player)
			if #descStrings>0 then
				--if cm==nil then
				--cm=require(game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.ChatModule)
				--end
				if questable then
					local questrelevance=processor:Invoke("QueryKeybase",{CompleteObservation,questable,false,false})
					if questrelevance then
						print("Got Quest Relevant Observation!")
						CompleteObservation=CompleteObservation.." "..questrelevance 
					end      
				end 
			end
			local finalStrings = {}
			local paragraphstring = phraselib.opener[aware.mathrandom(1,#phraselib.opener)]
			for i, str in ipairs(descStrings) do
				if str ~= "" and string.len(str)>3 then
					table.insert(finalStrings, phraselib.opener[aware.mathrandom(1, #phraselib.opener)] .. str .. ".")
					if i ~= #descStrings and has_punctuation(str) == false then
						paragraphstring = paragraphstring .. str .. ", "
					elseif has_punctuation(str) == false then
						paragraphstring = paragraphstring .. str .. ". "
					else
						paragraphstring = paragraphstring .. str.." "

					end
				end
			end
			local goal=DetermineGoal()

			if goal~="" then table.insert(finalStrings, goal) end
			if paragraphstring ~= "" then
				if has_punctuation(paragraphstring) == false then
					paragraphstring = paragraphstring .. ". "
				else
					paragraphstring = paragraphstring
				end

				table.insert(finalStrings, paragraphstring)
			end
			--	print(paragraphstring)
			--  print(finalStrings)
			-- Join the strings together
			if dung~="" then        
				finalStrings[#finalStrings+1]= dung
			elseif plan~="" then
				finalStrings[#finalStrings+1]= plan
			elseif tre~="" then
				finalStrings[#finalStrings+1]= tre

			end
			return finalStrings
		end

	end 

	local outfitstr=aware.judge.human.outfit(root.Parent,nil,player)
	local equipmentdesc=aware.judge.human.Equipment(root.Parent,player)
	local equipmentdesc2=nil
	local plroutfitstr=nil
	if root.Parent~=player.Character then
		plroutfitstr=aware.judge.human.outfit(player.Character,tostring(player).." is wearing a",player)
		equipmentdesc2=aware.judge.human.Equipment(player.Character,player,true)
	end
	local d1 = describeSurroundings(pos)
	local d2 = describeSurroundings2(pos)
	local syntheticdata = function()

		for i, str in ipairs(d1) do
			if str ~= "" then
				table.insert(d2,str)
			end
		end
		for i, str in ipairs(equipmentdesc) do
			if str ~= "" then
				table.insert(d2, str)
			end
		end
		if equipmentdesc2 then
			for i, str in ipairs(equipmentdesc2) do
				if str ~= "" then
					table.insert(d2, str)
				end
			end
		end	
		if outfitstr==nil then
			outfitstr=""
		end
		if equipmentdesc~={} and equipmentdesc~=nil and #equipmentdesc>1 then 

			outfitstr=outfitstr..equipmentdesc[#equipmentdesc]
		end
		if equipmentdesc2~={} and equipmentdesc2~=nil and #equipmentdesc2>1 then 
			outfitstr=outfitstr..equipmentdesc2[#equipmentdesc2]
		end
		if plroutfitstr~="" and plroutfitstr~=nil then
			outfitstr=outfitstr..plroutfitstr
		end
		--local powerstr=aware.get.npcdescription(root.Parent)
		--if powerstr~="" then
		--	table.insert(d2, powerstr)
		--	end
		if outfitstr~="" and outfitstr~=nil then
			table.insert(d2, outfitstr)
		end	

		if CompleteObservation~="" and CompleteObservation~="."  and CompleteObservation~=". " then table.insert(d2,CompleteObservation) end
		--print(d2)
		if CompleteObservation~="" and CompleteObservation~="." and outfitstr~=nil  and CompleteObservation~=". " then  table.insert(d2,CompleteObservation..outfitstr) end
		for i, str in ipairs(d2) do
			if str ~= "" then
				d2[i] = correctPunctuation(modify_string(aware.randomizeStringLight(str, phraselib.syntheticdatasynonms)))
			end
		end
print(d2)
		--  print(#d2.." Complete Obersation Index")
		return d2
	end     
	data = syntheticdata()

	return data
end

If anyone has any questions, issues, or suggestions concerning this let me know.
This didn’t change the functionality of the code but just makes it more usable, I plan on adding more features such as the next refactor being to return the strings for each category, to increase the versatility of the program further, by further refactoring of the aware.getsurroundingobjects(root, player,)