#mod_development

1 messages · Page 263 of 1

red tiger
#

I can encrypt and serve payloads from local server machines to PZ clients in anonymous environments that can't be tampered with. =)

grizzled fulcrum
#

I wonder if another modder is using this to poison the lua environment somehow

#

because I remember some players having issues trying to join servers because of the mods that they'd loaded previously (then reset the lua env) and then loaded the server mods

#

which somehow caused the old loaded mods to load again alongside the server mods

#

now that I'm thinking about it, its nothing to do with loadstring but a weird quirk

red tiger
#

Oh what I'm talking about is insanely outside of the normal Lua coding / modding PZ has.

red tiger
#

You can use the LVM as an additional layer of obscurity from say Java-level tampering in a possibly compromised client.

grizzled fulcrum
#

LVM? What is that acronym

red tiger
#

If you stop code from executing on the client that needs to run in order to keep say a multiplayer client from running properly on a server then make it so that data sent back is unique, obfuscated, encrypted and that it needs to respond to the server. Otherwise, kick em.

#

Lua Virtual Machine.

#

Anyways I'm rambling about fun side-projects. xD

#

You can use anonymous functions to keep from tampering / poisoning the global table and for security purposes.

grizzled fulcrum
#

ohh

#

wait so LVM is the concept you created?

red tiger
grizzled fulcrum
#

because I thought lua was interpr

#

oh I'm dumb lol

#

Java implementation of lia stupid irosjrbsobd

red tiger
#

I'm simply applying the "code-cave" security mindset to this environment where Lua code is modularly compiled and stored in Kahlua's virtual machine inside Java's runtime.

grizzled fulcrum
#

Kahlua 2 mindfuck last update 1 decade ago stupid orange juice code

#

still better than anything i can do but it really gives you a run for your money mentally ill admit

red tiger
#

It's all experimental security stuff which has roughly anything to do with 99.999% modding in pz. xD

#

But if servers with home-brewed mods want to secure both their works and protect against cheaters, this stuff becomes relevant.

bronze yoke
#

the rule to go by is lua never ever implicitly copies anything except primitives (as they aren't objects to begin with)

grizzled fulcrum
#

isn't lua pass by ref but func args are by value?

#

I might have read that randomly somewhere or for a different language idk

bronze yoke
#

it's always by ref

grizzled fulcrum
#

that's nice to know

night iron
#

is there any way to:

  1. force the game to reload lua without changing the mod list?
  2. clear the console.txt without having to close the game first to unlock the file?
bronze yoke
#

you can reload lua from the main menu when in debug mode

night iron
#

how do i go into debug mode again?

bronze yoke
#

launch the game with the -debug argument

night iron
#

thanks

silent fulcrum
#

Do you think this is a good mod poster?

night iron
#

I see ternery assigment is not possible in LUA is there anything equivalent to this?
local offset = isDrainable ? 20 : 0

bronze yoke
night iron
#

thats actually very similar to `const someProp = condition && valueA || valueB

#

hummm out of curiosity.... does local someVariable = value or defaultValue work in lua?

bronze yoke
#

yeah

night iron
#

cool cool

bronze yoke
#

the exploitable thing here is that and returns false if the first argument doesn't evaluate to true, but if it does it just returns the second argument, not whether that evalutes to true

night iron
#

would 0 and '' default to the or value then? or only false does it?

bronze yoke
#

only false and nil evaluate to false in lua

night iron
#

ha! so no falsy checks got it

night iron
#

anyone mind explaining me what this .. operator actually does here? is it a string concatnator converting a into to string?
'' .. self.item:getDrainableUsesInt()

bronze yoke
#

it's just the operator for string concatenation yeah

#

is it just being used like that on its own here? O_O i guess it is meant to be converting

night iron
#

kk so my assumption seems to have been correct 🙂

bronze yoke
#

it usually implicitly converts, except when it doesn't

night iron
#

would there a more correct form of doing this in lua though?

bronze yoke
#

yeah, tostring(something)

night iron
#

ha! i'll use that instead then

bronze yoke
#

if you're referencing the vanilla lua keep in mind a lot of it is substandard and generally very weird

#

especially the older stuff gives the impression the devs may not have used lua before

night iron
#

nah this was lifted from another mod

bronze yoke
#

same thing goes for mods as most are made by people new to programming in general and tend to be inspired by vanilla lua

night iron
#

there is this mod that lets you see the usages left for matches and batery levels, i'm using it as a template to make my own wich will show usages to all drainable items instead

#

but yeh i'm also refactoring the original code as it looked far to convoluted

night iron
#

Given my limited LUA understanding.... is there anything else that could be optimized here?

require 'ISUI/ISInventoryPane'

local parentRender = ISToolTipInv.render

function ISToolTipInv:render()
    if not (self.item and instanceof(self.item, 'DrainableComboItem')) then return parentRender(self) end

    local parentSetHeight = self.setHeight

    local usagesValue = tostring(self.item:getDrainableUsesInt())
    local font = UIFont[getCore():getOptionTooltipFont()]
    local lineHeight = getTextManager():MeasureStringX(font, ' ')
    local usagesValueWidth = getTextManager():MeasureStringX(font, usagesValue)
    local margin = 6

    self.setHeight = function(self, height, ...)  return parentSetHeight(self, height + margin + lineHeight + margin, ...) end

    parentRender(self)

    local currentWidth = self.tooltip:getWidth()
    local posX = currentWidth - usagesValueWidth - margin

    local currentHeight = self.tooltip:getHeight()
    local posY = currentHeight - lineHeight;

    self.tooltip:DrawText(font, 'Usages left:', 5, posY, 1, 1, 0.8, 1)
    self.tooltip:DrawText(font, usagesValue, posX, posY, 1, 1, 1, 1)

    self.setHeight = parentSetHeight;
end
red tiger
#

A lot of C# / Pascal-influenced devs worked on the Java end.

#

It explains the inconsistent casing across the code base.

viral spire
#

Wasn't there a mod called Toxic Airstrike? Did the author delete it? I was so looking forward to playing that.

austere turtle
#

I've been banned from the project zomboid reddit

#

from this image

#

The least important part of my pack A FUCKING MANJI.

sour island
#

Manjis go the other way - that's a swastika

#

Probably a good idea to correct that 😅

#

Also maybe don't include something that's 90% similar 🤷‍♂️

austere turtle
#

Litterally the reference i used

austere turtle
sour island
#

People are generally not fans of Nazi symbols

#

Not sure if it was an automod (doubtful) but your sprite also doesn't make it clear it's crossed out either

austere turtle
small thunder
austere turtle
sour island
#

You're not really helping your case

frank elbow
#

Well now you know that they don't like nazi symbolism—surprise—and you can correct it & maybe reach out and appeal

austere turtle
small thunder
#

That's because you accidentally used a swastika for your mod. I get that it wasn't your intention but it's your fault for not checking if that was the right way to depict a manji.

frank elbow
#

Probably by contacting one of the reddit mods, idk how reddit works

small thunder
#

That's the way it's usually done

#

Dm one of the mods

austere turtle
#

I just want to share my new tile 😦

small thunder
#

Yeah we know

austere turtle
small thunder
#

You still fucked up lol

austere turtle
#

15 minutes to ruin 4-5 days of work

small thunder
#

It was an accident man, just get an appeal and fix the symbol in your mod

sour island
#

I'ma just call a spade a spade and say - its not a manji - just own up to wanting to include edgy imagery and move on to appealing.

deft prism
# austere turtle I don't know how to sppeal on reddit

you could try contacting spiffo bot , but yeah i would message them because its def the wrong way for a manji when it comes to symbols like that you really need to do proper research on them and i would always double check with the moderation team here before posting anything like that for clarification

small thunder
#

👆

sour island
#

lol

frank elbow
#

You've acknowledged that it's not a manji, right

sour island
#

Yes, the manji thing was bs

austere turtle
frank elbow
#

Okay, there's the ticket. You being mistaken does not change reality

#

It isn't a manji. Do a google search & then stop reposting an image with a swastika in it

small thunder
# austere turtle Its realism not edgy

Dude, I guarantee that most people aren't gonna get the reference and will assume that its a swastika, because that's what it looks like. Just change the way it looks so it's actually depicted correctly.

austere turtle
#

I was just pissed with a perma

frank elbow
#

I'm sure they'll understand that accidents happen if you explain, especially if you intend to remove it

austere turtle
#

I just want feedback for my tiles

#

The is also the possibility i mirrored a manji i created

sour island
austere turtle
#

rant in the discord = feedback on tiles 🙂

frank elbow
#

There are certainly better ways to get feedback 😅 I do like them though

austere turtle
#

Oh and floor tiles

#

ANd this unfortunately the Swastika is in it 😦

#

Fixxed

frank elbow
#

I imagine the folks over in #mapping would have more to say

red tiger
#

Hope all is well.

frank elbow
#

Haven't been frequenting this channel much, same to you

red tiger
#

Been so damn busy as of late.

#

I'm kicking around some python stuff to fix a reload issue with Pythoid.

red tiger
#

Always working on something crazy.

frank elbow
#

I'm working on things squarely in the realm of sanity, but nice to hear Pythoid is making progress

broken lake
red tiger
#

I attached a Python interpreter that works in Java environments to PZ and adapted some stuff to make it work nicely.

broken lake
red tiger
broken lake
red tiger
#

The current one has an issue with reloading so I'm trying to get it fixed.

#

Been busy IRL so it's taken a long time to get back.

broken lake
#

I feel that, sometimes irl stuff can drag away from the fun projects. And I'll check out the git some day soon!

red tiger
tame lily
austere turtle
tame lily
#

are you a smart fella or a fart smella?

austere turtle
#

Literally references from this

austere turtle
#

no wait i mean fart fella

#

wait im lost

night iron
#

is there a way to get a item "class" name as a string?

#

in LUA i mean

#

essentially i'm looking for the means to figure out what item "class name" is to be used with the instanceof instruction

bronze yoke
#

you can print it if you just need to see what class it is

#

if you need to do it at runtime for some reason you need to tostring it and extract the class name with pattern matching

raw sand
#

This is a simple one and I'm kind of embarrassed to even ask as I have edited that file before, but I have been searching for the past two hours and I can't find it for the life of me.
I'm looking for the file that lets me edit the text of the health tab. It was just a simple file that had that info that I could easily edit with Notepad++ in like five seconds.

night iron
# bronze yoke you can print it if you just need to see what class it is

Ok i tried printing the item into the tooltip and from the results i'm getting i seem to be off mark, essentially i'm trying to extend RepairAnyMod with my own mod to include the items added by Yaki's makeshifit clothing... now looking at the first one all i seem to have to do is to map those objects through this:

TweakItem("Base.ArmsProtectionLower_01-Black", "FabricType", "Leather");

but how do i figure out what the ID is for the items of Yaki's mod? my plan was to somehow inspect them in game....

bronze yoke
#

you can see that with item:getFullType() but i'd probably just look at the item scripts at that point

night iron
#

Given my lack of knowledge on how to properly mod PZ what should i be looking for in Yakis mod? Lua files?

night iron
#

Add yaki's clothing / armor to the RepairAny mod

ancient grail
#

idk what repair any mod does

grizzled fulcrum
#

hey glytcher that guy in your steam comments about the bus thing, it's true, at least with his modlist I could reproduce the issue

#

I'll have to look to see why it could be happening. but idk

ancient grail
ancient grail
grizzled fulcrum
ancient grail
#

i appreciate it ! thank you

grizzled fulcrum
rustic shale
#

world war 2 zombies

ancient grail
#

i pasted mods folder outside

feral briar
#

I have a question about some "voice line mod"
Somebody ever tried to make a mod that put real voice lines on the TV Programms to do more imersion? I know some actors friends (myself included) that could help to make brazilian portuguese voice lines to the TV programs like WBLN Reports.
I just want to know if somebody already have this idea or are putting efforts to make this a real thing.

tame lily
#

dude

#

dudes

#

if i replace the attachments on thjs

#

with the attachments on this

tame lily
#

the other is from theworkshop

#

would it allow me to actually finally put more tools on the tool belt?

raw sand
round notch
#

My first mod (Overpowered for people who want to chill on zomboid with no worries of dying)

uneven ore
#

How do I make a player eat a food item faster?

bright fog
#

There is a project, tho idk if it's still active

chrome veldt
#

Hey guys, do you know if it's somehow possible to rotate annotations on the map? I'd like to allow text to be displayed diagonally to match the grid but so far I didn't find a solution

chilly relic
#

Hey, where i can find vanilla "AlcoholPower" script?

chrome veldt
chilly relic
chrome veldt
#

I see, I'm gonna try to find something

#

I don't think this mechanism is exposed to lua unfortunately, you might have to poke into the java side

chrome veldt
chrome veldt
#

Adding o.maxTime = o.maxTime / 10 before the return o at the end of the method would make it 10 times faster for every food item (drinks and cigarettes included).

onyx valve
#

Hello, a question, how can I make a weapon reload faster? I modified the ReloadTime parameter to a lower number but the weapon still reloaded the weapon as if I had not modified anything.

bronze yoke
#

the duration of most actions like that is tied directly to the animation

onyx valve
#

ooooh ok thanks a lot jajajh

hidden compass
#

I checked the Java implementation and couldn't figure it out, so please let me know if you know.
If a zombie is nearby while sleeping, it will not attack until the player wakes up.
Do you know the implementation reason for this?

crisp flicker
#

is IsoThumpable is used to make something that's built by the player that's health can only be modified by zombie thumping or I guess a sledge hammer

#

been mostly browsing through the lua code but there's a lot of java functions mixed in, so im just trying to make sense of it since im not on my desktop and most of my ram is being gobbled up by Zed so I doubt i'd have any luck using intellijs decomp stuff in the app

tranquil kindle
lone wyvern
ancient grail
#

im not sure if theres a vanilla way of the sound automatically lowered but heres what i did and would like to share to you guys

dynamic volume based on distance

function PsychoZedMod.VolumeHandler(dist, range)
    if dist >= range then
        return 0
    elseif dist <= 0 then
        return 1
    else
        return 1 - (dist / range)
    end
end

function PsychoZedMod.getCrySfx()
    return 'PsychoCry_'..tostring(ZombRand(1,7))
end
function PsychoZedMod.getScreamSfx()
    return 'PsychoScream_'..tostring(ZombRand(1,3))
end
function PsychoZedMod.getLaughSfx()
    return 'PsychoLaugh_'..tostring(ZombRand(1,8))
end

function PsychoZedMod.playSFX(zed, sfx)
    if not PsychoZedMod.isPsychoZed(zed) then return end
    local range = 50
    local pl = getPlayer(); if not pl then return end
    if PsychoZedMod.isClosestPl(pl, zed) then
        local sq = zed:getSquare()
        if sq then
            local vol = PsychoZedMod.VolumeHandler(PsychoZedMod.checkDist(pl, zed), range)
            if luautils.stringStarts(sfx, "PsychoScream") or string.find(sfx, "PsychoScream")  then
                if SandboxVars.PsychoZed.DeathScreamAttract then
                    addSound(zed, zed:getX(), zed:getY(), zed:getZ(), 50, vol);
                end
            end
            getSoundManager():PlayWorldSound(tostring(sfx), sq, 0, 50, vol, false);
        end
    end
end


floral shore
#

does anyone know which file the vanilla professions are defined in?

ancient grail
floral shore
crystal crypt
#

someone knows how can i learn to make UI´s ?

#

and if IntelliJ IDEA helps of learning how to mod ?

#

@tranquil kindle you´re my hope hahaha

#

@smoky tendon

tranquil kindle
crystal crypt
#

and i dont understand nothing

#

do u know where is the debug mode scripts ?

#

and UIS

#

i think its more ez to learn seeying the debug menus

#

nah , im just going to give up , no ones explain nothing.

tranquil kindle
#

I can't explain something that i just don't know nothing about

crystal crypt
#

i know , its not your fault

#

im searching about learning how to make a single ui/menu for 1 hour and i didint found anything

indigo pasture
crystal crypt
#

THANKS ! @indigo pasture

bronze yoke
covert vault
#

Hey everyone, does the Red Error Box is so hard coded that no one ever managed to make a mod to disable it? I know the devs won't disable it but I wonder why no one made a mod for it (that I know of)

frank elbow
dusky quiver
#

is ZombRand() some kind of "predictable pseudo-random" generator function that returns same values on server + on client? or what's its purpose?

bronze yoke
#

it's just a random number generator

dusky quiver
#

because lua standard libraries don't have one?

bronze yoke
#

they're supposed to, but kahlua doesn't implement it

dusky quiver
#

ok, thanks

bright fog
#

Ah nvm read that wrong

frank elbow
#

Regular Lua does too (just for the record, in case that was intended to be contrastive)

bronze yoke
#

it's actually a really weirdly high quality random number generator that arguably should not have been used for nearly anything the game uses zombrand for

#

you can call on java's native random function with```lua
local rand = newrandom()
rand:random(min, max)

bright fog
#

Yeah I use that now

still rain
#

Hey guys, I'm trying to figure out how evolved recipes work, and it looks like my recipe for a protein shake doesn't have any valid ingredients. What should I put into the evolvedrecipe parameter for the game to recognize the protein powder as an ingredient?

#

I've got it ste to JunkiezProteinShake, which is the name of both the resulting item and the evolvedrecipe

bronze yoke
#

EvolvedRecipe = RecipeName:HungerAmount e.g. EvolvedRecipe = JunkiezProteinShake:10 if you wanted it to add 10 hunger from the ingredient

still rain
night iron
#

Is it possible to defined a recipe created item to have less them 100% condition?

night iron
#

ok so i figured out how to change the created item via binding the onCreate handler with a lua script.... now is it possible to change the created item name? i tried both of this with no success:

    result:setDisplayName('Improvised ' .. result:getDisplayName())
    result:setName('Improvised ' .. result:getName())
#

btw is there any public API documentation for this stuff anywhere?

#

nvm i had a bug in my code wich was actually preventing the newer version from runing the setName actually worked

bronze yoke
still rain
# bronze yoke go ahead and post it, but i can't promise i'll know the solution, i don't do too...
    imports {
        Base
    }
    /** Comments can be multiline like this
        and can appear anywhere in the file, even in the
        middle of a { block }
    **/
    item JunkiezProteinPowder
    {
        DisplayName = Protein Powder,
        DisplayCategory = Food,
        Type = Food,
        Weight = 1.0,
        Icon = JunkiezProteinPowder,
        CantBeFrozen = TRUE,
        EvolvedRecipe = Soup:5;JunkiezProteinShake:5;Beverage:5;Beverage2:5;Cake:10;Sandwich:2;Sandwich Baguette:2;FruitSalad:2;HotDrink:10;HotDrinkRed:10;HotDrinkWhite:10;HotDrinkSpiffo:10;HotDrinkTea:10;Pancakes:10;Waffles:10;ConeIcecream:5;PieSweet:10;Toast:5;Oatmeal:10,
        Packaged = TRUE,
        HungerChange = -40,
        Calories = 2440,
        Carbohydrates = 48,
        Lipids = 120,
        Proteins = 480,
        UnhappyChange = 20,
        ThirstChange = 50,
    }

        item JunkiezProteinShake
    {
        DisplayName = Protein Shake,
        DisplayCategory = Food,
        Type = Food,
        Weight = 0.8,
        CustomContextMenu = Drink,
        Icon = JunkiezProteinShake,
        CantBeFrozen = TRUE,
        HungerChange = -15,
        Calories = 250,
        Carbohydrates = 18,
        Lipids = 12,
        Proteins = 120,
        ThirstChange = -20,
        ReplaceOnDeplete = WaterBottleEmpty,
        CustomEatSound = DrinkingFromBottlePlastic,
        StaticModel = WaterBottle,
        WorldStaticModel = WaterBottleFull,
        UseDelta = 0.1,
        UseWhileEquipped = FALSE,
    }

    evolvedrecipe JunkiezProteinShake
    {
        BaseItem:WaterBottleFull,
        MaxItems:4,
        ResultItem:JunkiezMoreSupplements.JunkiezProteinShake,
        AddIngredientSound:AddItemInBeverage,
        Name:Prepare Protein Shake,
        CanAddSpicesEmpty:true,
        Template:JunkiezProteinShake,
    }
    
}

#

Thank you @bronze yoke , I appreciate the extra set of eyes

#

It works for all of the other evolved recipes, just not the protein shake one

bronze yoke
#

hmm, let me check something

#

ughh this is dumb, i completely forgot about this

#

the EvolvedRecipe = thing is hardcoded to only ever search the Base module

still rain
#

Oh! Does that mean I need to set it to JunkiezMoreSupplements.JunkiezProteinShake:5?

bronze yoke
#

unfortunately that'll just make it look for Base.JunkiezMoreSupplements.JunkiezProteinShake

#

i think from looking at this you can probably attach an item to an evolved recipe using lua but the straight forward solution would just be to move the evolved recipe into base (everything else can stay in your module though)

still rain
#

I'll give that a try! Let me move that over now

#

Looks like we finally have some progress! I don't have the option of making the shake if I right click on the powder or the bottle, but the craft helper finally recognizes it as an ingredient

ancient grail
grizzled fulcrum
#

so for example, if the sound is like this:

sound mysound {
    ...
    is3D = true,
    clip {
        file = media/sound/somefile.ogg,
        distanceMin = 10,
        distanceMax = 100,
        volume = 1.0,
    }
}

Feel free to correct me, but I believe that at distanceMin tiles away, the volume will be 1.0 - and at distanceMax tiles away the volume will be 0.0 (and anywhere between is the volume scaled linearly based on the position between min and max).

#

Or, if you don't specify distanceMin, then I presume it just scales the volume from the sound's position to distanceMax instead of from distanceMin to distanceMax.

bronze yoke
#

the only correction i have is that it isn't scaled linearly, dropoff is exponential

grizzled fulcrum
#

ah ok, I did assume that it was linear my bad

bronze yoke
#

i considered nitpicking this in the code example as linear would probably sound very unconvincing

grizzled fulcrum
#

true, I wish the dev could change the exponent

#

like to have the curve change

#

on a side-tangent, what would be a decent way to auto-detect what script you are editing?

#

I don't think textmate grammar has that complicated of features, I thought maybe looking at the filename to see if it ends in a suffix like guns.item.txt or metal.recipes.txt something like that but that seems too hacky

#

actually ignore what I said as scripts can have multiple things in them ;-;

#

I am thinking with my "encapsulation is good practice" brain instead of "what is possible" brain

bronze yoke
#

i do actually like the idea proposed here though, an annoyance with the zedscript plugin is that there isn't an extension for it so it can't enable itself

grizzled fulcrum
#

yeah I have to manually do it for each script and it's so frustrating

bronze yoke
#

i'm sure the game would still accept e.g. items.zs.txt

grizzled fulcrum
#

and when I restart ide I have to do it again

#

ya

#

I will check

#

it does load it

ancient grail
#

when i posted the code about the volume it was for a different mod
but im doing this now which is also related to sounds.. i couldnt fetch all the audio scripts. i tried various syntax and closest i got to retrieve an array was using
GameSounds.getCategories
but the categories returned empty arrays

#
getScriptManager():getAllGameSounds()

this lags when i try it

#

getName() doesnt work 😦

night iron
#

Modding noob question... the client, server and shared folders inside most mods lua folder is it by convention or is there effectively a difference when placing lua files on each of those folders?

ancient grail
#
local sounds = getScriptManager():getAllGameSounds()
for i = 0, sounds:size()-1  do
    local sfx =  sounds:get(i)
    print(sfx)
end
bright fog
#

Client side, all 3 folders are loaded

#

Server side, only shared and server are loaded

lethal wind
#

I've a very simple idea for a mod (very niche but probably easy to code). If anyone's interested lmk

night iron
night iron
#

Is it possible to "listen" to player actions like dig grave and have an event triggered with a reference to the item used to do such action?

grizzled fulcrum
#

you bring up a good point that what's the point with the folders, most people including me just use the folders as categorisation, since like you mention the client loads all 3 anyway

#

but here's the general gist of how I structure my mods:

  • All client code goes in client folder like normal
  • All server code goes in server folder, but since it can be loaded on the client, prevent the entrypoint from running by checking if the client is loading it and returning (will be different based on how you structure your mod's lua code)
  • All shared code (code that server and client both use) goes in shared folder like mod metadata (id, version, dummy structs/tables, type definitions, etc)
#

Of course you could just put the client and server code in the client folder, but then the server wouldn't load it

#

You could also put all the client code in the server/shared folder and there are no downsides, but it's kinda counter-productive and harder on yourself lol

#

tl;dr it's kinda stupid

night iron
#

thanks for the in deepth answer, though i'm still at a stage that i can't even figure out what should go just for the client and just for the server so for now i'll just stick to the shared folder :x ::ducks incoming modding experts anger::

grizzled fulcrum
#

well it depends what you want

night iron
#

right now just playing with creating items based on the vanila versions

grizzled fulcrum
#

a LOT (and I mean it!) of your code will be client sided just because that is how the game has been made

#

the only things that would need to go in server folder are stuff involving either code that syncs stuff between players or somethn else I can't remember

night iron
#

for example i have a new recipe to create an improvised shovel out of branches, sheet strips and sharp stones, however the generated item is a copy of the vanilla shovel with just 2 max condition

#

would this sort of code require to be server side?

grizzled fulcrum
#

wdym the generated item?

#

or you mean just the item that you get from crafting

night iron
#
module Base {
    recipe Improvise Shovel {
        TreeBranch/MetalPipe/MetalBar=1,
        LeatherStrips=2,
        SharpedStone=1,

        Result:ImprovisedShovel,
        Time:300,
        Sound:PutItemInBag,
        Category:Improvised Tools
    }
}

#

like that

#

ImprovisedShovel is just a copy of the vanilla one with less condition

grizzled fulcrum
#

btw im curious, why did you pick Base module instead of your own one?

#

I see literally every modder do that, but I can't understand it

night iron
#
module Base {
    item ImprovisedShovel {
        (...)
        ConditionMax=2,
        (...)
        DisplayCategory=Improvised,
        DisplayName=Improvised Shovel,
        (...)
    }
}
#

just learning my away around... it's far less problemtic to change existing stuff then create it from the ground up without knowing what i'm doing 😦

grizzled fulcrum
night iron
#

that's my next step

#

so what i wanted to do now is for example had a high chance of that item breaking when used to TakeDirt or DigGrave

grizzled fulcrum
#

Oh, if you want to do that then I'd put the callbacks in the shared folder

#

I am trying to think for how you would get the takedirt/diggrave action thing

night iron
#

yeh been digging through the vanilla lua to try to figuera that one out

#

i was looking at this one right now:
lua\server\BuildingObjects\ISShovelGroundCursor.lua

function ISShovelGroundCursor:create(x, y, z, north, sprite)
    local playerObj = self.character
    local square = getWorld():getCell():getGridSquare(x, y, z)
    local groundType,object = self:getDirtGravelSand(square)
    local fullType,emptyItem = self:getEmptyItem()
    if luautils.walkAdj(playerObj, square, true) then
        ISWorldObjectContextMenu.transferIfNeeded(playerObj, emptyItem)
        ISWorldObjectContextMenu.equip(playerObj, playerObj:getPrimaryHandItem(), predicateShovel, true, true)
        ISTimedActionQueue.add(ISShovelGround:new(playerObj, emptyItem, object, "blends_natural_01_64", fullType))
    end
end
#

would it be feasable to override this and somehow get a ref of the item used to trigger this and break it?

grizzled fulcrum
#

Ideally you'd override the ISShovelGround action function that is after the action is performed

#

because if you did it in this function create, if the player walks away your code would be executed

#

So I'd personally hook ISShovelGround:perform because perform function is called when the action is completed, then you can calculate the things and damage the shovel

night iron
#

hummm is that action in this file though? still learning how to read this code

grizzled fulcrum
#

Most likely not, they usually put their actions in a separate file

night iron
#

lua\client\BuildingObjects\TimedActions\ISShovelGround.lua it seems

grizzled fulcrum
#

yes

night iron
#

from what little i can understand from this code i'll have to get both items on the character hands and then figure out which one is the shovel right?

#

btw is there any public api documentation anywhere we can consult regarding this item, character and other objects?

grizzled fulcrum
#

You hook it like this (as an example)

-- Caching global variables for faster code speed
local getPlayer = getPlayer
local ISShovelGround = ISShovelGround

-- Fancy mmodule thing
local hooks = {}

--- Our perform function
function hooks.perform()
    -- Do code at start of vanilla perform
    print("hello at start")

    -- Let vanilla perform code run
    o_perform()

    -- Do code at end of vanilla perform
    print("hello at end!")
    
    local player = getPlayer()
    local shovel = player:getPrimaryHandItem()

    -- Do your stuff here!
end

function hooks.init()
    local o_perform = ISShovelGround.perform
    ISShovelGround.perform = hooks.perform
end

return hooks
#

the whole hooks variable is just a fancy thing for a module, I think lua's PIL has it somewhere you can learn about

#

in this case, you'd just call hooks.init() when you want to hook it, like OnGameBoot

#

THOUGH getting the item is a whole separate thing

#

Timed actions are done on the client so you can just do getPlayer() to get the player (I will edit the example to demonstrate)

#

since getPlayer() function will return the client player (the one you are playing) but it will return nothing if the code is running on the server (because the server isn't playing as any player in the game)

night iron
#

ok ok i'm listening...

grizzled fulcrum
#

let me see how the action works one second

#

Do you know if the item has to be equipped at all for the action to be performed?

night iron
#

so we don't need to do something like:
require 'BuildingObjects/TimedActions/ISShovelGround' to ref ISShovelGround ?

grizzled fulcrum
#

No, lets see why:

night iron
#

i think so 🤔

grizzled fulcrum
#

I call project zomboid's lua implementation PZ Lua for this reason

#

it's not actually fully lua, it's Kahlua

#

its very wacky in it's own way

night iron
#

ok and does the lua file where i have this code have to follow any naming convetion other then live inside one of the 3 predefined client / shared / server folders?

grizzled fulcrum
#

You see how ISShovelGround is a global variable and isValid is a function which is being added to the ISShovelGround table?

night iron
#

is that on line 7 creating a global ?

grizzled fulcrum
#

yes

night iron
#

ha!!!!!

grizzled fulcrum
#

derive more or less returns a table

#

and as you probably know, you can reference globals from anywhere without referencing anything

night iron
#

so once delcared as a global it's available on all other scripts i would assume?

grizzled fulcrum
#

yep

night iron
#

kk got it!!!

grizzled fulcrum
#

btw I am not familiar with ISShovelGround action as I mod the game more than play it so what is the bag for?

#

It's referencing emptyBag and I assume it's like a bag to put the dirt in right?

night iron
#

so how do i get that init to trigger again you mentioned the onGameBoot event?

#

yeh i think for this action you need an item with 'takeDirt' like a shovel and an empty sack or a non empty sack of the same type

#

and then it will fill the bag with dirt, gravel or sand

#

depending on the tile

grizzled fulcrum
# night iron so how do i get that init to trigger again you mentioned the onGameBoot event?

Well assuming the file is in the client folder (which it should be, action code is client-side and just get synced to server), you just need a file in the client folder like this:

-- Requiring our module from before
local hooks = require("hooks")

-- Caching globals
local Events = Events

local events = {}

function events.on_game_boot()
    -- Call our function
    hooks.init()
end

function events.init()
    Events.OnGameBoot.Add(events.on_game_boot)
end

-- Just call events.init literally anywhere, even here!
events.init()

return events
#

this is how i'd do it so modify it as you wish

#

but try to learn from it instead of copy pasting, that's all I ask

night iron
#

kk thank you very much

#

so my new file with the override doesn't have to follow any particular name / path convetions other then living inside one of the 3 predefined folders right?

grizzled fulcrum
#

I will try to figure out how to get the shovel the player is using the best way I know of, I just gotta see how the action works

grizzled fulcrum
#

but if you plan on requiring it, you need to use it's file name like I did with require("hooks") where the file name for the hooks file was hooks.lua

night iron
#

kk thanks i'm experiementing it my self as well but by all means let me know if you find it out

#

ok and the path for the require is always the path starting after client | shared | server right? regardless of being a vanilla file or a mod file?

grizzled fulcrum
#

yes

night iron
#

kk thanks

grizzled fulcrum
#

though do know that if you name files the same, the require will act weird

#

like if you have same named files in both client and shared, and you require one of them from another file in client for example, it will not know whether to use the client file or the shared file so I think it defaults to the last loaded one which would be the client file

grizzled fulcrum
grizzled fulcrum
night iron
#

yeh i suspected that but haven't confirmed it yet

toxic escarp
#

is there a way to check if the player is sneaking or sitting?

night iron
#

does this makes any sence in LUA?

improvisedToolsOverrides = improvisedToolsOverrides or {}

local shovelGround = improvisedToolsOverrides.shovelGround = {}

The idea is to lazely create a global called improvisedToolsOverrides and then ref shovelGround localy while creating it as a "prop" for the global...

grizzled fulcrum
#

you might have to do that in two statements as I don't think that will work

night iron
#

kk so no chaining assigments then

grizzled fulcrum
#

you could do ```lua
improvisedToolsOverrides.shovelGround = {}
local shovelGround = improvisedToolsOverrides.shovelGround

#

yea no multiple assignment

#

unless it's a function's return values

night iron
#
improvisedToolsOverrides = improvisedToolsOverrides or {}

local shovelGround = {}

improvisedToolsOverrides.shovelGround = shovelGround
#

i was going with this but yeh same idea

grizzled fulcrum
night iron
#

also from your example it seems like local vars are actually available on all functions in the same file regardless of where they are declared??

#

looking at this one in particular:

function shovelGround.perform()
    originalPerform()

    local player = getPlayer()
    local shovel = player:getPrimaryHandItem()
end

function shovelGround.init()
    local originalPerform = ISShovelGround.perform

    ISShovelGround.perform = shovelGround.perform
end
grizzled fulcrum
night iron
#

kk good to know

#

so functions have no exclusive "local" scope got it

grizzled fulcrum
#

that is why I don't use local variables/functions inside my modules

#

so I can access them outside of the file by requiring the file

toxic escarp
night iron
#

hummm i though you didn't had to require a file to have access to non local vars 😕

grizzled fulcrum
#
-- can't access outside of file (local)
local var = "test"

-- can access outside of file (global)
var = "test"

-- can't access outside of file unless you require the module, since the module is local and returned by the file
local file = {}
file.var = "test"
return file
#
-- in a separate file

-- wont work
print(var)

-- will work since it's global
print(var) -- "test"

-- will work but only if you require the module
local file = require("file")
print(file.var)
night iron
#

Ha ok i get it

#

i mean i see you used the same name for both local and local var's but i get what you mean

#

anyway i'm getting an error with your example @grizzled fulcrum

#

it looks like getPlayer is not defined there?

grizzled fulcrum
#

is the code in the client folder?

#

thought i'd double check anyway

night iron
#

yep in the client

grizzled fulcrum
#

if you read the error, it says line # 12

#

so your originalPerform function is nil

night iron
#

hummmmm

grizzled fulcrum
#

did you add it to your module?

night iron
#
local getPlayer = getPlayer
local ISShovelGround = ISShovelGround

improvisedToolsOverrides = improvisedToolsOverrides or {}
improvisedToolsOverrides.shovelGround = {}

local shovelGround = improvisedToolsOverrides.shovelGround

function shovelGround.perform()
    print('--------> IMPROVISED TOOLS: shovelGround.perform START')

    originalPerform()

    local player = getPlayer()
    local shovel = player:getPrimaryHandItem()

    if shovel ~= nil then
        print('--------> IMPROVISED TOOLS: Type ' .. shovel:getFullType())
        print('--------> IMPROVISED TOOLS: Name ' .. shovel:getName())
    end

    print('--------> IMPROVISED TOOLS: shovelGround.perform END ')
end

function shovelGround.init()
    print('--------> IMPROVISED TOOLS: shovelGround.init')

    local originalPerform = ISShovelGround.perform

    ISShovelGround.perform = shovelGround.perform
end

return improvisedToolsOverrides.shovelGround
grizzled fulcrum
#

see the issue in init?

#

I will give you a sec

night iron
#

and

local shovelGround = require("overrides/shovel-ground")

local Events = Events

local events = {}

function onGameBoot()
    print('--------> IMPROVISED TOOLS: OnGameBoot')

    shovelGround.init()
end

Events.OnGameBoot.Add(onGameBoot)

return events

grizzled fulcrum
#

line 28 in your shovelGround.init

night iron
#

is it because it's declared as a local?

grizzled fulcrum
#

yes, you will not be able to use it outside of the function scope

#

put it in your module and reference it like that

night iron
#

but i did ask this before and you did have it like that on your example... so local vars are resctricted to the context of functions after all right?

grizzled fulcrum
#

yes they are, sorry if I said otherwise, let me see

#

o I do have that in my example sorry lol

night iron
#

nah it's fine that actually makes more sence i was very susprised that local function variables were accessable from other functions

grizzled fulcrum
#

I am typing in discord off memory so it's a bit wack but most of it should be work

night iron
#

lol nah it;s all good the universe actualy makes sence again he he

grizzled fulcrum
#

If you want to see an actual example of what I do here is what I do:

local hooks = {}

hooks.o_get_text = nil

--- @param ... any
--- @return string
--- @overload fun(text: string): string
--- @overload fun(text: string, ...: any): string
function hooks.get_text(...)
    -- code hereeeeeeeeee
end

function hooks.register()
    logger:debug("Hooking getText...")
    hooks.o_get_text = getText
    getText = hooks.get_text
end

return hooks
#

so you can tell if I hooked something by checking if hooks.o_get_text is nil, and when we unhook just set those back to nil after setting the original function back to the original reference

#

like unhooking (if you ever need it which you shouldn't because unhooking technically happens with lua reload anyway) you would do this

function hooks.cleanup()
    getText = hooks.o_get_text
    hooks.o_get_text = nil
end
#

basically just reversing the process

#

actually wait nevermind that wouldn't work I don't think, that's tricky damn

#

since variables are references to the values, this would set getText to the original but then also set it to nil, just forget I said anyting lol

#

but you don't need to worry about cleanup for hooks unless you really specifically need to*

#

just a practicality, but this is an example showing that i am stupid:

local test = 123
myvar = test
print(myvar .. " " .. test) -- 123 123
test = 456
print(myvar .. " " .. test) -- 123 456
#

so it turns out you don't know as much as you should (in my case)
"Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy." so I was right, I am just tripping over myself every step of the way im going to crawl in a hole now

night iron
#

ok i'm getting another error but this one seems trickier :x

#
local getPlayer = getPlayer
local ISShovelGround = ISShovelGround
local originalISShovelGroundPerform = nil

improvisedToolsOverrides = improvisedToolsOverrides or {}
improvisedToolsOverrides.shovelGround = {}

local shovelGround = improvisedToolsOverrides.shovelGround

function shovelGround.perform()
    print('--------> IMPROVISED TOOLS: shovelGround.perform START')

    originalISShovelGroundPerform()

    -- local player = getPlayer()
    -- local shovel = player:getPrimaryHandItem()

    -- if shovel ~= nil then
    --     print('--------> IMPROVISED TOOLS: Type ' .. shovel:getFullType())
    --     print('--------> IMPROVISED TOOLS: Name ' .. shovel:getName())
    -- end

    print('--------> IMPROVISED TOOLS: shovelGround.perform END ')
end

function shovelGround.init()
    print('--------> IMPROVISED TOOLS: shovelGround.init')

    originalISShovelGroundPerform = ISShovelGround.perform

    ISShovelGround.perform = shovelGround.perform
end

return improvisedToolsOverrides.shovelGround
grizzled fulcrum
#

what is line 12 in ur file

night iron
#

so is it possible the original function is losing it;s context and so the self keyward is nil?

grizzled fulcrum
#

huh

night iron
#

it's an empty line Oo

grizzled fulcrum
#

I think it's referencing the original call I have no idea

night iron
#

do lua functions work like JS functions where a function context is based on the caller unless bound?

grizzled fulcrum
#

I know why

grizzled fulcrum
#

but self isn't nil, it's your module

#

at least I think so, it's so mind-fucky

grizzled fulcrum
night iron
#

well it depends actual nomral functiosn will have the this point to the context of the caller

#

while bound or arrow functions have this point to the declaration context

grizzled fulcrum
#

for example, if the function is part of a module and you use : (like the original perform func does) then self belongs to the module of the perform like this:

function myModule:myFunction()
    -- self is basically context of myModule here
end

-- above is the same as doing below

function myModule.myFunction(self)
    -- self is context of myModule still
end
#

so I think that when we hook the function, our context's self overwrites the original self value in the original function

#

I am trying to think, maybe you could do

night iron
#

should i use the : operator instead then?

grizzled fulcrum
#

I think not

night iron
#

waaaaaaait

#

should this:
originalISShovelGroundPerform = ISShovelGround.perform
be
originalISShovelGroundPerform = ISShovelGround:perform

grizzled fulcrum
#

self in lua is basically a normal variable

grizzled fulcrum
#

I don't even think that's valid syntax

#

: is only used when you are defining a function or calling a function with self as the first arg

#

since that is a variable with a reference to the original perform function, you don't want to call it or use :

night iron
#

humm i did find another mod that does something similar and they do this:
parentRender(self)

grizzled fulcrum
#
myModule:myFunction()
myModule.myFunction(myModule --[[basically self]])
``` are the same
night iron
#

but this inside this:
function ISToolTipInv:render()

grizzled fulcrum
#

actually wait a sec

#

you gave me an idea to check something

night iron
#

so function deplared with : parent refenrenced with . and then invoked with name(self)

grizzled fulcrum
#

ye, it's just syntax sugar

#

btw you can set self in lua since it's just a normal variable

night iron
#

kk

grizzled fulcrum
#

I was thinking maybe could set self to the original one but I think it's not as hard

#

I've just gotta find it

night iron
#

trying something as well need a minute

#

yep this worked like a charm, no errors!

#
local getPlayer = getPlayer
local ISShovelGround = ISShovelGround
local originalISShovelGroundPerform = nil

improvisedToolsOverrides = improvisedToolsOverrides or {}
improvisedToolsOverrides.shovelGround = {}

local shovelGround = improvisedToolsOverrides.shovelGround

function shovelGround:perform()
    print('--------> IMPROVISED TOOLS: shovelGround.perform START')

    originalISShovelGroundPerform(self)

    -- local player = getPlayer()
    -- local shovel = player:getPrimaryHandItem()

    -- if shovel ~= nil then
    --     print('--------> IMPROVISED TOOLS: Type ' .. shovel:getFullType())
    --     print('--------> IMPROVISED TOOLS: Name ' .. shovel:getName())
    -- end

    print('--------> IMPROVISED TOOLS: shovelGround.perform END ')
end

function shovelGround.init()
    print('--------> IMPROVISED TOOLS: shovelGround.init')

    originalISShovelGroundPerform = ISShovelGround.perform

    ISShovelGround.perform = shovelGround.perform
end

return improvisedToolsOverrides.shovelGround
grizzled fulcrum
#

for example, calling ModuleA.test(self) inside of ModuleB would mean self is ModuleB

night iron
#

shovelGround:perform() + originalISShovelGroundPerform(self)

grizzled fulcrum
#

nice

#

I don't know how that works and I don't want to know why

night iron
#

lolol

#

it sounds like : declarations are unbound declarations that get their self assigned when invoked

grizzled fulcrum
#

yes, whne you use : in func declaring it basically just does local self = module at the start of the function behind the scenes

night iron
#

while . declarations seem to either have their self bound to the declartion scope or needs it to be passed in as argument

grizzled fulcrum
#

I want to test so many things I am confused as HECK I will cook

night iron
#

Success:

#

thanks @grizzled fulcrum you have been invaluable in helping me understand how to mod this!!!

#

think i'm going to dive into it for a bit now 😄

grizzled fulcrum
#

what's weird is self doesn't change after hooking

#

albion where are you lool

#
main: self = table: 0x1bf0eb0
shovel: self = table: 0x1bf0eb0
#

so basically you're passing your own table to the original function as self, but it still works???

#

I am actually baffled

#

seriously baffled

#
local main = {}
main.test = 36536536

main.o_perform = nil

function main.perform(self)
    print("main: self = " .. tostring(self) .. " | test = " .. tostring(self.test))
    main.o_perform(self)
end

function main.init()
    main.o_perform = ISShovelGround.perform
    ISShovelGround.perform = main.perform
end

main.init()
ISShovelGround.perform(ISShovelGround)

return main
ISShovelGround = {}

ISShovelGround.test = 123

function ISShovelGround:perform()
    print("shovel: self = " .. tostring(self) .. " | test = " .. tostring(self.test))
end
main: self = table: 0x13b4e20 | test = 123
shovel: self = table: 0x13b4e20 | test = 123
#

both pointing to the ISShovelGround table as self

#

albion if you ever see this please help me my brain is cooking like a bbq

bright fog
night iron
#

is it possible to define a recipe's ingredient min or max condition to be eligible?

bright fog
#

With OnTest I believe or smthg like that you can link to a lua function, which allows you to return true or false based on conditions of items

night iron
#

was just about to ask what the onTest event was for lol

ancient grail
#

if ontest returns false the option on wont show up

or if it doesnt return anything

#

i mean false

night iron
#

is the onTest aplied to all possible ingredients then?

ancient grail
#

sorry

bright fog
ancient grail
#

only to recipe

night iron
#

looking at a vanilla example it seems to be invoked on a per item basis:

function Recipe.OnTest.IsNotWorn(item)
    if instanceof(item, "Clothing") then
        return not item:isWorn()
    end
    return true    
end
ancient grail
#
function Recipe.OnTest.FullLiquor(item)
    if not item:hasTag("Petrol") then return true end
    return item:getUsedDelta() == 1
end
night iron
#

and it seems true means it's not valid?

ancient grail
#

from vanilla

#

so if doesnt have the tag and its empty
then option will showup

#

getUsedDelta is the amount consumed

so 1 means its empty

#

iirc

#

you could test it by making similar functions

#

i could be wrong

night iron
#

also is it possible for the Result to be a lua script as well? like this: keep [Recipe.GetItemTypes.Scissors]

ancient grail
ancient grail
#

that part means dont despawn the item that has Scissors tag

#

if there are multiple scissor items you need one to do the recipe
and so whatever that item is
keep it

#

removing the keep will despawn that item

night iron
#

i understand that, my question was a bit different

#

in this case keep could either be given a / sperated list of item ids or in this case is given a lua script which returns the list

#

what i mean to know is can we do something similar with the 'Result'

ancient grail
#

you can do that using getAllItems()

#

if i understand you correctly

what are you trying to achieve

#

whats the list for?

night iron
#

i would like to have a recipe that generates different results depending on the ingredient used

#

so something like: Result: Recipe.GetItemTypeBasedOnIngredient

ancient grail
#

you can put everything on an array then use oncreate

the item you will spawn will be based on

array[ZombRand()]

#
local array ={"Base.item",}
local count = #array
local toSpawn=array[ZombRand(count)]
getPlayer():getInventory():AddItem(toSpawn)

note im typing this via mobile without reference so check the syntax

night iron
#

sure and i understand this goes on the onCreate event that's all fine but what about the Result keyword on the recipe? do i just supress it? or does it have to have a default item generated by the recipe?

ancient grail
#

yes

#

you add to the recipe script removeResult item or something

#

so that the default result wont spawn
and you then add whatever you want using oncreate

you cant dynamically change the scripts result
as far as i know

#

but i havent explore recipe manager
so there might be a way

#

did this answer the question?
result is important there should always be result i think
just block it using that removeresult or whatever the actual syntax is

#

ill try to find exact syntax

night iron
#

yep i think it does just wish we could use a lua file as the result

ancient grail
#

i think thats right

RemoveResultItem

night iron
#

RemoveResultItem:true,

ancient grail
#

yes

bronze yoke
#

calling the function with : implicitly passes the object to the left as self, so all vanilla calls still pass an actual object to the overridden function, regardless of what table you define it in

ancient grail
bronze yoke
#

it matters, if you call a function with : e.g. table:function() this is equivalent to table.function(table)

#

there's no actual magical meaning to the self parameter, it behaves exactly like any other function parameter, it's just that : hides it

#

function t:foo() and function t.foo(self) compile to exactly the same bytecode

night iron
#

that actualy makes a lot of sense

#

thans for figuring this out @bronze yoke

grizzled fulcrum
#

From what I thought, when calling a function with self (see main.perform where I call the original function with the self value of the new perform function), I thought this would be equal to main table because we are calling it from main but it is somehow equal to ISShovelGround

bronze yoke
#

you call it with ISShovelGround.perform(ISShovelGround), as you didn't use : the first argument (self) is ISShovelGround

grizzled fulcrum
#

I assume self to be the container that is calling the function (usually the module or file, idk) right?

#

in that case where I pass ISShovelGround as self to perform, I don't see how it is transferring

#

like the o_perform variable that holds the reference to the original function doesn't store the value of self, so how does it know that ISShovelGround is self in the new perform function and not main?

bronze yoke
#
local t = {}

-- exactly equivalent:
function t:foo()
function t.foo(self)
function t.foo(bar)

-- also exactly equivalent:
t.foo(t)
t:foo()
#

since you call perform with only the argument ISShovelGround, ISShovelGround is self and that's what's passed along

grizzled fulcrum
#

wait I think it clicked lol

#

im so stupid wth

#

I am thinking like it's a different lang

#

I forgot that o_perform variable is literally the reference to the function and not the reference to a function that calls the original perform function

bronze yoke
#

ahhh i see

grizzled fulcrum
#

once I realised you can just replace the ISShovelGround.perform(ISShovelGround) with main.perform(ISShovelGround) it made much more sense lol

#

I was thinking with the concept that it should be like this instead: main.perform(main)

#

this is why I try to avoid self stuff in every language 😂

#

except java, it's unavoidable I swear

bronze yoke
#

that's one of the reasons i've never given it a chance LOL

grizzled fulcrum
#

it's useful for a total of like 2.5% of your entire codebase

#

it's like the one thing you use because it's convenient

#

I guess it's more confusing with Lua (for me) especially because it doesn't really follow OOP as other languages do, so self in Java you can atleast follow along more whereas Lua it's imo harder to follow

bronze yoke
#

yeah, i consider it the most unintuitive part of lua

#

since all the feature really does is hide what's actually happening

#

it wants you to believe that lua supports oop when it really doesn't

night iron
#

oop is overrated anyway ::hides::

grizzled fulcrum
#

some people say that, but I don't understand anything but OOP

#

it's like ingrained into my brain after coding for so long

#

like if I don't encapsulate every single thing and abstract everything into their own little sections I die

#

but hey at least I can sleep easier than the sick individuals who put 17,000 lines of code into ONE FILE as their whole entire mod

#

(really happened)

bronze yoke
#

i'm an oop defender but my counter argument to most criticisms of it is just 'well yeah, you shouldn't use oop for that'

night iron
#

thats just following the single responsibility principal has nothing to do with the paradigm used

grizzled fulcrum
#

I guess I mix them if the google definition is anything to go by

#

like in rust I use functional programming a lot because it's just easier and more convenient (I think the rust std has a bias towards that or even solely based around that)

#

but things like java c++ c# it's hard to use functional programming because a lot if not all of the codebase already exists as OOP

#

me when I tell people I never use recursion

night iron
#

ok i'm missing something again.... so i got this recipe with the following:

        OnTest:Recipe.OnTest.IsBrokenImprovisedTool,
        OnCreate:Recipe.OnCreate.SalvageImprovisedTool,
        OnGiveXP:Recipe.OnGiveXP.SalvageImprovisedToolXP

and under my lua/client/recipes i got a lua file with the following:

Recipe.OnTest = Recipe.OnTest or {};
Recipe.OnCreate = Recipe.OnCreate or {};
Recipe.OnGiveXP = Recipe.OnGiveXP or {};

function Recipe.OnTest.IsBrokenImprovisedTool(item)
    print('--------> TEST Start');

    if item == nil then return false end;

    print('--------> ' .. item:getName() .. ', ' .. item.getCondition());

    print('--------> TEST End');

    return item.getCondition() < 1;
end

function Recipe.OnCreate.SalvageImprovisedTool(items, result, player)
    print('--------> CREATE Start');
end

function Recipe.OnGiveXP.SalvageImprovisedToolXP(recipe, ingredients, result, player)
    print('--------> EXP Start');
end

yet in game i'm getting the following error when selecting the recipe:

bronze yoke
#

either define them in server or in a different table

#

the Recipe table is created by a server lua file, if you define it before that it'll just be deleted

night iron
#

ok still having trouble to understand what should go in client and what should go in server 😕

bronze yoke
#

in this case it is basically completely arbitrary

#

the vanilla ones are in server because they are

night iron
#

oooooook so Recipe.x should go under server is that correct?

bronze yoke
#

yeah

night iron
#

kk

bronze yoke
#

you can also just put them in e.g. MyModRecipe and define it wherever you want

#

the oncreate just needs to be the name of the function in the global namespace

night iron
#

hummm it's still a good exercise to get a grip on how to mod PZ

#

but good to know it doesn't have to be in Recipe.x

bronze yoke
#

when you *really* need it for things like e.g. iterating through a tree, iterating over a stack is the same thing with less of those issues

#

in c++ clang tidy just straight up tells you off for even using it

grizzled fulcrum
#

wait, no wonder...

bronze yoke
#

as far as i know it's only needed by the client

#

but usually when i say this someone says the server needs it too or anticheat will go off which i have never investigated

grizzled fulcrum
#

wait I am confused, you say if it is defined before it will be deleted right? never trust the folder names

bronze yoke
#

yeah, the server folder goes Recipe = {} so anything in there is getting dropped

grizzled fulcrum
#

you called it like a month ago, im still used to client meaning client and server meaning server

bronze yoke
grizzled fulcrum
#

yes

#

you know what boils my blood more than anything else on this planet

#

when im using the black formatter for py and it limits my code to like 88 chars, so when a print statement is 89 chars for verbosity it formats it to this attrocity:

print(
    "SOMEREALLYLONGPRINTSTATEMENTOHMYWHYISTHERESOMUCHTEXTHOWAREYOUREADINGIT"
)
#

like just don't even put the brackets on 3 whole new lines

bronze yoke
#

😭

grizzled fulcrum
#

Just to make sure, is there any situation where server code isn't loaded?

#

or rather lua files in the server folder aren't loaded

bronze yoke
#

in singleplayer, server doesn't actually load until you start loading a game

#

that is, it's not loaded on the main menu

grizzled fulcrum
#

It feels really wrong to put my recipe stuff in the server folder when the client uses it lol
but I can't put it in shared where I expect it to be because it gets overwritten right?

bronze yoke
#

if you just don't use the Recipe table you don't need to worry

grizzled fulcrum
#

trueee

#

thats a good idea actually

night iron
#

is there a way to check if an item has a method defined?

#

something similar to:
if item:getCondition == nil then return true end;

grizzled fulcrum
#

also I'll probably put that stuff I was talking about before into zedscript extension, I think I'll just end up making my own due to how his extension works

bronze yoke
#

i still haven't actually gotten around to trying it LOL so i don't have any specific attachment to it

bronze yoke
grizzled fulcrum
#

ye lol

night iron
#

that throws an error saying it expects an argument

bronze yoke
#

because you used : instead of .

grizzled fulcrum
#

but also, if you're checking for methods to determine the type like IsoObject or IsoWorldInventoryObject then use instanceof(obj, "IsoObject") instead!
( i only say this bc I've never seen someone check if methods exist before on items)

bronze yoke
#

only use : when calling/declaring functions

night iron
#

trying to avoid a situation where soe of the items don't seem to have the getCondition method Oo

grizzled fulcrum
#

maybe the items are like ContextMenuItemStack and Item?

bronze yoke
#

you definitely have some unexpected data in there, getCondition is declared in InventoryItem which is the base class for items

grizzled fulcrum
#

I do this to check for the Item itself (but this is only checking one)

--- @param player_idx integer
--- @param context ISContextMenu
--- @param items InventoryItem[] | ContextMenuItemStack[]
function context_menu.create_inventory_menu(player_idx, context, items)
    --- @type SandboxVarsDummy
    --- @diagnostic disable-next-line: assign-type-mismatch
    local sandbox_vars = SandboxVars[mod_constants.MOD_ID]

    --- @type InventoryItem
    local water_item = nil
    for i = 1, #items do
        local item = items[i]

        if instanceof(item, "InventoryItem") then
            --- @cast item InventoryItem

            if  item:isWaterSource()
            and item:isTaintedWater() == false
            and item:getCurrentUses() >= sandbox_vars.BrushTeethRequiredWater then
                water_item = item
                break
            end
        else
            --- @cast item ContextMenuItemStack

            for j = 1, #item.items do
                local real_item = item.items[j]

                if  real_item:isWaterSource()
                and real_item:isTaintedWater() == false
                and real_item:getCurrentUses() >= sandbox_vars.BrushTeethRequiredWater then
                    water_item = real_item
                    break
                end
            end
        end
    end

    if water_item == nil then return end
    context_menu.do_context_menu(water_item, player_idx, context)
end
#

just copy pasted it from my vscode but basically you check if the item you're looping through is an InventoryItem

#

if not, you can assume it's a ContextMenuItemStack which is just a table of some stuff (I think)

bronze yoke
#

it's the item stacks in your inventory, even a single item is a stack unless you specifically open the stack and select the item

grizzled fulcrum
#

yes that is correct I am just bad at game

bronze yoke
#

the way it's implemented is kind of gross

grizzled fulcrum
#

I don't play the game much so I end up asking other people how things work in the game myself lol

bronze yoke
#

stack.items[1] == stack.items[2] because that's the way the game displays the stack when you open it

grizzled fulcrum
#

that is not epic 😦

night iron
bronze yoke
#

tostring()

night iron
#

arrrrrrrr of course no camel case duuuhhh

#

🫢

bronze yoke
grizzled fulcrum
#

I've probably said this before but I switch between camelcase and the underscore thingy like a schizo switches their meds so I end up refactoring my whole codebase every now and then for absolutely no benefitial gains other than my monke brain going "i like that more now"

grizzled fulcrum
bronze yoke
grizzled fulcrum
#

but having access to the java has been probably the most helpful thing I'd say fullstop

#

assuming you can read java 😮

bronze yoke
#

honestly at least the java is typed

grizzled fulcrum
#

yes

bronze yoke
#

deciphering these weird ass table structures takes years off my life

grizzled fulcrum
#

I love my lua ArrayList type ✨

bronze yoke
#

damn i forgot to document the weird objects OnFillWorldObjectContextMenu actually passes and i already forgot

grizzled fulcrum
#

though sumneko's ls is not bad, it feels clunky in that you can't really do in depth typings before it starts to crumble

#

but it can only do so much considering it's lua

bronze yoke
#

i'm trying to remember if you can type 'tuple' tables or if i dreamed that

grizzled fulcrum
#

what the hell is that

#

like a table of tuples or a tuple of tables

bronze yoke
#

a table that is a tuple

grizzled fulcrum
#

0____0

bronze yoke
#

maybe you can just do a class definition and then ---@field [1] type actually lol

grizzled fulcrum
#

how does that work in lua, not even in typings

bronze yoke
#

it's not really a language feature and i may be making assumptions based on how tuples work in python

#

(and bear in mind that i have barely used tuples in python LOL)

grizzled fulcrum
#

because from what I know

#

a table is a table

#

a function that returns 2 values just returns 2 values, no tuple

#

I don't even think tuples exist

bronze yoke
#

yeah i just mean a table that behaves like one

grizzled fulcrum
#

can you not just annotate it like a table? or you need specific typings for specific indexes

bronze yoke
#

my thinking is if they aren't all the same type

#

the best example i can give is distributions tables

#

they go string, number, string, number

grizzled fulcrum
#

ohh

bronze yoke
#

when it's a class with named fields you just declare a class but for numeric indexes i don't remember if that was even real

#

come to think of it whether i dreamed it or not i remember it not really working very well LOL

grizzled fulcrum
#

so you can do

--- @type { [1]: string, [2]: number }

or some scuffed thing like that, but thye problem is that it only covers those two indexes specifically and not all of them

#

I am trying to run through all the things I know

bronze yoke
#

i don't know how many times i've scrolled past this table without paying attention to it

grizzled fulcrum
#

I literally have that open......

#

I'm just going to save it at this point

bronze yoke
#

oh i found where i used it and it's not exactly what i remembered

#

i think the distributions typing thing did work too (if i didn't dream it) but was essentially useless because any indexing just returned string|number

queen oasis
#

tuples are the devil

bronze yoke
#

i'd never seen the python style dictionary annotation, i do like that a lot, really bugs me how much i write table< in my annotations

#

the table literal style might also cut down on how many weird/fake class declarations i need to do for events typings

#

though i guess you can't comment fields that way so maybe not

frank elbow
#

(Idt this change has made it to the extension yet, or at least it hadn't the last time I checked)

bronze yoke
#

widening casts and actual generics support would be lifesavers

frank elbow
#

Sometimes I visit the generics super issue on the repo just to dream

night iron
#

is there any way of inspecting all methods of a lua object? just tried something like this but aparently my item value is not a table:
-- for key,value in pairs(item) do
-- print("found member " .. key);
-- end

#

it's a userdata

bronze yoke
#

in kahlua you should(?) still be able to iterate over it

#

however pairs will not find its methods

#

use getmetatable(item).__index and iterate over that

night iron
#

ok I'm starting to slowly lose my will to live after running in circles trying to pull this one off...

#

I've got this recipe to salvage broken improvised tools:

module Base {
    recipe Salvage Improvised Tool {
        ImprovisedShovel/ImprovisedSledgehammer/ImprovisedTongs/ImprovisedScissors=1,
        keep [Recipe.GetItemTypes.Scissors]/[Recipe.GetItemTypes.SharpKnife],

        Result:RippedSheets,
        RemoveResultItem:true,
        Time:300,
        Sound:PutItemInBag,
        Category:Improvised Tools,
        OnTest:ImprovisedTool.OnTest.IsBroken,
        OnCreate:ImprovisedTool.OnCreate.Salvage,
        OnGiveXP:ImprovisedTool.OnGiveXP.SalvageXP
    }
}

Tried to use the onTest event to only enable the recepie for improved tools that are effectively broken with:

function ImprovisedTool.OnTest.IsBroken(item)
    if item == nil then return false end;

    if item:getDisplayCategory() ~= 'Improvised' then return true end;

    if not item:isBroken() then return false end;

    print('--------> ' .. item:getName() .. ' is valid ');

    -- for key,value in pairs(getmetatable(item).__index) do
    --     print("found member " .. key);
    -- end

    return true;
end
#

now here's the fun bit.... when i right click a broken improved tool on my inventory i do get that print but no crafting recipe is listed on the context menu

#

and when i inspect the recipe on the crafting window nothing gets printed which seems to point that in that screen no broken items are ever evaluated and i get this:

#

if i move that print a few checks up it will trigger for all the other items but not for the broken ones

bronze yoke
#

add AllowDestroyedItem:true to your recipe script

night iron
#

ha!!!!! thanks!

#

yep that did it thank you so very much @bronze yoke

#

so now looking at the list of methods we have available for this items there isn't any reference to what ingredients were used to craft them right?

bronze yoke
#

no, they don't store that at all

#

if you need to you can add relevant data to the item's mod data

night iron
#

hummm i did create this items on my mod so i guess i could do that

#

i'm assuming this needs to be on the onCreate event of the items i want to later know how they were made right?

bronze yoke
#

yeah

night iron
#

@bronze yoke if you're still around i managed to print the items used during the recipe with:

function ImprovisedTool.OnCreate.Tool(items, result, player)
    for i = 0, items:size() - 1 do
        local item = items:get(i);
        local type = item:getFullType();

        print('--------> ' .. type);
    end
end

mind teaching me how i can now inject those types into the result?

#

the result is a:

module Base {
    item ImprovisedShovel {
        ( ... copy of the vanila shovel )
    }
}
bronze yoke
#
local modData = result:getModData()
modData.MyMod = {}
modData.MyMod.itemsUsed = {}
for i = 0, items:size() -1 do
    table.insert(modData.MyMod.itemsUsed, items:get(i):getFullType())
end
night iron
#

ha! so is this modData like some sort of meta data?

bronze yoke
#

yeah, it's literally just a table attached to an object

night iron
#

kk thank you very much!

bronze yoke
#

it's persistent so it's best to only put primitive types in it

#

things like objects won't persist

night iron
#

sounds reasonable yeh

#

i suspected that much ence why i was planning on storying the types of the ingredients rather the ingredients them selves

runic siren
#

alright so i thought of a good "expansion" to the idea of the spiffo redux mod

does anyone know how i can replace the zombie models with skeletons, but still allow them to wear clothes?

#

i'll just copy paste from the other server and add extra context

#

it's mostly for when people go to remove the suit/mask from the spiffo zed if/when they do it so they don't just see a person underneath

it's kind of a side idea that i'm fine if it doesn't work out, but it'd be really really nice if i can manage it because at this rate this is half a gimmick mod and half something i'm serious about lmfao

#

i love serious gimmick mods

night iron
#

huh... so lua has no "continue" to skip an iteration on a for loop?

night iron
twin pike
night iron
orchid quiver
#

Can anyone tell me how can I generate random numbers? I'm trying to make one of my mods generate a random time of the day.

#

I have tried everything and I haven't been able to make lua generate random numbers.

bright fog
#

Or

#

Better in performance (if you cache the first part)

local rand = newrandom()
local value = rand:random(n,m)
orchid quiver
#

Awesome! Thank you so much! ❤️

night iron
#

ok what am i doing wrong here? is it something obvious that my dyslexia is preventing me from seeing?

function ImprovisedTool.OnCreate.Salvage(items, result, player)
    for i = 0, items:size() - 1 do
        local item = items:get(i);
        local metaData = item:getModData();
        local improvisedTool = metaData.improvisedTool or {};
        local materials = improvisedTool.materials;

        if materials ~= nill then
            print('--==--==> Type: ' .. type(materials));

            print('--==--==> Size: ' .. materials:size());

            -- for j = 0, materials:size() - 1 do
            --     local material = materials:get(i);

            --     local roll = ZombRand(1, 21);

            --     print('--==--==> Material: ' .. material .. ' roled a ' .. roll);
            -- end
        end
    end
end
#

it's throwing an error on the second print, the one with the size

#

also the type print works as i can see the ouput on the console window as table

bronze yoke
#

are you sure this is the right error? it doesn't really look like anything in your code

night iron
#

nop the error that was being shown then didint even match the actual error but any case it was throwing an error with that :size on a table

#

i had to iterate through it like this instead:

            for _, material in pairs(materials) do
                local roll = ZombRand(1, 21);

                print('--==--==> Material: ' .. material .. ' roled a ' .. roll);
            end
#

but i dont understand why when the items was iterated with a regular incremental for

crisp flicker
#

from what I understand, Umbrella is just the demcompiled code cut up to just show the java functions and parameters, you install it by adding it as a library with whatever IDE you use, but everytime I download it, either cloning through git or downloading the zip and extracting it, it's empty, Im assuming im missing something so if anyones got an idea where im stuck that would be great.

bronze yoke
night iron
#

hummm ok and the way to iterate a table is though pairs?

bronze yoke
#

or a numeric for using this syntax:```lua
for i = 1, #t do
local v = t[i]
-- do something with v
end

#

if your table uses only consecutive numeric keys (so it acts like an array) this is much faster

night iron
#

what is the # for?

bronze yoke
#

it gets the length of the table

night iron
#

ha ok ok thanks

bronze yoke
#

you can also download a zip from releases or use the addon manager if you're using vscode

night iron
#
function ImprovisedTool.OnCreate.Salvage(items, result, player)
    print('--==--==> Type: ' .. type(items));

    for i = 0, items:size() - 1 do
        local item = items:get(i);
        local metaData = item:getModData();
        local improvisedTool = metaData.improvisedTool or {};
        local materials = improvisedTool.materials;

        if materials ~= nill then
            for j = 1, #materials do
                local material = materials[j];
                local roll = ZombRand(1, 21);

                print('--==--==> Material: ' .. material .. ' roled a ' .. roll);

                if roll > 15 then
                    print('--==--==> Material: ' .. material .. ' needs to be spawn in the character inventory ');
                end
            end
        end
    end
end

this worked like a charm 😄

#

tomorrow's goal: spawn the actual item

bronze yoke
#

oh, i see you're checking if materials ~= nill then, should be nil

#

probably still works because there is nothing defined as nill anyway

night iron
#

he he fair enough

#

fixed just in case

orchid quiver
#

Months in PZ go from 0 to 11 or 1 to 12? 🤔

bronze yoke
#

0 to 11

orchid quiver
#

Thank you very much! ❤️

night iron
#

thanks @bronze yoke you rock!

crisp flicker
#

got it working and all thanks for that just not sure why they'd post windows and linux specific files that're empty

bronze yoke
#

we don't post those, github generates them automatically

#

umbrella is a collection of three separate typings projects which are added as submodules, none of the stubs actually reside within the umbrella repository itself

crisp flicker
#

fair, thanks

pure hollow
#

where are the textures for the grass dirt roads ect located

#

wanna convert them to mars textures

#

think i mightve found them

royal pawn
#

Hello!

Any lua wizards want to waste their time teaching me how to create a mod I have in mind?

Modding docs I found are too confusing for my non coder brain to figure out. unhappy
I have experience creating lua mods for other game, but this time I feel as lost as I felt starting out the first time...

pure hollow
#

i want to make a mod where i could make a moodle based on being indoors or not to have a oxygen timer when outside and inside buildings without a door or windows or both, and when inside a building with doors and windows intact theres no oxygen timers (at end of timer u suffocate to simulate mars and a habitat),,, where should i look to learn things about how they doo the moodles is there some script files i should look at? where would be a good starting point? if that didnt make sense please do tell me lol.

#

maybe i have to look at the claustraphobia trait

royal pawn
pure hollow
#

ohh cuz it has to connect to a house?

royal pawn
pure hollow
#

ohh thats a good idea yea

royal pawn
#

their logic already deals with "air tight" indoors, so you could just invert it

pure hollow
#

perfectt

#

is the generator all within one script

royal pawn
#

welp that's where my knowledge ends

pure hollow
#

great starting point

#

yeah cant find generators in the files 😅

royal pawn
#

I'd research the docs

sinful elbow
#

C:\Users\mtwri\Pictures\1ART REF\Zomboid\3D modeling stuff\New Models\Props\Props All\FBXs\Generator.FBXd

#

the descriptions for folder names here at spiffo are fantastic

night iron
#

Morning folks!

night iron
royal pawn
night iron
#

my strategy has been to scour other mods and sift through the vanilla media folder until i get stuck then i pester the good folk here about it

royal pawn
#

Want to make a mod where some zombies get confused and attack other zombies.

night iron
#

this will help you inspect some objects btw:

    -- for key,value in pairs(getmetatable(item).__index) do
    --     print("found member " .. key);
    -- end
#

also runing the game in debug mod is a massive help as well

#

I also barely started with modding PZ but with 20+ years of experience coding i'll try my best to help you when i can 🙂

#

can't say i have even looked into anything related to zombies though

royal pawn
#

Yeah and I have 0 real expirience so Ill take any help at all.

#

It seems like there are literally 0 mods that do this sort of thing, so it's either impossible or noone likes the idea much

night iron
#

are you using any coding IDE? like VSCode?

royal pawn
#

sublime text

#

its a text editor

#

if that's what you mean. I dont use any engines or whatever is the right name

night iron
#

ok not my first choice so not sure if this is possible in sublime but if you "create a project" with the vanilla media folder you can then search the source code for stuff which can speed you your investigation

royal pawn
#

I usually google docs of the game Im trying to mod

night iron
#

my project in VSCode includes the user's zomboid/workshop where i develop my mods, the steam workshop folder 108600 (PZ mods folder) and the steam/steampps/common/projectzomboid/media (the vanilla code)

royal pawn
#

Ngl I had it open once, but one day the tab went away and I didn't try to open it up ever since...

#

Trying to find this tab atm

#

Should look something like this?

#

it's from other game i mod

night iron
#

ok just to recap:

  • Vanilla: \steamapps\common\ProjectZomboid\media
  • Other Mods: \steamapps\workshop\content\108600
  • Your Mods: Users[username]\Zomboid\Workshop
#

i don't use sublime so not sure that's the right panel but that file structure does not look familiar to me

royal pawn
#

I think I can only open/link 1 folder to my script

night iron
#

just get vscode mate it's free

royal pawn
#

Aw shucks it's a big boy coder program

night iron
#

on VSCode you start by click this blue button and pick one of those 3 folders:

#

afterwards just right cleck an empty area on the same panel and pick the add folder to workspace and add the rest:

royal pawn
#

I have to create my mod's folder first to link it right? Or vscode will just make one up

night iron
#

nah i do that my self, though all it takes is to create a folder inside that workshop folder i mentioned in your users folder

#

once you've set this up you can simply right click any folder and pick this find in folder option to search it's source code:

#

which switches to this panel:

#

hope that helps 😉

royal pawn
#

Thanks, hopefully Ill find examples of zombie's agro behavior

grizzled fulcrum
#

specifically the debugtools submod because the others aren't needed

#

it lets you right click and inspect any object and it's java methods (among other things), its great

night iron
#

btw finally managed to reach my first goal, ability to create improvised shovels, this are extremly flimsy (condition 2) and will break 75% of the time when collecting dirt. Once broken it can be salvaged with a small chance to recover each of the materials used to create it originaly 😄

#

next step is to apply this to other tools and activities and then get skills to play a roll on that condition and breaking / material recovering chances

#

lastly get some exp gaining when creating / salvaging those tools

#

i may also dabble with icons eventualy to make them distinguishable from vanilla tools other then through their name

royal pawn
#

Sounds pretty cool

royal pawn
#

yeah debug tool doesn't really help me to understand what exactly is the agro logic

#

I guess it's hard coded for the zombies to attack/react to player only?

grizzled fulcrum
#

so I don't think the attack target can be anything but

royal pawn
#

Unfortunate... I really wanted to make it happen

#

The Idea was like this: Zombie gets "hungry", jumps other zombie and starts to eat it. Hopefully in build 42 we'll get that option in the expanded mod support.

bright fog
#

(I don't remember which, I believe it's IsoMovingObject but it can only target players naturally, however you can set their target to a zombie)

royal pawn
#

IsMovingObject

bright fog
#

You can't make them naturally target other zombies

grizzled fulcrum
#

interesting

royal pawn
#

I didn’t see a single usage of it in targeting. Gotta do some experiments. But I don’t know how to even start doing that

bright fog
#

IsoMovingObject ?

#

That's bcs zombies are never set to target IsoMovingObject, but IsoPlayer, which is an IsoMovingObject

royal pawn
# bright fog wdym ?

Yeah it’s described in the docs, but I haves seen a single real application of it as an attack target

bright fog
#

But they can in fact target IsoZombie

royal pawn
#

Welp didn’t see either

bright fog
#

What did you not see lol I'm confused here

#

There's nothing to see

royal pawn
#

I’m not a coder. Usually I look up working examples.

bright fog
#

Bandits

#

Bandits are IsoZombie, and they are coded to be able to attack other zombies

royal pawn
#

So I’ll try and experiment with it my self. Never used bandits mods. Gonna download it later. Thanks for the tip

bright fog
#

They probably use the targeting too tho I don't have confirmation of that

#

As they might not use the default targeting system at all

#

As they handle every actions of the zombies to act human like

royal pawn
#

I’ve looked up superb survivors, those used some janky scripts, so I expect the same from bandits

bright fog
#

Superb Survivor is absolutely trash, also it doesn't use IsoZombies

#

It uses IsoPlayer

#

It creates IsoPlayers

#

Which is the reason it's incompatible with MP

royal pawn
#

Should be interchangeable tho, no?

bright fog
#

Bandits is not janky

#

Bandits is actually quite good, it's not perfect of course like nothing but it is quite really good

bright fog
royal pawn
#

Aight sounds like great news to me.

bright fog
#

IsoPlayer and IsoZombie do not work the same at all

royal pawn
#

I meant in targeting sense not as a controller or whatever the pawns are called

bright fog
#

No

#

I'd be surprised

#

An IsoPlayer doesn't have a target

royal pawn
#

Hmm

bright fog
#

setTarget is an IsoZombie method

#

Not an IsoGameCharacter or below

#

Thus it can't be applied to players

royal pawn
#

Aight. I never looked up IsoPlayer so I guess that’s the reason for jank

bright fog
#

Most definitely

#

I'm even surprised IsoPlayers can be created and made as NPC as the class was made for players, not any form of AI ?

royal pawn
#

Not that uncommon tbh. Same can be done in ground branch. It’s just an empty controller/pawn that can be forced to do anything.

#

Guess it was better for better survivors, because of the player like actions foraging/farming/doc etc

bright fog
royal pawn
#

Oh well. I’m to dumb to understand the nitty gritty

night iron
grizzled fulcrum
#

oh and you can do it even without the debug tools, in the F1 menu

night iron
#

actualy i just tested and worked pretty well i do imagine it can be problematic for large structural changes for tiny tweeks seems to work great and it does cut down on delay between changes dramatically

grizzled fulcrum
#

but you can do some stuff around that, I just dont like how it makes things

night iron
#

it's good to be aware of that but like i said it's awesome when just tinkering with minor tweeks

#

is there a lua equivalent to js string.contains(string) ?

grizzled fulcrum
#

but I will say, string.find(str, pattern, start?) will help

#

or alternate syntax which I think is cleaner, str:find(pattern, start?) where start is an optional parameter specifying the start to find from

night iron
#

btw is there anyway to clear the console without exiting to desktop?

grizzled fulcrum
#

it returns the start and end index of the found substring

grizzled fulcrum
#

alternatively, there is string.match(str, pattern, start) which returns the groups found (kinda like regex with () and %1)

#

and remember, Lua doesn't use regex, it uses it's own regex-like pattern matching syntax

night iron
#

kk

celest talon
#

I'd like to start making mods as a hobby. Can anyone help? I need a roadmap for Lua.

grizzled fulcrum
#

well there's actually a fourth param which basically acts like match, like this:

local start_idx, end_idx = ("Hello, world!"):find("Hello", 1, false)
#

where 1 is just the start index (which is an optional arg that is default to 1 if not specified)

grizzled fulcrum
#

and false is another optional arg whether to use pattern matching, so if you have it to default (false) it will use pattern matching and if not it will only find literals

bright fog
#

I can understand you guys develop mods that don't require it but there are way too many instances of it being extremely useful, especially for the little work it requires you in organizing your files

bright fog
grizzled fulcrum
#

It really depends on how you structure your mod, and you have to go out of your way to prevent these unexpected things from happening when hot-reloading, so I just outright just not recommend it. I am not saying they can't use it, just recommending that they stay away from it.

bright fog
#

Organizing your files should be a priority for your personal experience, separating events in a separate files is quite a good way of organizing bcs you can easily see where your functions link

grizzled fulcrum
#

Also, you can easily just avoid it by using smaller save maps, like the time it takes to reload lua I can just reload the lua and the save and be where I was before without any issues.

bright fog
#

I organize my files this way

-- myMod_module.lua
local myModule = {
    -- put data which is set here
}

return myModule
-- myMod_main.lua
-- main functions here
-- myMod_events.lua
-- add the functions in the events here
grizzled fulcrum
#

This is a bit of a stretch, but even so, most people don't have 200 concurrent issues that they need to solve straight away. It's much easier to manage one or two.

grizzled fulcrum
#

reloading lua can still break stuff, it just depends on how you set up stuff

bright fog
#

This simple organization is enough to reload in-game without causing any problems

bright fog
#

In fact I gained quite a fuck ton, losing some bad habits and properly organizing files

grizzled fulcrum
#

and most noob modders (no offense) don't even know that hot-reloading can break stuff, so when you clear them to just use it and then they come back wondering why their scripts break or why their code is just completely off, it's no wonder

night iron
#

sorry to interrupt the ongoing best practices discussion but can you guys help me understand if i'm doing something wrong here... now that i'm using this community developer tools, when inspecting my new items i just noticed they have no javafields whatsoever as opposed to the vanilla objects that do have a bunch of java proprieties on them...

#

am i messing this up somehow?

bright fog
#

The debug menu is dogshit too so gl finding out about it with this

grizzled fulcrum
bright fog
#

Today I constantly swap between my code, write some bits, long or short, test things directly in-game, by just reloading in-game

#

Smthg breaks ? I don't need to quit, reload lua, join back

#

I can just look at the code, fix it, instantly reload and done

#

I literally gained fucking hours of my life

grizzled fulcrum
night iron
#

I'm absolutely onboard with you'r approach @bright fog as this is what i experience as well

bright fog
#

And I find it a terrible habit to keep telling people that they shouldn't do it. Just at least please be objective that it can be extremely useful but they have to be aware of how it works

night iron
bright fog
#

And YES it can't be applied to every code types, there's things that do require quit and reload lua

#

Like patching for example

night iron
#

70% - 80% of the time it fine to just reload

bright fog
#

yea, even if you reload fast, it adds up SOOOOO much sometimes

#

Especially when you test bits

night iron
#

in any case can i get some help on why on earth my new items are losing their java props?

bright fog
#

java props ?

night iron
#

fields i mean

bright fog
#

You sure that shows your item ?

#

You right clicked your item and inspected it ?

night iron
#

yep

#

this is my recipe:

    recipe Improvise Scissors {
        Twigs=1,

        Result:ImprovisedNeedle,
        Time:300,
        Sound:PutItemInBag,
        Category:Improvised Tools,
        OnCreate:ImprovisedTool.OnCreate.Tool
    }
}```
#

and the item:

#
module Base {
    item ImprovisedNeedle {
        ConditionMax=2,
        DisplayCategory=Improvised,
        DisplayName=Improvised Needle,
        Icon=Needle,
        Medical=TRUE,
        MetalValue=2,
        SurvivalGear=TRUE,
        Tags=SewingNeedle,
        Type=Normal,
        Weight=0.1,
        WorldStaticModel=Needle
    }
}
grizzled fulcrum
night iron
#

and the onCreate:

function ImprovisedTool.OnCreate.Tool(items, result, character)
    -- local metaData = result:getModData();

    -- metaData.improvisedTool = {};
    -- metaData.improvisedTool.materials = {};

    local metalValue = 0;

    for i = 0, items:size() - 1 do
        local item = items:get(i);
        local type = item:getFullType();

        if string.find(type, "Metal") then metalValue = metalValue + 10 end

        -- table.insert(metaData.improvisedTool.materials, type);
    end

    -- result:setMetalValue(metalValue);
end
grizzled fulcrum
#

you need comma on all param lines

night iron
#

really? 😮

grizzled fulcrum
#

yes

night iron
#

ok let me try that then

#

that changed nothing and as i suspected this is the absurd trend of expecting interperters to be fault tolerent regarding dangling comas -.-

night iron
#

ok this must be some issue related with the community dev tools because when salvaging the item print('--==--==> Metal: ' .. item:getMetalValue()); returns the expected value. so even though it's not showing on that inspector window the field is def set

bronze yoke
#

it's unavoidable

#

kahlua's reflection api only allow us to inspect fields declared by the actual class of the object, not its parent classes

#

99% of item fields are declared by a common parent class so none of those are ever visible with this tool

#

this is why you don't see anything at all

night iron
#

ok ok so nothing for me to worry about then

bright fog
#

I actually don't use the inspection tool that much personally