Jump to content

How can I code a recipe to require a nearby Stove or Campfire?


Madman_Andre

Recommended Posts

After doing some tests, can confirm it is possible to detect this using lua code.

 

 

You have to search inside the IsoCell or IsoGridSquare that the player is in to find the stove or campfire you need.

And then you compare their positions and distances from each other use to determine whether you are near the stove/campfire or not.

 

 

To save you some time and trouble, I wrote you a function "isCloseToCookingUtil(maxDistance)" that returns a boolean "true" if you are near and can see a cooking utility that is turned on, lit, or have a fire.

 

I recommend the "maxDistance" parameter be set to 1.2, but you can use any value you prefer as the distance.

 

 

 

Feel free to modify, improve, analyze, or use this code.

--[[
    This function returns a boolean if the client (player) is near a valid cooking utility and the valid criteria is met.
    
    Returns true if ALL following criteria below are met:
        - The client (player) is close enough to one of the given cooking utilities.
        - And, the client (player) is within line of sight of a cooking util.
        - And, the cooking util must be turned on, lit, or be on fire.
        
    Returns false if ONE following criteria below is met:
        - The client (player) is too far from the given cooking utils
        - Or, The client (player) is not within light of sight.
        - Or, The cooking util is turned off, not lit, or is not on fire.
    
    Parameters:
        maxDistance - The max distance a player can be from a given cooking utility.
]]
local function isCloseToCookingUtil(maxDistance)

    --local objects = getCell():getObjectList();
    --local objects = getCell():getStaticUpdaterObjectList();
    --local objects = getCell():getPushableObjectList();
    
    
    --print("===================================")
    
    
    --===================--
    -- Cooking Utilities --
    --===================--
    local cookingUtils = {
        ["Stove"] = true, 
        ["Barbecue"] = true, 
        ["Fireplace"] = true, 
        ["StoneFurnace"] = true, 
        ["Fire"] = true, -- "Fire" includes campfires, etc.
    }
    
    
    -- Find All Process and Static IsoObjects in the client's (player's) cell.
    --local playerObj = getSpecificPlayer(0);
    local playerObj = getPlayer();
    local objects = playerObj:getCell():getProcessIsoObjects(); -- This contains most cooking appliances.
    objects:addAll(playerObj:getCell():getStaticUpdaterObjectList()); -- This contains other stuff such as lights, campfires, etc.
    
    
    -- Look at each IsoObject and check if it's a cooking utility and if the player is close enough.
    for i=0, objects:size()-1 do
        
        local o = objects:get(i);
        --print(string.format("=== %s, %s", tostring(o:getName()), tostring(o:getObjectName()) ));
        
        -- Check if object is a cooking utility.
        if cookingUtils[o:getObjectName()] == true then
            
            -- The object "o" is a cooking utility.
            -- Check if the player is close enough to a cooking util.
            
            -- get object position.
            local objX = o:getX() + 0.5; -- center with 0.5 offset
            local objY = o:getY() + 0.5; -- center with 0.5 offset
            local objZ = o:getZ();
            
            -- get player position.
            local pX = playerObj:getX();
            local pY = playerObj:getY();
            local pZ = playerObj:getZ();
            
            -- Is the player close enough to the cooking util?
            local distance = math.sqrt((objX-pX)^2 + (objY-pY)^2 + (objZ-pZ)^2)
            --print(distance)
            
            if distance <= maxDistance then
                
                -- Can the player see the cooking util?
                local gridSquare = o:getSquare();
                local lineOfSightTestResults = LosUtil.lineClear(playerObj:getCell(), objX, objY, objZ, pX, pY, pZ, false);
                --print(string.format("%s", tostring(lineOfSightTestResults)));
                
                if tostring(lineOfSightTestResults) ~= "Blocked" then
                    
                    --print(string.format("%s, %s", tostring(o:getName()), tostring(o:getObjectName()) ));
                    
                    -- Is the fire still alive? Includes campfires, etc. (IsoFire)
                    if (o.getLife ~= nil and o:getLife() > 0) or (o.getLightRadius ~= nil and o:getLightRadius() > 1) then
                        --o:update();
                        --print(o:getLightRadius());
                        return true; -- The player is close enough to a working cooking util and can see it; return true.
                    end
                    
                    -- Is the fire lit? (IsoFireplace, IsoBarbecue)
                    if o.isLit ~= nil and o:isLit() == true then
                        return true; -- The player is close enough to a working cooking util and can see it; return true.
                    end
                    
                    -- Is the fire started? (BSFurnace --> ObjectName: "StoneFurnace")
                    if o.isFireStarted ~= nil and o:isFireStarted() == true then
                        return true; -- The player is close enough to a working cooking util and can see it; return true.
                    end
                    
                    -- Is the cooking util turned on? (IsoStove)
                    if o.Activated ~= nil and o:Activated() == true then
                        return true; -- The player is close enough to a working cooking util and can see it; return true.
                    end
                    
                end
            end
        end
        
    end
    
    return false; -- The player is too far away from all cooking utils, cannot see it, or they are not turned on or lit; return false.
end



local function onMove(player)
    local isCloseEnough = isCloseToCookingUtil(1.2)
    --print(isCloseEnough)
end

--Events.OnPlayerMove.Add(onMove)

 

 

 

CookingUtil.lua

Edited by ATPHHe
Link to comment
Share on other sites

Holy shit, you the real OG.

 

It's surprising that stoves/campfires/etc are all unique to to such a degree, It's also a little surprising something like this doesn't really exist in the game. Now I need to figure out how to use this. Is " isCloseToCookingUtil" the part you add into the custom recipe entry, or did I misread something?

 

Also, again, thank you. You're doing great things for the community. :D

Link to comment
Share on other sites

A bit late, but I have a question regarding the implementation of the lua code. I should have asked a couple of other questions, but does CookingUtil.lua go in the client or server folder inside the mod? Or does it go somewhere else?

 

Also, is "NearItem.isCloseToCookingUtil" the correct way to implement it in the recipe, or did I completely bodge it up?

Edited by Madman_Andre
grammar
Link to comment
Share on other sites

No problem.

 

CookingUtil.lua should go into the client folder.

"NearItem.isCloseToCookingUtil" is fine, as long as "NearItem" is some table, object, or something that can store functions.

 

May I see how you implemented your recipes, items, and code? I can give a better summary if I know how the files and code are written.

Edited by ATPHHe
Link to comment
Share on other sites

5 hours ago, ATPHHe said:

No problem.

 

CookingUtil.lua should go into the client folder.

"NearItem.isCloseToCookingUtil" is fine, as long as "NearItem" is some table, object, or something that can store functions.

 

May I see how you implemented your recipes, items, and code? I can give a better summary if I know how the files and code are written.

 

Ah, okay. I had the lua file in the right place. Initially I thought it went in server at first but then I realized it belonged in client. Admittedly, I'm still really new to coding in lua (or any programming language for that matter) so I kinda apologize for coming off sounding newb-ish at this.

As for the recipes file. Well, here is a good example of one of the recipes I have created. There are a few others, but they're all functionally versions of this first one:

	recipe Fry Chicken
		{
			keep Pan,
			Chicken,
			AAABreadingBowl;4,
			Egg,
			Water;2,
			AAACookingOil;2,

			Result:ChickenFried,
			Time:60.0,
			Category:Cooking,
			OnGiveXP:Give3CookingXP,
		}

Basically, its a recipe that lets you pan fry chicken with a few necessary ingredients. (As a note to avoid confusion in the above recipe, "AAABreadingBowl" and "AAACookingOil are custom items.) As the recipe is currently written, one can functionally fry said chicken over a magical fire of nothing basically. Also, as for the NearItem variable I mentioned above, I read about it while trying to figure out how to get the recipe to work near a heat source. "NearItem:Campfire," works perfectly as intended, but it makes the recipe only craftable near, well, a campfire. In my experimentation, the campfire doesn't even need to be lit either, it just has to exist.

Again, thanks for the help.

Link to comment
Share on other sites

Nicely done, then all looks good. I assume you have everything working with the "NearItem" variable and that all it's functions work as intended.  :)

 

And no problem, always glad to help. Any other questions feel free to ask.

Link to comment
Share on other sites

Well, as I said, that was an example. I'm not sure how to implement the lua file inside the recipe. I was hoping you could give me advice in that regard.

I tried the following:

	recipe Fry Chicken
		{
			keep Pan,
			Chicken,
			AAABreadingBowl;4,
			Egg,
			Water;2,
			AAACookingOil;2,

			NearItem:cookingUtils,

			Result:ChickenFried,
			Time:60.0,
			Category:Cooking,
			OnGiveXP:Give3CookingXP,
		}

Adding that line into the recipe. However it didn't work. I also tried NearItem:Stove among others, with no such luck.

Link to comment
Share on other sites

I found these variable names.

Seems like only these can be used currently in the recipes.txt file to call lua functions.

  • OnTest
  • OnCreate
  • OnGiveXP
You can reference these in the future if you need examples on what they do with these functions.
  • ..\steamapps\common\ProjectZomboid\media\lua\server\recipecode.lua
  • ..\steamapps\common\ProjectZomboid\media\scripts\recipes.txt
 
 
 
You will need "OnTest".
To use "OnTest", you have to write a custom function with the correct parameters.
"OnTest" will basically test an each item need for the recipe.
When "OnTest" returns true for that item, that item can be used for crafting.
 
 
 
Here's the bare minimum.
The finished code will be in "recipecode_CookingUtils.lua".
-- (OnTest)
function CookingUtils_OnTest(sourceItem, result)
    return true;
end

-- (OnCreate)
function CookingUtils_OnCreate(items, result, player, selectedItem)
    return;
end

-- (OnGiveXP) Gives by default, 3 XP to cooking.
function CookingUtils_GiveSomeCookingXP(recipe, ingredients, result, player)
    player:getXp():AddXP(Perks.Cooking, 3);
end

 

Here's how the functions should be written in the recipes.txt file.

  • OnTest:CookingUtils_OnTest,
  • OnCreate:CookingUtils_OnCreate,
  • OnGiveXP:CookingUtils_GiveSomeCookingXP,
module SomeCustomRecipes
{
    /*** Import Project Zomboid's Base recipes ***/
	imports
    {
        Base
    }
	
	/************** Cooking Recipes **************/
	
	recipe Fry Chicken Edit
    {
        keep Pan,
        Chicken,
        Egg,
        Water;2,

        OnTest:CookingUtils_OnTest,
        OnCreate:CookingUtils_OnCreate,
        
        Result:ChickenFried,
        Time:60.0,
        Category:Cooking,
        SkillRequired:Cooking=0,
        
        OnGiveXP:CookingUtils_GiveSomeCookingXP,
    }
	
}

 

 

I got it to work like this now, once you have all of the ingredients inside your inventory.
Stove Turned On:
image.thumb.png.e18f11df4a4de42fa3c2e7ba095ca485.png
 
Stove Turned Off:
image.thumb.png.1f4f1f0d703015588e972bd05fbfb240.png
 
 
The only problem that came up was speed.
 

I had to optimize/speed up the code. The code got super laggy and started slowing down the game by a ton using "OnTest".

Apparently "OnTest" is seems to be called for every single item on the recipe.
All of the items in the recipe calling "CookingUtils.isCloseToCookingUtil(playerObj, maxDistance)" caused lag problems.
 
To fix this, I added a "CookingUtils_Ticks" variable to call the function every 30 ticks and I added some other variables. This helped reduced the lag by a ton.
 
 
Here's the new files below I made for you. All code was modified.
  • ..\media\lua\server\CookingUtils.lua
  • ..\media\lua\server\recipecode_CookingUtils.lua
  • ..\media\scripts\recipes.txt

 

 

CookingUtilsMod.zip

Edited by ATPHHe
Link to comment
Share on other sites

It's amazing work. I for one believe you should consider releasing it on the Steam Workshop as a modding resource. It adds a bit of functionality that plain doesn't exist in the game. A fair few modders out there would use it if they knew about this.

 

Also, do you have a username/id on Steam? I'd like to add you as a contributor to the mod you've helped me with. It's the least I can do.

Edited by Madman_Andre
addition
Link to comment
Share on other sites

Ah, I just realized that I forgot to convert "lineOfSightTestResults" to a string. It is on Line 91 in "CookingUtils.lua".

If it's not converted to a string, then suddenly you can cook through walls.

if lineOfSightTestResults ~= "Blocked" then
if tostring(lineOfSightTestResults) ~= "Blocked" then

 

Here's a fixed "CookingUtils.lua" file. 

The Line Of Sight should work again and you shouldn't be able to cook though walls with this minor fix.

 

I'll edit the zip file in all my posts to include this fix also.

 

CookingUtilsMod.zip CookingUtils.lua

Edited by ATPHHe
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...