You can definitely use tags, and organized folders to create a system where one script controls all npcs. as I have done. Also, you can load a asset during runtime, require the modules code once, and delete the module. A easy way to convert a script to a tagged system is to create a module that says
return function(script)
--your code here
end
local taggedinstead=require(functionscript)
game.CollectionService:GetInstanceAddedSignal("TaggedScript"):Connect(taggedinstead)
Management of connections is trivial.
I have converted most of my npcs to be locally animated with one script and it runs very efficiently. Additionally, on the server I have all of my npcs running on one single function that has variable behavior based on attributes. I could write a function in the command line to convert this data to any configuration have it as one copy and not even have this attributed object eliminate the performance bottleneck of GetAttribute() and just use a hash table.
Bindable functions, are great for communication between scripts. a common approach I take is
local requiredmodule=require(modulehere)
BindableFunction.OnInvoke=function(key,payload) --BindableFunction:Invoke("Key",{character,player,true,false})
return requiredmodule[key](payload[1],payload[2],payload[3],payload[4],payload[5],payload[6])--however many variables your functions use
end
You can make incredible things staying organized is key, a style of programming where you repeat your code as little as possible is the best. Recently did a new project, simplified and modularized everything that is repeated, a touch signal, a damage brick, trampoline, spinning objects, clothing items that don’t overlap, moving platforms. So neat when I can copy and paste my touchsignal module, define a couple variables a payload function and not have to create an efficient and functional touch signal gate over and over, return the signals, disconnect them when the time is right.