diff options
| author | Alexander Pickering <alexandermpickering@gmail.com> | 2018-11-03 18:23:45 -0400 |
|---|---|---|
| committer | Alexander Pickering <alexandermpickering@gmail.com> | 2018-11-03 18:23:45 -0400 |
| commit | 28affa22541b9ef251707793f6b1c1a26d663592 (patch) | |
| tree | 622754894d75c74dc5e8516ccf184ad4bf328fef /gamemode | |
| parent | c639e7c7c6ab1595fdce39f56312e3d6a886bbe8 (diff) | |
| download | artery-28affa22541b9ef251707793f6b1c1a26d663592.tar.gz artery-28affa22541b9ef251707793f6b1c1a26d663592.tar.bz2 artery-28affa22541b9ef251707793f6b1c1a26d663592.zip | |
Started on new npc system
Started work on the new npc system
Diffstat (limited to 'gamemode')
33 files changed, 866 insertions, 246 deletions
diff --git a/gamemode/client/cl_inventory.lua b/gamemode/client/cl_inventory.lua index f0c4d07..8f88d7e 100644 --- a/gamemode/client/cl_inventory.lua +++ b/gamemode/client/cl_inventory.lua @@ -12,7 +12,7 @@ ]] --local qinv = nrequire("cl_qinventory.lua") local state = nrequire("cl_state.lua") --Holds weather or not player is in inventory -local itm = nrequire("core/inventory/common/items.lua") +local itm = nrequire("core/inventory/cl_invtracker.lua") local log = nrequire("log.lua") --local qpray = nrequire("cl_qprayers.lua") local inv = {} @@ -99,6 +99,7 @@ end ---Shows the player's inventory. -- If the player's inventory hasn't been built yet, builds the inventory, then displays it. +-- @domain client function inv.ShowInventory() print('Showing inventory') if not qframe then diff --git a/gamemode/config/colortheme.lua b/gamemode/config/colortheme.lua index 13c7a26..c6c2f97 100644 --- a/gamemode/config/colortheme.lua +++ b/gamemode/config/colortheme.lua @@ -36,4 +36,11 @@ theme.ui = { border = Color(113,113,113) } +theme.game = { + -- The text displayed when someone is dammaged + dammagetext = theme.console.foreground, + -- The text displayed next to an npc when editor mode is enabled + npcsettings = theme.console.foreground +} + return theme diff --git a/gamemode/config/sv_newplayer.lua b/gamemode/config/sv_newplayer.lua index 229c11e..403e933 100644 --- a/gamemode/config/sv_newplayer.lua +++ b/gamemode/config/sv_newplayer.lua @@ -1,29 +1,50 @@ +--- Holds the data new players should be spawned with. +-- If new inventories central to the gamemode are added, +-- players should probably spawn with them. Add the +-- inventory to np.data. +--@server sv_newplayer.lua +--@alias np + local np = {} local inv = nrequire("inventory/inventory.lua") nrequire("inventorysystem/equipment/sh_equipment.lua") nrequire("inventorysystem/shapedinventory/sh_shaped.lua") -nrequire("inventorysystem/prayers/sh_prayers.lua") +nrequire("inventorysystem/abilities/sh_abilities.lua") nrequire("inventorysystem/skills/sh_skills.lua") nrequire("inventorysystem/quests/sh_quests.lua") local log = nrequire("log.lua") --local itm = nrequire("inventory/item.lua") -local data = { +--- The data that players spawn with. +-- @table data +-- @field inventories +-- @usage +-- local np = nrequire("config/sv_newplayer.lua") +-- local inv = nrequire("inventory/inventory.lua") +-- local invtbl = np.data.inventories +-- invtbl[#invtbl + 1] = {"My New Inventory",inv.CreateInventory("MyInventory"):Serialize()} +np.data = { inventories = { {"Equipment", inv.CreateInventory("Equipment"):Serialize()}, {"Shaped Inventory",inv.CreateInventory("Shaped Inventory"):Serialize()}, - {"Prayers",inv.CreateInventory("Prayers"):Serialize()}, + {"Abilities",inv.CreateInventory("Abilities"):Serialize()}, {"Skills",inv.CreateInventory("Skills"):Serialize()}, {"Quests",inv.CreateInventory("Quests"):Serialize()}, }, } +--- Function called with a new player needs default data. +-- By default, this function just returns np.data +-- You can overwrite it to return any other table though. +-- @treturn table The new data to return np.newdata = function() log.debug("newdata asked for") - log.debug(table.ToString(data,"data",true)) - return data + log.debug(table.ToString(np.data,"data",true)) + return np.data end +--- Function to return metadata for a player. +-- This just returns a server and location for the player to spawn. np.newmeta = function() log.debug("newmeta asked for") return { diff --git a/gamemode/config/sv_sql.lua b/gamemode/config/sv_sql.lua index a4b5daa..501f8e1 100644 --- a/gamemode/config/sv_sql.lua +++ b/gamemode/config/sv_sql.lua @@ -1,7 +1,20 @@ +--- Defaults relating to the sql database. +-- If you need to change the defaults, nrequire() thi +-- module, then change any of the fields. +-- @server sv_sql.lua + local sql = {} --SQL stuff, be careful to keep this secret! +--- The values in the sql table +-- @table mysql_config +-- @field boolean EnableMySQL=true Should we use MySQLOO to store the data? +-- @field string Host=localhost The hostname that the mysql database lives on +-- @field string Username=root The username to log into the database +-- @field string Password=root The password to log into the database +-- @field number Database_port=3306 The port to connect to the database on +-- @field string Preferred_module=mysqloo The perfered module to use for sql, when multiple are avaliable. local parse = { ["EnableMySQL"] = tobool, ["Host"] = tostring, @@ -34,4 +47,5 @@ for _,line in pairs(string.Explode("\n",mysqlconfig,false)) do sql[key] = parse[key](value) end + return sql diff --git a/gamemode/core/animation/cl_animate.lua b/gamemode/core/animation/cl_animate.lua index c7dc19d..4b86234 100644 --- a/gamemode/core/animation/cl_animate.lua +++ b/gamemode/core/animation/cl_animate.lua @@ -1,3 +1,7 @@ +--- Client side of the animation subsystem +-- Stores the code to run animations client side. +-- Also see @{sh_animations.lua} and @{sv_animate.lua} +-- @client cl_animate.lua net.Receive("art_start_animation",function() local what = net.ReadEntity() @@ -12,6 +16,9 @@ net.Receive("art_stop_animation",function() what:StopLuaAnimation(anim) end) +--- All visible players and their sequences. +-- @table sequences +-- Stores all the sequences for all visible players local sequences = {} net.Receive("art_start_sequence",function() local who = net.ReadEntity() diff --git a/gamemode/core/config/sv_config.lua b/gamemode/core/config/sv_config.lua index 6eb5394..2173dc0 100644 --- a/gamemode/core/config/sv_config.lua +++ b/gamemode/core/config/sv_config.lua @@ -8,12 +8,13 @@ local config = {} local addons = {} local function config_number(panel) - + error("TODO") end local config_types = { ["number"] = config_number, - "text", - "textbox" + ["boolean"] = config_boolean, + ["option"] = config_option, + ["text"] = config_text, } function config.RegisterConfig(name,t,func) assert(config_types[t],string.format("Attempted to register unknown config type %q, allowed types are %s"),t,table.concat(table.GetKeys(config_types))) diff --git a/gamemode/core/inventory/cl_invtracker.lua b/gamemode/core/inventory/cl_invtracker.lua index e6633f9..2591e96 100644 --- a/gamemode/core/inventory/cl_invtracker.lua +++ b/gamemode/core/inventory/cl_invtracker.lua @@ -4,6 +4,7 @@ local inv = nrequire("inventory/inventory.lua") local itm = nrequire("item.lua") +local log = nrequire("log.lua") -- nrequire("cl_loadglobals.lua") --local state = nrequire("cl_state.lua") @@ -122,4 +123,26 @@ concommand.Add("PrintKnownInventories",function(ply,cmd,args) PrintTable(known_inventories) end) +---Drops an item. +-- Client side only, will error if you try to use it server side +--@tparam entity ent_or_tbl the entity that wants to drop the item +--@tparam number invid The inventory number the entity wants to drop from +--@tparam table frompos The position in the inventory the item was in. +function q.DropItem(ent_or_tbl,invid,frompos) + --[[ + if type(ent_or_tbl) == "table" then + drop_self(ent_or_tbl) + else + drop_provided(ent_or_tbl,invid,frompos) + end + ]] + assert(CLIENT,"requested to drop an item when we are not the client!") + log.debug("Drop item was requested, ent_or_tbl is" .. tostring(ent_or_tbl)) + net.Start("art_RequestInvDrop") + net.WriteEntity(ent_or_tbl) + net.WriteUInt(invid,32) + net.WriteTable(frompos) + net.SendToServer() +end + return q diff --git a/gamemode/core/inventory/common/items.lua b/gamemode/core/inventory/common/items.lua deleted file mode 100644 index 65d8e4a..0000000 --- a/gamemode/core/inventory/common/items.lua +++ /dev/null @@ -1,40 +0,0 @@ ----Some common functions for working with items. --- Just one function for now ---@shared items.lua ---@alias items - -local log = nrequire("log.lua") -local items = {} - --- local function drop_provided(ent,invid,frompos) --- assert(CLIENT,"requested to drop an item when we are not the client!") --- net.Start("art_RequestInvDrop") --- net.WriteEntity(ent) --- net.WriteUInt(invid,32) --- net.WriteTable(frompos) --- net.SendToServer() --- end - ----Drops an item. --- Client side only, will error if you try to use it server side ---@tparam entity ent_or_tbl the entity that wants to drop the item ---@tparam number invid The inventory number the entity wants to drop from ---@tparam table frompos The position in the inventory the item was in. -function items.DropItem(ent_or_tbl,invid,frompos) - --[[ - if type(ent_or_tbl) == "table" then - drop_self(ent_or_tbl) - else - drop_provided(ent_or_tbl,invid,frompos) - end - ]] - assert(CLIENT,"requested to drop an item when we are not the client!") - log.debug("Drop item was requested, ent_or_tbl is" .. tostring(ent_or_tbl)) - net.Start("art_RequestInvDrop") - net.WriteEntity(ent_or_tbl) - net.WriteUInt(invid,32) - net.WriteTable(frompos) - net.SendToServer() -end - -return items diff --git a/gamemode/core/mapstich/cl_mapstich.lua b/gamemode/core/mapstich/cl_mapstich.lua index 6f85eeb..dbd332d 100644 --- a/gamemode/core/mapstich/cl_mapstich.lua +++ b/gamemode/core/mapstich/cl_mapstich.lua @@ -2,6 +2,7 @@ The client constantly cheks to see if we're in a serverchnage zone ]] if not nrequire("sh_zones.lua") then return end +local log = nrequire("log.lua") hook.Add("Think","artery_checklevelchange",function() local z pcall(function() @@ -18,5 +19,6 @@ end) net.Receive("art_sendtoserver",function() local where = net.ReadString() - LocalPlayer():ConCommand("connect " .. where) + log.debug("Being sent to another server:" .. where) + --LocalPlayer():ConCommand("connect " .. where) end) diff --git a/gamemode/core/npc/sh_common.lua b/gamemode/core/npc/sh_common.lua new file mode 100644 index 0000000..cd72a61 --- /dev/null +++ b/gamemode/core/npc/sh_common.lua @@ -0,0 +1,7 @@ +--[[ + Some common functions that a lot of npcs use, take out here to make fixing bugs easier. +]] +do return end +local com = {} + +return com diff --git a/gamemode/core/npc/sh_npcsystem.lua b/gamemode/core/npc/sh_npcsystem.lua new file mode 100644 index 0000000..501f21c --- /dev/null +++ b/gamemode/core/npc/sh_npcsystem.lua @@ -0,0 +1,160 @@ +---Various functions for npcs. +-- Helps you spawn monsters, townies, and shopkeepers +--@server sv_npcsystem.lua +--@alias n + +local f = nrequire("concommands.lua") +local log = nrequire("log.lua") +local n = {} +local npcs = {} --Master table of npcs +local autocompletef + +---Registers an NPC. +-- Adds an npc to the global table. NPC's should have unique .Name fields, if they don't, this function will error. +--@see npctbl +--@tparam table npc The npc's table. +function n.RegisterNPC(npc) + assert(npc ~= nil, "Attempted to register a nil npc") + assert(type(npc) == "table", "Attempted to regsiter an npc that was not a table, it was a " .. type(npc)) + assert(npc.Name ~= nil, "Attempted to register an npc without a name") + npcs[npc.Name] = npc + autocompletef = f.AutocompleteFunction(npcs) +end + +function n.GetNPC(name) + assert(npcs[name] ~= nil, "Tried to get npc without name") + return npcs[name] +end + +--Ents to remove when refreshing the npc map +local removeents = {"art_npc", "info_townienode", "npc_shop"} + +if SERVER then + ---Creates an NPC. + -- Creates an npc, by name + --@tparam string npcname The npc's name + --@tparam vector3 pos The position to spawn the npc + function n.CreateNPCByName(npcname, pos) + assert(npcs[npcname],string.format("No npc named %q, valid names are:\n%s",npcname,table.concat(table.GetKeys(npcs),"\n"))) + --print("Createing a ", npcname, " at ", pos) + local npctbl = npcs[npcname] + local npc = ents.Create("npc_huntable") + npc:SetPos(pos) + + for k, v in pairs(npctbl) do + npc[k] = v + end + + npc:Spawn() + + return npc + end + + ---Creats a shop npc. + -- Creates a shop npc from a shop npc table + --@see shopnpctbl + --@tparam table npc The shop npc's table. + function n.CreateShop(npc) + --print("Createing shop npc") + local npcent = ents.Create("art_npc") + local shopkeep = n.GetNPC("Shopkeep") + setmetatable(npc,{__index = function(self,key) + return shopkeep[key] or npcent[key] + end}) + npc:Spawn() + --print("Called spawn") + end + + ---Creates a townie. + -- Creates a new townie that wanders around his areas of intrest + --@see townienpctbl + --@tparam table npc The townie npc's table. + function n.CreateTownie(tbl) + local npcent = ents.Create("art_npc") + local townie = n.GetNPC("Townie") + setmetatable(tbl,{__index = function(self,key) + return townie[key] or npcent[key] + end}) + tbl:Spawn() + end + + ---Create an area of intrest. + -- Creates an point that you can use in a townie's locations of intrest. + --@see navnodetbl + --@tparam table tbl The table for the nav node + function n.CreateNavNode(tbl) + local nodeent = ents.Create("info_townienode") + assert(tbl ~= nil, "Tried to create a nil navnode") + for k, v in pairs(tbl) do + nodeent[k] = v + end + nodeent:Spawn() + end + + for k, v in pairs(removeents) do + local eot = ents.FindByClass(v) + for i, j in pairs(eot) do + j:Remove() + end + end +end + +local function ExecuteOnFolder(dir, recursive, func) + local path = "" + local fpath = table.concat({path,dir,"/*"}) + local files, directories = file.Find(fpath,"DATA") + for k,v in pairs(files) do + local callpath = table.concat({path,dir,"/",v}) + func(callpath) + end + if not recursive then return end + for k,v in pairs(directories) do + local npath = table.concat({dir,"/",v}) + ExecuteOnFolder(npath,true,func) + end +end + +local function loadMap() + local mapname = game.GetMap() + + local foldername = "artery/maps/" .. mapname + ExecuteOnFolder(foldername,true,function(path) + print("I want to run",path) + local filetxt = file.Read(path,"DATA") + --print("File text is", filetxt) + CompileString(filetxt,path)() + --print("I want to execute",path) + end) +end + +hook.Add("InitPostEntity", "artery_spawnmapnpcs", function() + loadMap() +end) + +---Reloads the entities on the map. +-- Removes and then reload all of the entities on the level +--@concommand artery_reloadmap +concommand.Add("artery_reloadmap", function(ply,cmd,args) + if not ply:IsAdmin() then return end + for k, v in pairs(removeents) do + local eot = ents.FindByClass(v) + + for i, j in pairs(eot) do + j:Remove() + end + end + + loadMap() +end) + +---Create a new npc. +-- Creates a new npc a the point the player is looking +--@usage artery_makenpc <npc_name> +--@concommand artery_makenpc +concommand.Add("artery_makenpc", function(ply, cmd, args) + if not ply:IsAdmin() then return end + local na = args[1] + n.CreateNPCByName(na, ply:GetEyeTrace().HitPos) +end, autocompletef) + +return n diff --git a/gamemode/core/npc/sv_common.lua b/gamemode/core/npc/sv_common.lua deleted file mode 100644 index e37a5f8..0000000 --- a/gamemode/core/npc/sv_common.lua +++ /dev/null @@ -1,38 +0,0 @@ ---[[ - Some common functions that a lot of npcs use, take out here to make fixing bugs easier. -]] - -local com = {} - -com.pausefor10sec = function(npc) - npc.StartActionTime = CurTime() + 10 - npc:SetSequence(npc:LookupSequence("idle")) - npc.loco:FaceTowards(Vector(-343, 148, 565)) - local oyaw,oacc = npc.loco:GetMaxYawRate(), npc.loco:GetAcceleration() - timer.Simple(0,function() - npc.loco:SetMaxYawRate(0) - npc.loco:SetAcceleration(0) - npc.loco:SetVelocity(Vector(0,0,0)) - end) - timer.Simple(10, function() - npc.loco:SetMaxYawRate(oyaw) - npc.loco:SetAcceleration(oacc) - end) -end - -com.is10secdone = function(npc) - return npc.StartActionTime < CurTime() -end - -com.Rumors = { - "This is a rumor!", - "Here is another!", - "And yet another!", -} - -com.GetRumor = function() - local rng = math.random(#com.Rumors) - return com.Rumors[rng] -end - -return com diff --git a/gamemode/core/npc/sv_npcsystem.lua b/gamemode/core/npc/sv_npcsystem.lua deleted file mode 100644 index eb149f2..0000000 --- a/gamemode/core/npc/sv_npcsystem.lua +++ /dev/null @@ -1,150 +0,0 @@ ----Various functions for npcs. --- Helps you spawn monsters, townies, and shopkeepers ---@server sv_npcsystem.lua ---@alias n - -local f = nrequire("concommands.lua") -local n = {} -local npcs = {} --Master table of npcs -local autocompletef - ----Registers an NPC. --- Adds an npc to the global table. NPC's should have unique .Name fields, if they don't, this function will error. ---@see npctbl ---@tparam table npc The npc's table. -function n.RegisterNPC(npc) - assert(npc ~= nil, "Attempted to register a nil npc") - assert(npc.Name ~= nil, "Attempted to register an npc without a name") - npcs[npc.Name] = npc - autocompletef = f.AutocompleteFunction(npcs) -end - ----Creates an NPC. --- Creates an npc, by name ---@tparam string npcname The npc's name ---@tparam vector3 pos The position to spawn the npc -function n.CreateNPCByName(npcname, pos) - assert(npcs[npcname],string.format("No npc named %q, valid names are:\n%s",npcname,table.concat(table.GetKeys(npcs),"\n"))) - --print("Createing a ", npcname, " at ", pos) - local npctbl = npcs[npcname] - local npc = ents.Create("npc_huntable") - npc:SetPos(pos) - - for k, v in pairs(npctbl) do - npc[k] = v - end - - npc:Spawn() - - return npc -end - ----Creats a shop npc. --- Creates a shop npc from a shop npc table ---@see shopnpctbl ---@tparam table npc The shop npc's table. -function n.CreateShop(npc) - --print("Createing shop npc") - local npcent = ents.Create("npc_shop") - for k,v in pairs(npc) do - npcent[k] = v - end - npcent:Spawn() - --print("Called spawn") -end - ----Creates a townie. --- Creates a new townie that wanders around his areas of intrest ---@see townienpctbl ---@tparam table npc The townie npc's table. -function n.CreateTownie(tbl) - local npcent = ents.Create("npc_townie") - for k, v in pairs(tbl) do - npcent[k] = v - end - npcent:Spawn() -end - ----Create an area of intrest. --- Creates an point that you can use in a townie's locations of intrest. ---@see navnodetbl ---@tparam table tbl The table for the nav node -function n.CreateNavNode(tbl) - local nodeent = ents.Create("info_townienode") - assert(tbl ~= nil, "Tried to create a nil navnode") - for k, v in pairs(tbl) do - nodeent[k] = v - end - nodeent:Spawn() -end - ---Ents to remove when refreshing the npc map -local removeents = {"npc_townie", "info_townienode", "npc_shop"} - --- "art_chest", -for k, v in pairs(removeents) do - local eot = ents.FindByClass(v) - for i, j in pairs(eot) do - j:Remove() - end -end - -local function ExecuteOnFolder(dir, recursive, func) - local path = "" - local fpath = table.concat({path,dir,"/*"}) - local files, directories = file.Find(fpath,"DATA") - for k,v in pairs(files) do - local callpath = table.concat({path,dir,"/",v}) - func(callpath) - end - if not recursive then return end - for k,v in pairs(directories) do - local npath = table.concat({dir,"/",v}) - ExecuteOnFolder(npath,true,func) - end -end - -local function loadMap() - local mapname = game.GetMap() - - local foldername = "artery/maps/" .. mapname - ExecuteOnFolder(foldername,true,function(path) - print("I want to run",path) - local filetxt = file.Read(path,"DATA") - --print("File text is", filetxt) - CompileString(filetxt,path)() - --print("I want to execute",path) - end) -end - -hook.Add("InitPostEntity", "artery_spawnmapnpcs", function() - loadMap() -end) - ----Reloads the entities on the map. --- Removes and then reload all of the entities on the level ---@concommand artery_reloadmap -concommand.Add("artery_reloadmap", function(ply,cmd,args) - if not ply:IsAdmin() then return end - for k, v in pairs(removeents) do - local eot = ents.FindByClass(v) - - for i, j in pairs(eot) do - j:Remove() - end - end - - loadMap() -end) - ----Create a new npc. --- Creates a new npc a the point the player is looking ---@usage artery_makenpc <npc_name> ---@concommand artery_makenpc -concommand.Add("artery_makenpc", function(ply, cmd, args) - if not ply:IsAdmin() then return end - local na = args[1] - n.CreateNPCByName(na, ply:GetEyeTrace().HitPos) -end, autocompletef) - -return n diff --git a/gamemode/ents/art_npc/cl_art_npc.lua b/gamemode/ents/art_npc/cl_art_npc.lua new file mode 100644 index 0000000..0233666 --- /dev/null +++ b/gamemode/ents/art_npc/cl_art_npc.lua @@ -0,0 +1,139 @@ +local ENT = nrequire("sh_art_npc.lua") +local e = nrequire("editor.lua") +local col = nrequire("colortheme.lua") +print("in cl_art_npc, ENT loaded from sh_art_npc is", ENT) + +ENT.RenderGroup = RENDERGROUP_BOTH + + +local function get_settings_info(what) + -- Settings to display next to an npc + local settings = {} + + settings["Model"] = what:GetModel() + + -- Classes that this npc inherits from, in the order it inherits + local sinh = {} + local sinhc = 1 -- Keep going, even if we encounter nil + local cursor = what + sinh[sinhc] = cursor.Name + while cursor do + cursor = getmetatable(cursor) + if type(cursor) == "table" then + sinh[sinhc] = cursor.Name or "nil" + else + sinh[sinhc] = tostring(cursor) + end + sinhc = sinhc + 1 + end + settings["Inherits from"] = string.format("[%s]",table.concat(sinh,", ")) + + return settings +end + +local settings_info = nil +function ENT:Draw() + if e.Enabled then --What to draw when "Editor" is enabled + self:DrawModel() + + if settings_info == nil then + settings_info = get_settings_info(self) + end + local pos,ang = (self:GetRight() * -32) + (self:GetUp() * 72) + self:GetPos() , self:GetAngles() + + cam.Start3D2D( pos, ang + Angle(0, 90, 90), 0.2 ) + local line = 0 + for k,v in pairs(settings_info) do + draw.DrawText(string.format("%s:%s",k,tostring(v)), "Default", 0, line * 20, col.game.npcsettings ) + line = line + 1 + end + + cam.End3D2D() + else + self:DrawModel() + end +end + +function ENT:DrawTranslucent() + + -- This is here just to make it backwards compatible. + -- You shouldn't really be drawing your model here unless it's translucent + + self:Draw() + +end + +function ENT:BuildBonePositions( NumBones, NumPhysBones ) + + -- You can use this section to position the bones of + -- any animated model using self:SetBonePosition( BoneNum, Pos, Angle ) + + -- This will override any animation data and isn't meant as a + -- replacement for animations. We're using this to position the limbs + -- of ragdolls. + +end + +function ENT:SetRagdollBones( bIn ) + + -- If this is set to true then the engine will call + -- DoRagdollBone (below) for each ragdoll bone. + -- It will then automatically fill in the rest of the bones + + self.m_bRagdollSetup = bIn + +end + +function ENT:DoRagdollBone( PhysBoneNum, BoneNum ) + + -- self:SetBonePosition( BoneNum, Pos, Angle ) + +end + +local chatframe = nil + +net.Receive("art_opennpcdialog",function() + if chatframe ~= nil and chatframe:IsValid() then + chatframe:Remove() + chatframe = nil + end + local width, height = ScrW(), ScrH() + local who = net.ReadEntity() + local chattbl = net.ReadTable() + chatframe = vgui.Create( "DFrame" ) + chatframe:SetPos( (width / 2) - (width / 4), height - (height / 4) ) + chatframe:SetSize( width / 2, height / 4 ) + chatframe:SetTitle( chattbl["Name"] ) + chatframe:SetDraggable( true ) + chatframe.OnClose = function() + net.Start("art_closenpcdialog") + net.WriteEntity(who) + net.SendToServer() + end + + local chattxt = vgui.Create( "DLabel", chatframe ) + --chattxt:SetPos( 40, 40 ) + chattxt:SetText(chattbl["Message"]) + chattxt:Dock(TOP) + + for k,v in pairs(chattbl["Options"]) do + local chatbutton = vgui.Create( "DButton",chatframe ) + --chatbutton:SetPos( 40, 40 ) + chatbutton:SetText( v ) + --chatbutton:SetSize( 120, 60 ) + chatbutton.DoClick = function() + net.Start("art_updatenpcdialog") + net.WriteEntity(who) + net.WriteString(v) + net.SendToServer() + end + chatbutton:Dock(BOTTOM) + end + chattxt:Dock(FILL) + + + + chatframe:MakePopup() +end) + +scripted_ents.Register(ENT, "art_npc") diff --git a/gamemode/ents/art_npc/sh_art_npc.lua b/gamemode/ents/art_npc/sh_art_npc.lua new file mode 100644 index 0000000..c7d549c --- /dev/null +++ b/gamemode/ents/art_npc/sh_art_npc.lua @@ -0,0 +1,14 @@ +local ENT = {} +local base = nrequire("sh_basenpc.lua") + +ENT.Type = "anim" +ENT.Base = "base_nextbot" + +local ent_m = {__index = base} + +hook.Add("artery_core_loaded","load_ent_art_npc",function() + print("At the time artery_core_loaded is called, ENT is", ENT) + setmetatable(ENT,ent_m) +end) + +return ENT diff --git a/gamemode/ents/art_npc/sv_art_npc.lua b/gamemode/ents/art_npc/sv_art_npc.lua new file mode 100644 index 0000000..9c24e9d --- /dev/null +++ b/gamemode/ents/art_npc/sv_art_npc.lua @@ -0,0 +1,180 @@ +local ENT = nrequire("sh_art_npc.lua") +local log = nrequire("log.lua") + +util.AddNetworkString( "art_opennpcdialog" ) +util.AddNetworkString( "art_closenpcdialog" ) +util.AddNetworkString( "art_updatenpcdialog") + +local oinit = ENT.Initalize +function ENT:Initialize() + --self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetSolid(SOLID_BBOX) + self:SetCollisionGroup(COLLISION_GROUP_NPC) + + self:SetHealth(50) + + -- self.loco:SetDeathDropHeight(500) --default 200 + -- self.loco:SetAcceleration(400) --default 400 + -- self.loco:SetDeceleration(400) --default 400 + -- self.loco:SetStepHeight(18) --default 18 + -- self.loco:SetJumpHeight(25) --default 58 + -- self.loco:SetDesiredSpeed( 50 ) + + self.nodereached = false + + self.lastdooropen = CurTime() + + if self.Model then self:SetModel(self.Model) + else log.error("NPC created without model, this might be a bug!") end + + if self.Pos then self:SetPos(self.Pos) + else log.error("NPC created without a position, this might be a bug!") end + + self.talking = false + + if self.Name then self:SetName(self.Name) + else log.error("NPC created without a name! They won't be able to open doors!") end + + if self.Ang then self:SetAngles(self.Ang) end + + if self.OnSpawn then self.OnSpawn(self) end + + self.allowedNodes = {} + self.NavNodes = self.NavNodes or {} + + for k,v in pairs(ents.FindByClass( "info_townienode" ) ) do + if self.NavNodes[v.Name] then + table.insert(self.allowedNodes,v) + end + end + + self:SetUseType( SIMPLE_USE ) + + self.DialogCursors = {} + if oinit then + oinit(self) + end +end + +function ENT:OnInjured(dmg) + if self.OnDammage ~= nil then self:OnDammage(dmg) end +end + +local removeblock = { + ["prop_door_rotating"] = function(bot,ent) + ent:Fire("OpenAwayFrom",bot:GetName()) + timer.Simple(3,function() + ent:Fire("Close") + end) + end +} + +function ENT:BehaveUpdate(num) + if not self.BehaveThread then return end + if self.curnode and self.curnode:IsValid() and self.curnode:GetPos():Distance(self:GetPos()) < 5 then + if self.nodereached == false then + self.curnode.OnReached(self) + self.nodereached = true + else + if self.curnode.IsDone(self) then + --error("Finished action") + self.curnode = self:selectNewNode() + self.nodereached = false + end + end + end + local trdata = { + ["start"] = self:GetPos() + (self:GetUp() * 72), + ["endpos"] = self:GetPos() + (self:GetUp() * 72) + (self:GetForward() * 32), + ["filter"] = self + } + local tr = util.TraceLine(trdata) + local ecl + if (tr ~= nil) and (tr.Entity ~= nil) and tr.Entity:IsValid() then + ecl = tr.Entity:GetClass() + end + if tr.Hit and removeblock[ecl] ~= nil then + removeblock[ecl](self,tr.Entity) + end + local ok, message = coroutine.resume( self.BehaveThread ) + if not ok then + self.BehaveThread = nil + Msg( self, "error: ", message, "\n" ); + end + +end + +function ENT:OnKilled(dmg) + if not self.Drops then return end + for k,v in pairs(self.Drops) do + local rng = math.random(0,100) + local itemname = self.Drops[k][1] + local itemchance = self.Drops[k][2] + local heightoffset = 10 + if rng < itemchance then + local drop = ents.Create("ws_item") + drop.Item = GetItemByName(itemname) + drop:SetModel(drop.Item.Model) + drop:SetPos(self:GetPos() + (self:GetUp() * heightoffset)) + drop:Spawn() + heightoffset = heightoffset + 10 + end + end + self:BecomeRagdoll( dmg ) +end + +local devs = {} +concommand.Add("artery_develop",function(ply,cmd,args) + if not ply:IsAdmin() then return end + if devs[ply] then + devs[ply] = nil + else + devs[ply] = true + end +end) + +--Fix the dialog so we aren't sending functions +local function SendableDialog(tbl) + local ntbl = table.Copy(tbl) + ntbl["Options"] = table.GetKeys(tbl["Options"]) + return ntbl +end + +function ENT:Use(ply) + if devs[ply] then + + else + + self.DialogCursors[ply] = self.getDialogFor(ply) + -- + -- if self.oyaw ~= 0 and self.oacc ~= 0 then + -- self.oyaw, self.oacc,self.onod = self.loco:GetMaxYawRate(), self.loco:GetAcceleration(), self.curnode + -- end + -- self.loco:SetAcceleration(0) + -- self.loco:SetVelocity(Vector(0,0,0)) + -- self.loco:SetMaxYawRate(9999990) + -- self.loco:FaceTowards(ply:GetPos()) + -- self.loco:SetMaxYawRate(0) + timer.Simple(0.5,function() + --self.loco:FaceTowards(ply:GetPos()) + + + end) + net.Start("art_opennpcdialog") + net.WriteEntity(self) + net.WriteTable(SendableDialog(self.DialogCursors[ply])) + net.Send(ply) + end +end + +net.Receive("art_updatenpcdialog",function(len,ply) + local npc = net.ReadEntity() + local option = net.ReadString() + npc.DialogCursors[ply] = npc.DialogCursors[ply]["Options"][option](ply) + net.Start("art_opennpcdialog") + net.WriteEntity(npc) + net.WriteTable(SendableDialog(npc.DialogCursors[ply])) + net.Send(ply) +end) + +scripted_ents.Register(ENT, "art_npc") diff --git a/gamemode/inventorysystem/prayers/cl_prayers.lua b/gamemode/inventorysystem/abilities/cl_abilities.lua index e28db63..e28db63 100644 --- a/gamemode/inventorysystem/prayers/cl_prayers.lua +++ b/gamemode/inventorysystem/abilities/cl_abilities.lua diff --git a/gamemode/inventorysystem/prayers/sh_prayers.lua b/gamemode/inventorysystem/abilities/sh_abilities.lua index 9d8ff3b..fc6cd82 100644 --- a/gamemode/inventorysystem/prayers/sh_prayers.lua +++ b/gamemode/inventorysystem/abilities/sh_abilities.lua @@ -11,7 +11,7 @@ if CLIENT then inv = nrequire("cl_prayers.lua") end -inv.Name = "Prayers" +inv.Name = "Abilities" inv.track = {} function inv:FindPlaceFor(item) if item.Pray ~= nil then diff --git a/gamemode/inventorysystem/cl_common.lua b/gamemode/inventorysystem/cl_common.lua index bf9fb6f..a83deb1 100644 --- a/gamemode/inventorysystem/cl_common.lua +++ b/gamemode/inventorysystem/cl_common.lua @@ -63,6 +63,7 @@ function com.generatereceiver() if posequal then return end local item = frominv:Get(frompos) + if not item then return end --Fake remove the item, in case the position we want to move it to overlaps with where it is now. frominv:Remove(frompos) local cf = toinv:CanFitIn(topos,item) diff --git a/gamemode/inventorysystem/skills/cl_skills.lua b/gamemode/inventorysystem/skills/cl_skills.lua index b5e4620..208cc73 100644 --- a/gamemode/inventorysystem/skills/cl_skills.lua +++ b/gamemode/inventorysystem/skills/cl_skills.lua @@ -24,6 +24,7 @@ inv.DrawOnDPanel = function(self,panel) local label = vgui.Create("DLabel",ipanel) label:Dock(TOP) label:SetDark(true) + label:SetWrap(true) local bar = vgui.Create("DProgress",ipanel) bar:Dock(TOP) elements[j] = { diff --git a/gamemode/npcsystem/sh_basenpc.lua b/gamemode/npcsystem/sh_basenpc.lua new file mode 100644 index 0000000..b3e7e49 --- /dev/null +++ b/gamemode/npcsystem/sh_basenpc.lua @@ -0,0 +1,34 @@ +--[[ + Defines some ai primitives for npc's +]] +local log = nrequire("log.lua") +local reg = nrequire("sh_npcsystem.lua") + +local npc = {} + +npc.Name = "NPC Base" + +function npc:Spawn() + local e = ents.Create("art_npc") + + if self.Model then self:SetModel(self.Model) + else log.error("NPC created without model, this might be a bug!") end + + if self.Pos then self:SetPos(self.Pos) + else log.error("NPC created without a position, this might be a bug!") end + + self.talking = false + + if self.Name then self:SetName(self.Name) + else log.error("NPC created without a name! They won't be able to open doors!") end + + if self.Ang then self:SetAngles(self.Ang) end + if self.OnSpawn then self.OnSpawn(self) end + + self.Entity = e + e:Spawn() +end + +reg.RegisterNPC(npc) + +return npc diff --git a/gamemode/npcsystem/sh_humannpc.lua b/gamemode/npcsystem/sh_humannpc.lua new file mode 100644 index 0000000..b4a2b15 --- /dev/null +++ b/gamemode/npcsystem/sh_humannpc.lua @@ -0,0 +1,67 @@ +local reg = nrequire("sh_npcsystem.lua") +local log = nrequire("log.lua") + + +local base1 = nrequire("sh_talkablenpc.lua") +local base2 = nrequire("sh_movingnpc.lua") + +local human_models = {} +for i = 1,7 do + human_models[#human_models + 1] = string.format("models/Humans/Group01/Female_0%d.mdl",i) +end +for i = 1,9 do + human_models[#human_models + 1] = string.format("models/Humans/Group01/Male_0%d.mdl",i) +end + +local npc = {} +setmetatable(npc,{__index = function(self,key) + if key == "Model" then + return human_models[math.random(#human_models)] + else + return base1.key or base2.key + end +end}) + +npc.Name = "Human NPC Base" + +npc.canlearn = true + +--things that npcs can learn +local learnable = { + action = { + "name", -- Name of the action + "preconditions", --Things that must be true before we can do an action + "postconditions", --Things that must be true after we do an ation + }, + event = { + "name", -- The name of the event + "time", -- When the event happened + "who", --Who was involved in the event ? + "where", --Where did this event take place ? + }, + entity = { --NOT the same as source engine entities + "name", --The name of this person + "relations", --Things about this person + }, + thing = { + "name", -- The name of the thing + "location", -- Where is this thing? + "size", --How big is this thing? + }, +} +for k,v in pairs(learnable) do + npc["known_" .. k .. "s"] = {} + local capt = k:gsub("^%l", string.upper) + npc["Teach" .. capt] = function(self,tbl) + if self.canlearn == false then return end + for i,j in pairs(v) do + if tbl[j] == nil then + log.error(string.format("Tried to teach %s about %s %q without field %q",self.Name, k, tbl.Name, j)) + end + end + local kt = self["known_" .. k .. "s"] + kt[#kt + 1] = tbl + end +end + +reg.RegisterNPC(npc, "Human NPC Base") diff --git a/gamemode/npcsystem/sh_movingnpc.lua b/gamemode/npcsystem/sh_movingnpc.lua new file mode 100644 index 0000000..21f302e --- /dev/null +++ b/gamemode/npcsystem/sh_movingnpc.lua @@ -0,0 +1,22 @@ +local reg = nrequire("sh_npcsystem.lua") + +local base = nrequire("sh_basenpc.lua") +local nextbot = scripted_ents.Get("base_nextbot") +local npc = {} + +npc.Name = "Walkable NPC Base" + +setmetatable(npc,{__index = function(self,key) + return self[key] or base[key] or nextbot[key] +end}) + +function npc:Initalize() + if base.Initalize then base.Initalize(self) end + if nextbot.Initalize then nextbot.Initalize(self) end + print("After initalizeing walkable, self.loco is", self.loco) +end + +function npc:Face(ang_or_vec) + print("trying to face:",ang_or_vec,type(ang_or_vec)) +end +reg.RegisterNPC(npc) diff --git a/gamemode/npcsystem/sh_shop.lua b/gamemode/npcsystem/sh_shop.lua new file mode 100644 index 0000000..c2b291d --- /dev/null +++ b/gamemode/npcsystem/sh_shop.lua @@ -0,0 +1,16 @@ +local reg = nrequire("sh_npcsystem.lua") + +local base = nrequire("sh_talkablenpc.lua") +local npc = {} + +local npc_m = {__index = function(self,key) + return base[key] +end} + +setmetatable(npc,npc_m) + +npc.Name = "Shopkeep" + +reg.RegisterNPC(npc) + +return npc diff --git a/gamemode/npcsystem/sh_talkablenpc.lua b/gamemode/npcsystem/sh_talkablenpc.lua new file mode 100644 index 0000000..9e1cfb9 --- /dev/null +++ b/gamemode/npcsystem/sh_talkablenpc.lua @@ -0,0 +1,14 @@ +--[[ + Some basics for talking to npcs +]] +local reg = nrequire("sh_npcsystem.lua") + +local base = nrequire("sh_basenpc.lua") +local npc = {} +setmetatable(npc,{__index = base}) + +npc.Name = "Talkable NPC Base" + +reg.RegisterNPC(npc) + +return npc diff --git a/gamemode/npcsystem/sh_townie.lua b/gamemode/npcsystem/sh_townie.lua new file mode 100644 index 0000000..3b693c5 --- /dev/null +++ b/gamemode/npcsystem/sh_townie.lua @@ -0,0 +1,17 @@ +local reg = nrequire("sh_npcsystem.lua") + +local base1 = nrequire("sh_talkablenpc.lua") +local base2 = nrequire("sh_moveingnpc.lua") +local npc = {} + +local npc_m = {__index = function(self,key) + return base1[key] or base2[key] +end} + +setmetatable(npc,npc_m) + +npc.Name = "Townie" + +reg.RegisterNPC(npc) + +return npc diff --git a/gamemode/npcsystem/sv_blockingdummy.lua b/gamemode/npcsystem/sv_blockingdummy.lua index c40fc54..d29d33c 100644 --- a/gamemode/npcsystem/sv_blockingdummy.lua +++ b/gamemode/npcsystem/sv_blockingdummy.lua @@ -1,5 +1,5 @@ -local n = nrequire("sv_npcsystem.lua") +local n = nrequire("sh_npcsystem.lua") local NPC = {} NPC.Name = "Blocking Training Dummy" NPC.Desc = "A man made of straw. His dream is to have a brain." diff --git a/gamemode/npcsystem/sv_dummy.lua b/gamemode/npcsystem/sv_dummy.lua index 0bfa063..f527c03 100644 --- a/gamemode/npcsystem/sv_dummy.lua +++ b/gamemode/npcsystem/sv_dummy.lua @@ -1,4 +1,4 @@ -local n = nrequire("sv_npcsystem.lua") +local n = nrequire("sh_npcsystem.lua") local NPC = {} NPC.Name = "Training Dummy" diff --git a/gamemode/npcsystem/sv_rat.lua b/gamemode/npcsystem/sv_rat.lua index fadbc8d..bf2cc65 100644 --- a/gamemode/npcsystem/sv_rat.lua +++ b/gamemode/npcsystem/sv_rat.lua @@ -1,4 +1,4 @@ -local n = nrequire("sv_npcsystem.lua") +local n = nrequire("sh_npcsystem.lua") local NPC = {} NPC.Name = "Rat" NPC.Desc = "A nasty little guy" diff --git a/gamemode/npcsystem/sv_zombie.lua b/gamemode/npcsystem/sv_zombie.lua index a612e92..9f0f747 100644 --- a/gamemode/npcsystem/sv_zombie.lua +++ b/gamemode/npcsystem/sv_zombie.lua @@ -1,4 +1,4 @@ -local n = nrequire("sv_npcsystem.lua") +local n = nrequire("sh_npcsystem.lua") --local ncom = nrequire("sv_common.lua") local NPC = {} NPC.Name = "Zombie" @@ -154,7 +154,7 @@ end -- -- endpos =( self:GetForward() * 50) + self:GetPos() + Vector(0,0,50), -- -- filter = self -- -- }) --- +-- -- end --These are just here to tell the editors/develoeprs what functions are available.. dont un-comment them out, as this could affect all the items. diff --git a/gamemode/nrequire.lua b/gamemode/nrequire.lua index 1b6be2f..4313ce0 100644 --- a/gamemode/nrequire.lua +++ b/gamemode/nrequire.lua @@ -6,6 +6,7 @@ ]] if nrequire ~= nil then return end +--The files we want clients to load local clienttoload = {} local searchpaths = { @@ -131,6 +132,7 @@ local ntbl = {} local reqtbl = {} --Holds already nrequire()'d things local lastcall = {} --Holds when things were loaded +local location = {} --Holds the location of files ("DATA","GAME","LUA",...) local deptbl = {} --Holds the dependencies between files local pathstack = {} function nrequire(req,...) @@ -153,6 +155,7 @@ function nrequire(req,...) local trace = debug.getinfo(2,"flnSu") local source = trace.source + print("Adding to deptbl, src:",source,"tpath:",tpath) deptbl[source] = tpath --If we've already run it (and its up to date), just return it @@ -187,7 +190,8 @@ function nrequire(req,...) local m = filefunc(varargs) hook.Run("artery_file_included",tpath,m) reqtbl[tpath[1]] = m - lastcall[tpath[1]] = CurTime() + lastcall[tpath[1]] = file.Time(tpath[1],tpath[2]) + location[tpath[1]] = tpath[2] end,function(err) MsgC(Color(209,96,196),debug.traceback(),"\n") MsgC(Color(209,96,196),"nrequire Error:",err,"\n") @@ -201,6 +205,25 @@ function nrequire(req,...) end +local update_file_co = coroutine.create(function() + while true do + for k,v in pairs(reqtbl) do + local loc = location[k] + if file.Time(k,loc) > lastcall[k] then + print(string.format("Found updated file:%s calling nrequire",k)) + nrequire(k) + end + coroutine.yield() + end + end +end) + +hook.Add("Tick","nrequire_update_tick",function() + if coroutine.status(update_file_co) == "suspended" then + coroutine.resume(update_file_co) + end +end) + if SERVER then net.Receive("artery_requestcsfile",function(ln,ply) local which = net.ReadString() diff --git a/gamemode/questsystem/component_gather.lua b/gamemode/questsystem/component_gather.lua index 5647f42..cc7f44f 100644 --- a/gamemode/questsystem/component_gather.lua +++ b/gamemode/questsystem/component_gather.lua @@ -8,6 +8,12 @@ local comp = {} comp.Name = "Quest Component Gather" +--[[ +Update this quest, this is called every time a player +picks up an item. This method removes the items from the player, then +adds them back in (so dropping an item and picking it up x number of times +will not work. +]] function comp:Update() if SERVER then local items = {} @@ -49,6 +55,10 @@ function comp:Init(ply,itemname,itemnumber) log.debug("After initalizing quest, found " .. tostring(self.items) .. " items") end +--[[ +Detour the player's GiveItem(), to check if the quest is +complete after giving the player the item +]] if SERVER then local plymeta = FindMetaTable("Player") local det = plymeta.GiveItem @@ -56,7 +66,7 @@ if SERVER then det(self,tbl) log.debug("Calling component_gather's GiveItem()") for k,v in pairs(quests) do - if v.ItemName == tbl.Name then + if v.Name == comp.Name and v.ItemName == tbl.Name then v:Update() end end diff --git a/gamemode/questsystem/component_kill.lua b/gamemode/questsystem/component_kill.lua index 3925a12..b1ffa71 100644 --- a/gamemode/questsystem/component_kill.lua +++ b/gamemode/questsystem/component_kill.lua @@ -1,3 +1,70 @@ --[[ Something to stop gmod from freaking out ]] +if SERVER then + inv = nrequire("sv_invtracker.lua") +end +local log = nrequire("log.lua") + +local quests = {} +local comp = {} + +comp.Name = "Quest Component Kill" +comp.kills = 0 +comp.npcname = "Init not yet called" + +function comp:Update() + self.Quest:UpdateCompleted() +end + +function comp:Complete() + if self.kills >= self.numkills then + log.debug("Completed a gather arc of a quest!") + end + return self.items >= self.ItemNumber +end + +function comp:Init(ply,npcname,numkills) + if not ply or not itemname or not itemnumber then log.error("Tried to create a kill arch for a quest without correct arguments") end + self.npcname = itemname + self.kills = 0 + self.numkills = 0 + if CLIENT then return end + self.Owner = ply + -- self:Update() + quests[#quests + 1] = self +end + +--[[ +Detour the player's GiveItem(), to check if the quest is +complete after giving the player the item +]] +if SERVER then + local plymeta = FindMetaTable("Player") + local det = plymeta.GiveItem + function plymeta:GiveItem(tbl) + det(self,tbl) + log.debug("Calling component_gather's GiveItem()") + for k,v in pairs(quests) do + if v.Name == comp.Name and v.ItemName == tbl.Name then + v:Update() + end + end + end +end + +function comp:GetText() + return string.format("Gather %s %s",self.ItemNumber,self.ItemName) +end + +function comp:Serialize() + return util.TableToJSON({self.ItemName,self.ItemNumber}) +end + +function comp:DeSerialize(data) + local tbl = util.JSONToTable(data) + self.ItemName = tbl[1] + self.ItemNumber = tbl[2] +end + +nrequire("core/quests/arcs.lua").RegisterArc(comp) |
