troltos Posted July 27, 2016 Share Posted July 27, 2016 I have working code allowing me to place any item with durability into a science machine and get SOMETHING back, like a gold nugget. now that that seems to be working fine, my next and second to last test is to replicate the functions of green staff apon inserting an item into the science machine. however when i instruct the game to preform the functions of the green staff code after putting the item in the machine, the game crashes saying lua:23 (the line that says "local recipe = GetRecipe(target.prefab)") attempt to call global 'GetRecipe' (a nil value) my hunch is that this "target" function is set up in a different file and that the reason it is crashing is because the item put into the science machine does not count as the target, so the game is wondering where the target is, and crashes. however i do not know how to set the item put into the machine to be the target. mostly was wondering how or where the "target" thing (i don't really know what to call it) in the file for staffs, specifically the green staff, works and where its function is defined. the green staff code that seems to work with "target" code i am talking about is this ----- local function candestroy(staff, caster, target) if not target then return false end local recipe = GetRecipe(target.prefab) return recipe ~= nil end ----- local function destroystructure(staff, target) local ingredient_percent = 1 if target.components.finiteuses then ingredient_percent = target.components.finiteuses:GetPercent() elseif target.components.fueled and target.components.inventoryitem then ingredient_percent = target.components.fueled:GetPercent() elseif target.components.armor and target.components.inventoryitem then ingredient_percent = target.components.armor:GetPercent() end local recipe = GetRecipe(target.prefab) local caster = staff.components.inventoryitem.owner local loot = {} if recipe then for k,v in ipairs(recipe.ingredients) do if not string.find(v.type, "gem") then local amt = math.ceil(v.amount * ingredient_percent) for n = 1, amt do table.insert(loot, v.type) end end end end if #loot <= 0 then return end for k,v in pairs(loot) do SpawnLootPrefab(target, v) end target:Remove() end ----- The code for my mod is as follows local function candestroy(target) if not target then return false end local recipe = GetRecipe(target.prefab) return recipe ~= nil end local function destroystructure(target) local ingredient_percent = 1 if target.components.finiteuses then ingredient_percent = target.components.finiteuses:GetPercent() elseif target.components.fueled and target.components.inventoryitem then ingredient_percent = target.components.fueled:GetPercent() elseif target.components.armor and target.components.inventoryitem then ingredient_percent = target.components.armor:GetPercent() end local recipe = GetRecipe(target.prefab) local loot = {} if recipe then for k,v in ipairs(recipe.ingredients) do if not string.find(v.type, "gem") then local amt = math.ceil(v.amount * ingredient_percent) for n = 1, amt do table.insert(loot, v.type) end end end end if #loot <= 0 then return end local sounds = {} sounds = getsoundsforstructure(staff, target) for k,v in pairs(sounds) do print("playing ",v) staff.SoundEmitter:PlaySound(v) end for k,v in pairs(loot) do SpawnLootPrefab(target, v) end target:Remove() end -- accept local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() inst:DoTaskInTime(1.5, destroystructure) end local function AcceptTest(inst, item, giver) return item.components.finiteuses or item.components.armor or item.components.fueled end -- recycler: local function recycleengine(inst) if not inst.components.lootdropper then inst:AddComponent("lootdropper") end inst:AddComponent("trader") inst.components.trader:SetAcceptTest(AcceptTest) inst.components.trader.onaccept = OnGetItemFromPlayer end AddPrefabPostInit("researchlab", recycleengine) -- trading local function MakeTradable(inst) if not inst.components.tradable then inst:AddComponent("tradable") end end AddComponentPostInit("finiteuses", function(self) local inst = self.inst MakeTradable(inst) end) AddComponentPostInit("armor", function(self) local inst = self.inst MakeTradable(inst) end) AddComponentPostInit("fueled", function(self) local inst = self.inst MakeTradable(inst) end) i would appreciate any help, thank you. Link to comment Share on other sites More sharing options...
Mobbstar Posted July 28, 2016 Share Posted July 28, 2016 The issue is that "GetRecipe" is a global function and thus needs to be called as "GLOBAL.GetRecipe" in modmain, but only modmain. Link to comment Share on other sites More sharing options...
troltos Posted July 28, 2016 Author Share Posted July 28, 2016 thank you, that solves one issue. however, now i am getting an error on lua:43 which is SpawnLootPrefab(target, v) the error being "attempt to call global 'SpawnLootPrefab' (a nil value)" as i said before, my guess is it is not registering the item put into the science machine as the target, and this it doesnt preform the recipie and percent "getting" on the item, so it doesn't know what to spawn. i don't know how to set the input item as the target Link to comment Share on other sites More sharing options...
Mobbstar Posted July 28, 2016 Share Posted July 28, 2016 12 hours ago, troltos said: "attempt to call global 'SpawnLootPrefab' (a nil value)" GLOBAL.SpawnLootPrefab is correct. Again, you have to refer to the global environment when in modmain. Link to comment Share on other sites More sharing options...
troltos Posted July 28, 2016 Author Share Posted July 28, 2016 I did that, but on the same line of code it says Variable 'SpawnLootPrefab' is not declared once again i am left thinking that it doesn't know what item to make "target" and generate the recipe ingredients of. Link to comment Share on other sites More sharing options...
Mobbstar Posted July 29, 2016 Share Posted July 29, 2016 My fault, it's not global, it's a local function in the staff.lua file: Spoiler local function SpawnLootPrefab(inst, lootprefab) if lootprefab then local loot = SpawnPrefab(lootprefab) if loot then local pt = Point(inst.Transform:GetWorldPosition()) loot.Transform:SetPosition(pt.x,pt.y,pt.z) if loot.Physics then local angle = math.random()*2*PI loot.Physics:SetVel(2*math.cos(angle), 10, 2*math.sin(angle)) if loot.Physics and inst.Physics then pt = pt + Vector3(math.cos(angle), 0, math.sin(angle))*(loot.Physics:GetRadius() + inst.Physics:GetRadius()) loot.Transform:SetPosition(pt.x,pt.y,pt.z) end loot:DoTaskInTime(1, function() if not (loot.components.inventoryitem and loot.components.inventoryitem:IsHeld()) then if not loot:IsOnValidGround() then local fx = SpawnPrefab("splash_ocean") local pos = loot:GetPosition() fx.Transform:SetPosition(pos.x, pos.y, pos.z) --PlayFX(loot:GetPosition(), "splash", "splash_ocean", "idle") if loot:HasTag("irreplaceable") then loot.Transform:SetPosition(GetPlayer().Transform:GetWorldPosition()) else loot:Remove() end end end end) end return loot end end end You have to copy it into modmain too to properly drop the items. Link to comment Share on other sites More sharing options...
troltos Posted July 30, 2016 Author Share Posted July 30, 2016 Thanks, i added that and also gave PI and Vector3 a global prefix to stop crashinh, but trying to see if my mod worked an interesting side effect happned the upon inserting my axe into the science machine, the machine itself blew apart! i guess that makes sense if you throw tools into moving components, but that's not exactly what i was going for. at this point i am almost certain the issue is that the science machine is being set as "target", when i want the item put into it to be the "target" Link to comment Share on other sites More sharing options...
Mobbstar Posted July 30, 2016 Share Posted July 30, 2016 Just now, troltos said: at this point i am almost certain the issue is that the science machine is being set as "target", when i want the item put into it to be the "target" Yes, you are right. You can do either of the following: Spoiler Use a wraper function of sorts inst:DoTaskInTime(1.5,function() destroystructure(target) end) Refer to the target to begin with target:DoTaskInTime(1.5, destroystructure) Give a second parameter to the function inst:DoTaskInTime(1.5, destroystructure, target) --for this, you will need to add "inst" as first parameter of the destroy function Link to comment Share on other sites More sharing options...
troltos Posted July 30, 2016 Author Share Posted July 30, 2016 they all crash in differnent ways, im assuming all im supposed to do is change what i previously had local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() inst:DoTaskInTime(1.5, destroystructure)end to either local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() inst:DoTaskInTime(1.5,function() destroystructure(target) end)end or local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() target:DoTaskInTime(1.5, destroystructure)end The first method gives me an error lua:57 which is the start of if target.components.finiteuses then ingredient_percent = target.components.finiteuses:GetPercent() elseif target.components.fueled and target.components.inventoryitem then ingredient_percent = target.components.fueled:GetPercent() elseif target.components.armor and target.components.inventoryitem then ingredient_percent = target.components.armor:GetPercent() end the error being "attempt to index local 'target' (a nil value) and the second method gives me an error of lua:96 which the line of "target:DoTaskInTime(1.5, destroystructure) the error being "attempt to index local 'target' (a nil value) Link to comment Share on other sites More sharing options...
Mobbstar Posted July 30, 2016 Share Posted July 30, 2016 1 hour ago, troltos said: the error being "attempt to index local 'target' (a nil value) Woops, the "target" is called "item" in that function. Just use "item" instead of "target". (Every function names the stuff you give it, this one calls it "item" and the destroy function calls it "target". It is important to remember what is what.) Link to comment Share on other sites More sharing options...
troltos Posted July 30, 2016 Author Share Posted July 30, 2016 alright, i switched in local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() item:DoTaskInTime(1.5, destroystructure) end and then i am getting lua:26 at pt = pt + GLOBAL.Vector3(math.cos(angle), 0, math.sin(angle))*(loot.Physics:GetRadius() + inst.Physics:GetRadius()) the error being attempt to preform arithmetic on a nil value i tried switching pt = pt + GLOBAL.Vector3(math.cos(angle), 0, math.sin(angle))*(loot.Physics:GetRadius() + inst.Physics:GetRadius()) to pt = pt + GLOBAL.Vector3(math.cos(angle), 0, math.sin(angle))*(loot.Physics:GetRadius() + item.Physics:GetRadius()) and local function SpawnLootPrefab(inst, lootprefab) to local function SpawnLootPrefab(inst, item, lootprefab) and that fixed the crash, but it did nothing when it played the prototyping animation. Link to comment Share on other sites More sharing options...
troltos Posted August 6, 2016 Author Share Posted August 6, 2016 ive been trying everything for the last five days, to no avail, i would really like some help or i'm probably going to have to abandon this. Link to comment Share on other sites More sharing options...
DarkXero Posted August 6, 2016 Share Posted August 6, 2016 local function DropEverythingOnItem(item) if item.components.inventory then item.components.inventory:DropEverything() end if item.components.container then item.components.container:DropEverything() end end local function GenerateRecycledLoot(item) local ingredient_percent = 1 if item.components.finiteuses then ingredient_percent = item.components.finiteuses:GetPercent() elseif item.components.armor then ingredient_percent = item.components.armor:GetPercent() elseif item.components.fueled then ingredient_percent = item.components.fueled:GetPercent() end local recipe = GLOBAL.GetRecipe(item.prefab) local loot = {} if recipe then for k, v in ipairs(recipe.ingredients) do if not string.find(v.type, "gem") then local amt = math.ceil(v.amount * ingredient_percent) for n = 1, amt do table.insert(loot, v.type) end end end end return loot end local function SpawnRecycledLoot(inst, loot) for k, v in pairs(loot) do inst.components.lootdropper:SpawnLootPrefab(v) end end local function OnGetItemFromPlayer(inst, giver, item) inst.components.prototyper.onactivate() DropEverythingOnItem(item) local loot = GenerateRecycledLoot(item) inst:DoTaskInTime(1.5, SpawnRecycledLoot, loot) end local function AcceptTest(inst, item, giver) return item.components.finiteuses or item.components.armor or item.components.fueled end -- recycler: local function recycleengine(inst) if not inst.components.lootdropper then inst:AddComponent("lootdropper") end inst:AddComponent("trader") inst.components.trader:SetAcceptTest(AcceptTest) inst.components.trader.onaccept = OnGetItemFromPlayer end AddPrefabPostInit("researchlab", recycleengine) -- trading local function MakeTradable(inst) if not inst.components.tradable then inst:AddComponent("tradable") end end AddComponentPostInit("finiteuses", function(self) local inst = self.inst MakeTradable(inst) end) AddComponentPostInit("armor", function(self) local inst = self.inst MakeTradable(inst) end) AddComponentPostInit("fueled", function(self) local inst = self.inst MakeTradable(inst) end) Link to comment Share on other sites More sharing options...
troltos Posted August 8, 2016 Author Share Posted August 8, 2016 Thank you, that seems great for replicate the functions of the green staff! i figured once i got a replications of the function of the green staff it would be pretty simple to do a minor tweak, simply to get rid of the whole "always give at least one of the component" feature of the green staff looking through the code, i couldn't determine what instructed the game to always give back one instead of just following the % chance of the items durability, so i decided to test the numerical values. local ingredient_percent = 1 seems to do absolutely nothing regardless of what number i set it to, it didn't even have an effect if i removed the line entirely. with for n = 1, amt do setting the number to zero gives you at least 2 of every component, even if there was only one of that component in the recipie. setting the number to above one will take away that many - 1 from whatever you would have gotten. for example, setting it to 3 and then recycling a 100% marble suit will give you back 10 marble and 2 rope (meaning it took away 2 marble and 2 rope) Link to comment Share on other sites More sharing options...
Mobbstar Posted August 8, 2016 Share Posted August 8, 2016 2 hours ago, troltos said: i couldn't determine what instructed the game to always give back one local amt = math.ceil(v.amount * ingredient_percent) math.ceil() ALWAYS rounds up. To ALWAYS round down, use math.floor(). To round "properly", you can add 0.5 and subtract it later again. Link to comment Share on other sites More sharing options...
troltos Posted August 9, 2016 Author Share Posted August 9, 2016 hmm, is there a way, rather than just rounding, to have it be a % chance? like so putting a 95% axe in the science machine would have a 95% chance to drop a twig and a 95% chance to drop a flint. i had always assumed that was similar to how the green staff worked, but i realize now that it is actually just the amount required of an ingredient in a recipe multiplied by the % durability. Link to comment Share on other sites More sharing options...
DarkXero Posted August 9, 2016 Share Posted August 9, 2016 if recipe then for k, v in ipairs(recipe.ingredients) do if math.random() <= ingredient_percent then local amt = math.ceil(v.amount) for n = 1, amt do table.insert(loot, v.type) end end end end ingredient_percent goes from 0-1, math.random() vomits a number between 0-1 with uniform distribution. So if percent is 0.95, then you have a 95% chance to get the ingredient used, per ingredient. Link to comment Share on other sites More sharing options...
troltos Posted August 10, 2016 Author Share Posted August 10, 2016 that is definitely better than before, and works perfectly with items that only have a single number of each ingredient, but after some tests it seems to be "all or nothing" with ingredients, for example, putting a 50% weather pain into the machine, i would have a 50% chance to get a gear, a 50% chance to get a goat horn, and a 50% chance to get all 10 feathers back. but if i don't get all 10 of them back, i get none back at all. Link to comment Share on other sites More sharing options...
DarkXero Posted August 10, 2016 Share Posted August 10, 2016 Well, I assumed you wanted it per ingredient type, since the example only had 1 of each type. Code would look like: if recipe then for k, v in ipairs(recipe.ingredients) do local amt = math.ceil(v.amount) for n = 1, amt do if math.random() <= ingredient_percent then table.insert(loot, v.type) end end end end Link to comment Share on other sites More sharing options...
troltos Posted August 11, 2016 Author Share Posted August 11, 2016 Thanks, my mod is almost complete now Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.
Please be aware that the content of this thread may be outdated and no longer applicable.