#General mod help

1 messages · Page 1 of 1 (latest)

errant sundial
#

You see the @Register.item part?

#

That's what you want

#

The public itemArgus: ItemType; below it is marking a "field" for your registered item's ID to be injected into

#

Worry about the actual collecting of blood later, for right now just try to get familiar with creating an item using this syntax

#
@Register.item("bottleOfBlood", {
})
public itemBottleOfBlood: ItemType;

Start with this, add properties to the item description as necessary

#

You can use Debug Tools to give yourself a bottle of blood — make sure Debug Tools is installed and enabled, then use Alt + P to "inspect" yourself, and there's an "Add Item" dropdown that you can select your bottle of blood in

#

This is all you should need, besides putting your item texture in the right place

#

Should be static/image/item/bottleofblood.png

#

If you want your item to be able to appear on the ground, you'll also need to provide an _8.png version (8x8)

flint quarry
#

should the class be named after the mod or the item/items?

errant sundial
#

Doesn't matter

#

Name it what you like

flint quarry
#

Whats it just kindof a container?

errant sundial
#

Yeah, it's basically just the "scripts" container for your mod

#

You can put "event handlers" there, so that you can run code on specific events happening, like for example, the player doing an action, or pressing a button on their keyboard, or an item being destroyed, etc

flint quarry
#

Can I just auto import stuff as I write?

errant sundial
#

Yeah if it lets you

#

Sometimes it's bad and dumb and fails to auto import

flint quarry
#

Argus has all these but I shouldnt need all this to import the item

errant sundial
#

yeah, you shouldn't need most of those

flint quarry
#

Yeah im not sure what I need

#

How would I know?

errant sundial
#

When you type something and there's a red squiggle under it, hover over it and see what the error says

#

If it says something like this, then you need to import something

flint quarry
#

connot find module

#

thats all for argus though

errant sundial
#

Yeah ignore argus

#

It's cuz you haven't run wayward +mod update on it

flint quarry
#

yeah it doesnt have the resources

#

what is the mod instance before the registrys

errant sundial
#

You can probably ignore that for now

#

It's a little complicated

#

It starts mattering when you're registering multiple things and need their descriptions to reference each other

#

Focus on just getting the item working for now

flint quarry
#

okay

#

the code looks good, how do I call the sprite? I dont see where argus references a png

errant sundial
#

That "bottleOfBlood" in the code I gave you is setting the name of the registered item. All images in the game are loaded via paths made with those, and sometimes also with the mod name included

#

For items it's always static/image/itemname.png

#

It's converted to lowercase and stripped of special characters for the path

flint quarry
#

so does the capitilization of letters have to match between my png and the code?

#

oh

#

so it doesnt matter

errant sundial
#

yeah

#

you could actually make the registration name something crazy like "BoTtLE. $%&@#$%@#$of () BLOOD" and I think it would still turn into the string bottleofblood.png lol

flint quarry
#

With that code it should load in then and be spawnable with the debug tools?

errant sundial
#

yep!

flint quarry
#

alright thanks! let me try

errant sundial
#

if there's any issues it should also warn you about them in the console

#

so you might want to have that open

#

(toggle developer tools in the developer section of options, if you haven't opened it before)

flint quarry
#

the file says it failed to load the mod

errant sundial
#

Are you building it?

#

Ctrl + Shift + B?

flint quarry
#

oh

errant sundial
#

There should be an out folder created

flint quarry
#

oh my gosh lol

#

I copied the out folder from argus cause I didnt know what it was

errant sundial
#

lmfao

flint quarry
#

🤪

errant sundial
#

In general you don't want to copy files from other mods

#

Use the wayward +mod create commands

#

They're set up to help give you a template

flint quarry
#

can I keep node modules and stuff in for now still?

#

when I load the mod

errant sundial
#

You shouldn't ever need to touch node modules

#

Just ignore it

flint quarry
#

okay, argus doesnt have one so I wasnt sure

errant sundial
#

It's because when you download a mod it's not set up for development

#

It's set up to be used

flint quarry
#

I see

errant sundial
#

It can be set up for both at the same time

#

When you publish the mod later, it'll only publish the files that allow it to be used

flint quarry
errant sundial
#

Check the log, there's still something wrong

flint quarry
#

found 0 errors watching for file changes...

errant sundial
#

Typescript not erroring doesn't mean there's not something wrong still

flint quarry
#

Theres no errors

errant sundial
#

There is definitely going to be a mod loading error

#

Since that's what the tooltip says

flint quarry
#

how do I see that

errant sundial
#

It will be somewhere in the log

#

Open the Developer Tools and look through it

#

Some tips to make debugging faster:

  1. In launch_options.json (in the Wayward steam folder), set "devtools" to true instead of false. This will make it always open the Developer Tools on every launch
  2. Press F5 to reload the game without having to close it and click Play in Steam again. (Ctrl + F5 reloads & opens most recent save.)
flint quarry
#

theres no mod.js file it looks like?

errant sundial
#

What file do you have instead?

#

Do you have any files?

#

Send me your mod.json and your tsconfig.json

#

I have a feeling you're just using argus's tsconfig.json which is not going to work

#

If you want, you could try deleting the tsconfig.json and running ../../bin/wayward +mod create . +script in the VSCode terminal, which should recreate the tsconfig.json without touching any of the rest of your files

flint quarry
#

Idk why they sent as embedded code sorry

#

the mod json was in there idk what the issue is

errant sundial
#

Hmmmmz

#

What's in your out folder?

flint quarry
errant sundial
#

You need to change your mod.json to say "file": "out/Bloodrites"

flint quarry
#

ohhh

errant sundial
#

Because you renamed the .ts file it changed the output to Bloodrites.js instead of Mod.js yeah

flint quarry
#

I thought that looked weird

errant sundial
#

Or well I guess you were probably referencing argus

flint quarry
#

Yeah I was lol

errant sundial
#

The initial setup is always the hardest part for first time modders

#

Should get a bit easier from here I think. More complicated stuff, but also easier to figure out what the problem is

flint quarry
#

Anytime you jump into something new its always a process

#

Im glad you guys take the time to help

#

many devs do not

errant sundial
#

A big part of the fun of making a game is helping people experience it how they want to experience it. If that includes modifying it, I'm all for helping there where I can, too

#

It's why every so often we do things like add game options for things that were done by old mods that aren't maintained anymore, or we decide to change how something works so that people stop feeling like they need to mod it, or when a technical change makes one kind of mod a whole lot more difficult, sometimes we just straight up add support for it into the base game in a way that allows a mod to just toggle it on

#

I have examples for all three of these

#

The way doors work now. The fact that in Runekeeper due to the container UI rework, mods that showed item stacks on tiles as container UI no longer worked, so I just straight up added support for those to the base game so that mods can just turn it on

flint quarry
#

All the work you guys do shows. The game has come such a long way

#

I have progress here but no image

#

I expected it not to have a title because I never gave it one

flint quarry
#

I got it!

flint quarry
#

Im still not understanding how im supposed to name it though

errant sundial
#

That’s done with the lang/english.json file

#

Sorry for going afk had some irl stuff going on

#

Argus will have an example of how that works

#

I'm guessing now you want to have glass bottles have a collect blood action that you can use on puddles of blood?

#

If you do I can give you a place to start in like 30 mins, have to brb again

flint quarry
#

Yeah, I'd like to try doing that next

flint quarry
errant sundial
#

Okay so

#

There's a couple new things you'll need to learn for this

#
  1. Creating a custom action
  2. Registering your custom action to an action type
  3. Injecting into vanilla descriptions (to add your custom action type to the glass bottle description)
#

That will make it so you can right click on a glass bottle while facing a puddle of blood and it'll allow you to use your "Collect Blood" action or whatever

#

Coincidentally, Argus contains the first two of those things

#

With its action "See All"

#

To start with, copy a blank version of its action into your Mod class. You'll need some extra things on it that Argus didn't need so I'm going to give you a slightly modified version

@Register.action("CollectBlood", new Action(ActionArgument.ItemInventory)
  .setUsableBy(EntityType.Human)
  .setCanUse((action, item) => {
    // this handler will be for returning whether the action is usable right now.
    // ie, if the player is actually facing blood.

    // in multiplayer, this code happens in all of the following situations:
    // - when the player is hovering the mouse over the action,
    //   so that the action can display the red text if you can't use it
    // - when the player clicks on it when it's assigned to an action slot.
    //   if it's not usable in this situation, the client doesn't even send the attempt to the server.
    // - when you actually use the action, it calls this on both the clients and the host/server,
    //   as one final check to make sure this is legal.
  })
  .setHandler((action, item) => {
    // this is called when the player actually attempts to collect the blood.
    // in multiplayer, to keep the clients and the host/server in sync, this code happens for both.
  }))
public readonly actionCollectBlood: ActionType;
#

This actually takes care of 1. and 2., we just need to fill in the canUse and handler

flint quarry
#

Action(ActionArgument.ItemInventory)

#

Is this for items that are not equiped?

errant sundial
#

It's to prevent use on items that are like in a chest or on the ground

#

There's also ActionArgument.ItemNearby (accepts any nearby item as well, ie chests/ground) and ActionArgument.Item which is any item, even if it's halfway across the map (more useful for debug-type actions)

flint quarry
#

Thats a little confusing that its called inventory

errant sundial
#

Why?

#

It accepts any item that's in your inventory

flint quarry
#

just so I can use actions with it?

errant sundial
#

I'm confused

flint quarry
#

me too lol

errant sundial
#

We're saying that this action will require an item that's in your inventory in order to be called

#

Actual verification that the item passed in can collect blood will be in canUse

flint quarry
#

okay

#

That makes sense

#

sorry

errant sundial
#

No, no worries, I probably phrased something wrong

#

Miscommunications are common for this kind of thing, there's a lot going on

#

Do you want to add the action to glass bottles now or do you want to actually implement the action itself first?

#

If we add it to glass bottles first then you can see it appear in the right click menu in-game before starting to implement it

#

I think you might need to add return { usable: true }; to the end of the canUse handler for us to do that though

flint quarry
errant sundial
#

Looks good, will need the bit I said in my last message in the canUse for now though

flint quarry
#

what line?

#

idk where to put that

errant sundial
#

Just anywhere in the canUse

#

Between the {}

#

you know where all the comments are

flint quarry
#

Gotcha

#

It did work

errant sundial
#

Nice!

flint quarry
#

but the action is a string

errant sundial
#

?

flint quarry
#

Action:ModBloodRitesCollectBlood

errant sundial
#

Yeah, that's the internal name of the action

#

Where are you seeing that?

flint quarry
#

when I left click

#

the item

#

right

#

click

errant sundial
#

Oh does it show up on literally every item?

#

That's funny I didn't know it worked like that

flint quarry
#

No, just those two. Shouldnt it just say "collect blood"

#

or is that done in the lang

errant sundial
#

Wait why are you adding collect blood to containers that already have blood?

flint quarry
#

oh true

errant sundial
#

It's in an "action" dictionary
Action:ModBloodRitesCollectBlood is telling you Dictionary:TranslationName

flint quarry
#

do I just call the normal glass bottle and add the action to that?

errant sundial
#

I'm not sure what that means, probably not. There's something new you have to do for that

flint quarry
#

like how do I give a preexisting item an action

errant sundial
#

Yes I know what you want

flint quarry
#

inject into vanilla i guess

errant sundial
#

yeah I need to show you how to do it

#

give me a minute I'm getting you an example

flint quarry
#

ok

errant sundial
#

Okay I'm pretty sure you should have access to this, I just checked when it was added I think it was before we switched over to working on Runekeeper

#
// an "override" is for injecting into vanilla descriptions
@Register.override(() => ({
    // the "object" is the thing you're injecting into. 
    // you will be replacing a single property inside the object with a new value.
    // when your mod is disabled, it will automatically be un-injected and reset to the original value.
    object: itemDescriptions[ItemType.GlassBottle],
    // here we're injecting into "use", ie the list (array) of actions on the bottle
    property: "use",
    // here we say what value we want it to have. we're giving it a brand new array of actions
    value: [
        // this line *looks* complicated, but in actuality it's pretty simple.
        // all it's doing is including everything that was already in the vanilla glass bottle "use" array.
        // the ?? [] bit is just saying "if there wasn't a use array, make a new one." 
        // it basically just stops it from being like:
        // "aaaaa i just tried to put everything of <undefined> into this array, that doesn't make sense!!!!!"
        ...itemDescriptions[ItemType.GlassBottle].use ?? [],
        // now we add our action.
        Registry<BloodRites>().get("actionCollectBlood"),
    ],
}))
public readonly glassBottleDescription: IItemDescription;
flint quarry
#

Im trying to import IItemdescriptions but its not working

#

I tried using the directory from the guide you sent

errant sundial
#

When auto-import doesn't work, you'll have to look up the path on the wiki

flint quarry
#

how do I auto import

errant sundial
#

If that doesn't work try game/game/item/IItem

#

Sometimes when you type a name it'll suggest importing it

#

It'll be just one of the little suggestion popups as you type

#

It'll say "auto import from xyz" or whatever

#

Sometimes that doesn't work though

#

auto import looks something like this, though ignore these paths, they're runekeeper ones (we changed the way some stuff works)

flint quarry
#

The IItemdescriptions works it says its value is never read

errant sundial
#

Show me your code

#

And your error

flint quarry
#

how do I embed again?

errant sundial
#

Embed what?

#

Do you just want to post code?

flint quarry
#

code

errant sundial
#

```ts
// paste code here
```

flint quarry
#
import Mod from "mod/Mod";
import Register, {Registry} from "mod/ModRegistry";
import { EntityType } from "game/entity/IEntity";
import { Action } from "game/entity/action/Action";
import { ActionType, ActionArgument } from "game/entity/action/IAction"
import { IItemGroupDescription } from "game/item/IItem";
import { ItemType} from "game/item/IItem";

export default class BloodRites extends Mod {

    @Mod.instance<BloodRites>("Glassbottleofblood")
    public static readonly INSTANCE: BloodRites;

    @Register.item("Glassbottleofblood",{
    })
    public itemGlassbottleofblood: ItemType;

    @Register.item("Clayjugofblood",{
    })
    public itemClayjugofblood: ItemType;

    @Register.action("CollectBlood", new Action(ActionArgument.ItemInventory)
    .setUsableBy(EntityType.Human)
    .setCanUse((action, item) => {
      return { usable: true };
    })
    .setHandler((action, item) => {
    }))
  public readonly actionCollectBlood: ActionType;
  }

  @Register.override(() => ({
    object: itemDescriptions[ItemType.GlassBottle],
    property: "use",
    value: [ itemDescriptions[ItemType.GlassBottle].use ?? [],
    Registry<BloodRites>().get("actionCollectBlood"),
    ],
}))
public readonly glassBottleDescription: IItemDescription;
errant sundial
#
  1. You have not imported the name itemDescriptions
  2. You imported IItemGroupDescription instead of IItemDescription
#

game/item/ItemDescriptions

#

you also removed the ... here

#

you also put @Register.override outside of your Mod class

#

I think that's everything

flint quarry
#

looks like all the errors are gone

#

thanks

errant sundial
flint quarry
#

Yep it works! 🙂

errant sundial
#

Nice!!

#

Oh yeah you'll need an action icon too

flint quarry
#

can it be red or does it have to be wite like the rest?

#

white*

errant sundial
#

Up to you chirishrug

flint quarry
#

neat

errant sundial
#

I would recommend white for UX — the icons look how they do so that a player seeing an icon can quickly be like "oh that's an action icon. that's a skill icon" etc

#

But if you wanna do something different I can't and won't stop you chiritonguewink

#

If you want to know where to put the icon, look at the warnings or errors in the Developer Tools console

#

Should give you the path it's trying to load somewhere

#

something like static/image/ui/icon/action/something.png maybe?

flint quarry
#

Oh okay I see

#

then once I make the graphic it will auto add it

errant sundial
#

yep!

flint quarry
#

since its already looking

#

cool

#

Did you guys write all that into the engine?

errant sundial
#

Kinda yeah

#

The paths are all a single system

flint quarry
#

thats amazing to me lol

#

Whats the size for the image?

errant sundial
#

Actually displaying textures are a mixture of:

  • The game canvas (the terrain, trees, doodads, the player, creatures, the fog, etc), which was all written from scratch, mostly by Sassafrass afaik but with lots of stuff maintained/updated by Spacetech, and a tiny amount of stuff by me and Drathy
  • The iconography in the UI — all the UI, really — is all displayed like a webpage. It uses the same technologies. HTML, CSS, etc. So it's kinda just having a script put an element on the screen and pointing it to the path it thinks your resource will be at
flint quarry
#

quite smalll right? 8x8?

errant sundial
#

Action icons are 16x16

#

Like items

flint quarry
#

oh okay

#

it just scales it

errant sundial
#

if it helps here's all the base game action iconography

#

I think that's all the time I have to help for the day, I can help you with the collect blood action tmrw

#

Is this your first time doing any programming?

#

If so probably good to do it without being overwhelmed by all the other stuff we've already done

flint quarry
#

No not quite my first. I do stuff with godot mostly

errant sundial
#

Ah gotcha!

flint quarry
#

I'm trying to get better all the time lol

#

got the icon too 🙂

errant sundial
#

Nice!!

flint quarry
#

Thanks again for your help today. I should probably head to bed myself 🤣

errant sundial
#

No worries!

#

Feel free to ping me here if there's a good time tmrw, I can be available

flint quarry
#

I'd love to continue learning tomorrow. I will talk to you then 😄

errant sundial
#

My bedtime is in like 2 hours (11pm) so our availability seems to line up decently well

flint quarry
#

Oh yeah thats great. It's 5am for me; I regularly stay up late.

flint quarry
#

Hey Chiri, I've been working more by myself on trying to complete the recipe for the bottles of blood and I think I'm definitely getting somewhere but I had a question about one thing:

#

The "1, 1" at the end; what does that mean?

#

They seem like random parameters to me , does it correspond to a specific item type?

errant sundial
#

Hover over RecipeComponent or ctrl click on it and see what the second and third parameters are called

#

If you still don’t understand give me a ping

#

I may have fallen back to sleep tho so actually I’ll check regardless in like an hour maybe idk

flint quarry
#

I cant figure out how to put blood in the recipe, its not in the itemtypegroup or anything only liquid and liquid container. Why wouldn't all "Liquid" be under the same umbrella?

errant sundial
#

You’ll have to register a new item group for blood

#

If you want it to be classified as a liquid as well you’ll have to also add it to the liquid group

#

The code can’t just randomly guess what your item is, gotta categorise it chiritongue

#

to register an item group you’re looking for @Register.itemGroup

#

Should take a name for the group + a list of things in the group

#

Or you can add items to the group via the group property on the item description

#

Either works

#

Either way to reference the other thing you’ll have to use that Registry get syntax again

#

Like what you did to get the action type for use

#

You’ll already need the item description property group to add it to the liquid group so probably want to do it that way

flint quarry
#

Im still not understanding this is very frustrationg

#

frustrating*

errant sundial
#

You shouldn’t need any other parameters there

#

Ctrl click on itemGroup and send me a screenshot of it

#

Sorry i’m just still on mobile

flint quarry
#

It says name: string and description:

errant sundial
#

Just screenshot it

#

I’m going to walk you through understanding what it all means

flint quarry
#

the item group perameters?

errant sundial
#

Yeah

#

To hopefully make it easier for you to figure stuff like this out in the future

#

It’s okay it takes time to learn this stuff

flint quarry
errant sundial
#

Okay, so you need a name, which you have, which is a string. You also need an IItemGroupDescription. We need to figure out what that means now. Ctrl click on that

#

Can you screenshot it and send it to me? And we’ll figure out what you need from that

flint quarry
#

sure

#

Does blood have to be added too this list?

errant sundial
#

I’m not sure yet

flint quarry
#

oh

errant sundial
#

I haven’t messed with groups in a long time and usually am looking stuff up while helping and i’m on mobile atm

#

I don’t mind helping I just need screenshots of types

#

And I’ll walk you through my thought process

flint quarry
errant sundial
#

Okay perfect

#

So a couple things

#

see how this says it’s an interface?

#

An interface describes an “object”

#

Basically a generic container of any number of properties

#

The item description is also an object

#

The thing we return in the Register.override is also an object

#

It’s specifically the stuff that looks like this
{
property: value,
other property: other value,
}

#

In your code

#

So our goal is to, for the second parameter in itemGroup, make an object that matches what IItemGroupDescription is saying

#

Let’s look at the properties in it

#

See how the first one, default, has : but the other two have ?: ?

#

That means the first one is required for an object to match, but the other two are optional

#

So all we need to do is make an object that has a default property in it

errant sundial
#

It’s the entire thing I sent you there

#

That itself is an object

#

{} is an empty object

flint quarry
#

right

errant sundial
#

So what you want here is
{ default: <we need an item type to put here> }

#

So to explain what that is

#

You know how some recipes use item groups as ingredients?

#

And you know how crafted items can be disassembled to get back the components that crafted it?

#

If a player receives a naturally created item that is something that can be crafted from item groups, then disassembles it, each item group ingredient of the recipe gives its default item

#

So like say a creature drops, or a merchant sells, something that you can craft with an item group. And then you disassemble it. And it gives you the default items that make it up

#

So every group in the game as a result is required to have a default item

flint quarry
#

oh alright

errant sundial
#

Basically in your case you just need to choose one of your containers of blood to return

#

Once you’ve decided, you’re looking for that Registry get syntax

#

The same way we added your custom action to the use array

flint quarry
#

I'll start with the glass first

#

so

#

I'll want it to return to being a glass bottle right?

#

well

errant sundial
#

Register.itemGroup(“Blood”, { default: Registry whatever blah blah (“itemGlassBottle”) })
I can never remember the syntax lol

#

Don’t copy that it has smart quotes

flint quarry
#

lol

errant sundial
#

If you crafted something with a different item in a group it’ll return the same item when its disassembled

#

It’s only when its a natural item that it returns defaults

#

So you just choose whatever for the default

flint quarry
errant sundial
#

Would probably have an easier time just copying the existing example we have for that one chirisweat

#

Registry<BloodRites>().get("itemGlassBottleOfBlood")

#

or whatever

#

(I just moved to pc)

flint quarry
#

sweet

#

what is whatever

#

thats too nuanced I dont understand that sorry lol

errant sundial
#

that is me not knowing the syntax

flint quarry
#

oh

errant sundial
#

I looked it up when I got back to pc

#

and i sent it to you

flint quarry
errant sundial
#

you had it right here

#

you're also missing the { default:

flint quarry
#

When I add that theres another issue... ugh

errant sundial
#

Because remember the itemGroup definition said it was looking for the parameters name: string, description: IItemGroupDescription. There's no such thing as labelling parameters when you're calling a function, so you just need to do itemGroup(string, IItemDescription)
ie, itemGroup("Blood", { default: Registry<BloodRites>().get("itemGlassBottleOfBlood") })

#

Show me the issue

flint quarry
errant sundial
#

Do you have the field after it?

#

public itemGroupBlood: ItemTypeGroup;

#

?

#

Because every time you use a @Register decorator like this, you need to be giving it a field to inject the registration into

flint quarry
errant sundial
#

I gave you the wrong item name

#

What's the right one?

#

I just guessed

flint quarry
#

This is horrible ive been doing this all day with nothing to show for it 🤪 🤪 🤪

errant sundial
#

Look for your glass bottle field

flint quarry
#

These three lines

#

why does it have to be so complicated

errant sundial
#

The field is only the line that starts with public

#

It's not complicated it's just stuff you're not familiar with

#

That's normal when you're learning something new

#

If you start typing a string in the .get() it'll also give you a suggestion for the right field name

#

I have a feeling you're just getting lost though because the stuff hasn't really been sticking

#

Feeling like syntax soup or whatever

flint quarry
#

oh...

#

the puctuation...

#

punctuation*

#

right..

errant sundial
#

looks like last time you sent me the code it was "itemGlassbottleofblood", you didn't capitalise every word like I'm used to

flint quarry
#

Yeah

#

I just saw that lol

#

its fixed now

errant sundial
#

Nice!!

#

Now we just need to add your two containers to the group

#

Once we do it for one we can just copy it to the other

#

One of the fields listed at the top is group

#

So inside the item description — remember the description is the object {} inside the @Register.item decorator call

#

We need to add a group property

#

It will be a list of all the groups we want the item to be in

flint quarry
#

in this case the glass bottle right?

#

with blood

errant sundial
#
@Register.item("Glassbottleofblood", {
  group: [
    // we can put base game groups here
    // or reference groups that we've registered with the same Registry().get syntax
  ],
})
public itemGlassbottleofblood: ItemType;
#

So you can just directly list Registry<BloodRites>().get("itemGroupBlood") inside that group list/array.
This is saying "when my itemGroupBlood is registered, put its ID here"

#

Other groups you might want to add:

ItemTypeGroup.ContainerWithLiquid, 
ItemTypeGroup.FireExtinguisher, 
ItemTypeGroup.Liquid,
flint quarry
#

what does countainer with liquid do

errant sundial
#

lemme check

#

Actually you can skip that one

#

It's only used in consume item checks

#

So unless you're also adding vampirism probably not necessary

flint quarry
#

alright so thats done

#

but how does it know what blood is

errant sundial
#

Not sure what you're asking exactly

flint quarry
#

if I face blood on the ground

#

How does the game know that the blood I just added is there to gather

errant sundial
#

Oh, for your collect blood action? We still have to finish that

flint quarry
#

oh

errant sundial
#

We need to add a canUse handler that will return that the action is usable if you're facing blood, and that it's not if you're not facing blood (with a message saying that you're not facing blood)

flint quarry
#

I keep getting ahead of myself my bad haha

errant sundial
#

There are a lot of moving parts in the mod you want to make

#

So yeah it's going to be a very steep learning curve

#

It'll be okay though it's trial by fire and then once you pass it should be a bit easier

#

You'll have your own code as an example, then

flint quarry
#

nods

errant sundial
#

Okay so as a reminder this is what I sent yesterday, sending it again because I think you took out all the comments

#
@Register.action("CollectBlood", new Action(ActionArgument.ItemInventory)
  .setUsableBy(EntityType.Human)
  .setCanUse((action, item) => {
    // this handler will be for returning whether the action is usable right now.
    // ie, if the player is actually facing blood.

    // in multiplayer, this code happens in all of the following situations:
    // - when the player is hovering the mouse over the action,
    //   so that the action can display the red text if you can't use it
    // - when the player clicks on it when it's assigned to an action slot.
    //   if it's not usable in this situation, the client doesn't even send the attempt to the server.
    // - when you actually use the action, it calls this on both the clients and the host/server,
    //   as one final check to make sure this is legal.
  })
  .setHandler((action, item) => {
    // this is called when the player actually attempts to collect the blood.
    // in multiplayer, to keep the clients and the host/server in sync, this code happens for both.
  }))
public readonly actionCollectBlood: ActionType;
#

So right now we're working on the first one, this bit

flint quarry
#

I saved a reference

#

I just cut it from the actual file to save my eyes a bit lol

errant sundial
#

The typical way a canUse handler is written is:

  • A series of checks, seeing each one finding a reason why it's not possible to do the action
    • When it's not possible, exiting from the canUse handler by returning the message why it's not usable
  • Finally, when all checks have passed, that means that it is usable, so we then return that it is usable
    • Along with this, we also return custom data that our action needs to operate. In this case, since multiple puddles of blood can be on the same tile, we should return the specific puddle of blood that the action will collect
#

We're going to start a bit slow by just assigning some variables

#
const player = action.executor;
#

The entity that executed an action is always put inside action.executor, so just for convenience we'll put them in a variable

#
const tile = player.facingTile;
#

The tile we're interacting with is the tile the player is facing, so we'll save a reference to that

flint quarry
#

Does it matter where I put these constants or does everything just compile as it is?

errant sundial
#

Put them in order in the canUse handler

flint quarry
#

oh okay I see

errant sundial
#

There shouldn't be any red squiggles, just a yellow squiggle under tile because it's not used yet

#

Now that we have those variables, in order to get the list of "Tile Events" on the tile, we access tile.events
In your case though, you specifically want a tile event that is TileEventType.Blood, so we're going to have to filter down the events into ones of the correct type

#

Don't put this in your code yet

const bloodTileEvents = tile.events
  .filter(event => event.type === TileEventType.Blood);
#

This is saying:

  • Given the list of all the events on the tile
  • Filter down that list into just the ones that satisfy the given function
    • The function we give it only returns true (ie, that it should keep the event) when event.type is TileEventType.Blood
#

Does that make sense so far?

flint quarry
#

Yes the function oly returns true when the specified tile event type is correct

#

only*

errant sundial
#

Yep

#

Okay so now that we have a list of tile events that are blood, we just need to get the first one. And that's the one we'll be using for collecting. This code can go in your canUse handler

const blood = tile.events
  .filter(event => event.type === TileEventType.Blood)
  .first(); // use the first from the list of blood tile events, or `undefined` if there's no blood
#

So now we have something that we can actually check — this blood variable will either be a blood Tile Event, or it will be undefined if there wasn't any blood

#

In the case of undefined, we'll need to exit out of the can use handler with a message for the player saying there's no blood

#
if (blood === undefined) {
  return {
    usable: false,
    // our message will go here. 
    // unfortunately first we have to register it, and then do something new to access it.
    // for now, we'll use a placeholder message:
    message: Message.NothingHereToFill,
  };
}
#

Once you've put that in your can use handler, can you show me what it looks like so I can verify it's correct?

flint quarry
#

Tile event isnt defined

#

imported

errant sundial
#

it's this second one my cursor is over

flint quarry
#

I got that one

#

"Tile.events is possibly undefined"

errant sundial
#

I think I might be misunderstanding what your error is. I'll have an easier time understanding it if you show me the error rather than rephrasing it

#

Ahhhh

#

Okay in that case make the .filter line start with ?

#

?.filter(

flint quarry
#

Yep worked

#

whats that mean

errant sundial
#

That means "if the previous thing was undefined don't do the rest of this line and make the entire expression undefined instead"

#

Which makes sense — if there's no events, it should be undefined anyway since that's what we're checking for

flint quarry
#

mm

#

now only blood needs defining

#

er

#

oh no we just havnt used it

errant sundial
flint quarry
#

should it be on message

errant sundial
#

I'm not sure what that means

#

If you send me what your code looks like right now I can show you where to put it

#

Everything I've sent you should go in order though

#

should be

// initial variables

// getting the blood tile event, or undefined if there isn't one

// returning that the action can't be used if blood is undefined

// returning that the action can be used
flint quarry
errant sundial
#

okay 2 things

  1. you still need to import Message
  2. you have the order wrong. you have:
// returning that the action can be used (this needs to be last)

// initial variables

// getting the blood tile event, or undefined if there isn't one

// returning that the action can't be used if blood is undefined

Wince you're returning that the action can be used at the top, the game will never run the rest of the code, it will always be like "yep seems good!" If you saved the file right now, typescript might even automatically remove the rest of the code because it never gets used lmfao

flint quarry
#

uh oh lol

#

its in the exact order you sent it lol

#

player tile bloodtileevent

errant sundial
#

okay TBF! i wasn't referring to what i sent last night when i said that chiritongue

#

wait do you still not understand what's in the wrong spot?

#

it's the return { usable: true }; at the start

#

that should be at the end

flint quarry
#

Im so confused

errant sundial
#
.setCanUse((action, item) => {
    const player = action.executor;
    const tile = player.facingTile;

    const blood = tile.events
        ?.filter(event => event.type === TileEventType.Blood)
        .first();

    if (blood === undefined) {
        return {
            usable: false,
            message: Message.NothingHereToFill,
        };
    }

    return { usable: true };
})
flint quarry
#

Alright

#

Thanks lol

#

mine wasnt even lined up right somehow

errant sundial
#

no worries chiritongue

#

I will say, with a mod with as much going on as yours having a bit more programming experience would probably help

#

I'll help you get it done and hopefully you are picking some things up

#

But I have a feeling you're going to get stuck on things like this quite a few times chiriaaaaaaaa

flint quarry
#

What can I use to practice?

errant sundial
#

Any scripting language, really

#

Any language that requires using an IDE like vscode

flint quarry
#

I think its just the difference of syntax

#

I mostly use gdscript

errant sundial
#

gotcha

#

gdscript does look somewhat similar. much less {} and () though

flint quarry
#

Which definitely looks similar to typescript

errant sundial
#

Looks cool honestly

flint quarry
#

I like it, I have another side project going on that haha

errant sundial
#

I think the biggest difference in Typescript is the ordering of things and the fact that there's a lot more instances of putting things inside things

#

Like for example classes in gdscript looks like a per-file thing?

#

whereas in ts you can have as many in a file as you like, they're all inside {}

flint quarry
#

While Im doing this theres nothing visually that tells me x and y aside from you, we're not using a game engine I think is the main difference

#

This is like homebrew lol

errant sundial
#

Not sure what you mean

flint quarry
#

Its kinda hard to explain

errant sundial
#

If you hover over things it should be giving you tons of info about what's there

#

And if you ctrl click on things you can look at the inner definitions

flint quarry
#

in godot for example

#

I can drag an image into the engine into a sprite node, give it a collisionshape (or not) and its in

#

adding stuff visually is very simple

errant sundial
#

oh, yeah

#

well that i knew chiritongue

#

i thought we were more talking about the gdscript part though?

flint quarry
#

In Gdscript the entire doc is included as a sidebar with a hotkey

#

You still have to script regularly though, yeah

#

whatever functions you wanna add

errant sundial
#

How often are you making like actual functions and classes in gdscript? or are you just doing things like visually clicking on a dropdown and saying "call this gdscript function when this happens" and it automatically calls one very small isolated block of code that you've written

#

this looks very familiar to me, and it's stuff i can get behind, esp. the fact that it simplifies class syntax down into what just looks like a normal script context

#

you just know that it's a class because it's a single file representing the class

#

i'm wondering whether there's cases where you just kinda define a function visually in godot and so all you have is like this, but maybe even simpler than this since this is showcasing a bunch of possible syntax

#

anyway.

#

fwiw we do want to do things like json modding and a visual editor eventually

#

it's just that that will take a lot of development time
and it's development time specifically centred on me (since i'm the ui developer) and i am generally swamped

flint quarry
#

Sorry I was trying to set something up to show you my project lol

#

aw it didnt play his animations

#

obs didnt record the debug window lol

#

There we go

flint quarry
#

It'll come when and if it comes

#

Until then I don't mind learning, maybe you could give me a bit of an easier mod idea to do as a challenge. The feeling that comes along with code working is unmatched

errant sundial
#

At this point you're pretty close to having something that works

flint quarry
#

As difficult as some of the concepts can be for me to grasp I think its fun

errant sundial
#

You might as well finish this

flint quarry
#

I wish there was a way to just force myself to understand lol

errant sundial
#

I think if you want a good thing to learn, just adding variants on existing items or tweaking numbers on existing items are going to be your best options for getting really familiar with the way registering new stuff and referencing new stuff works

#

Basically, mods that primarily use @Register.item and @Register.override and that's it

flint quarry
#

Just getting familiar with writing those over and over and tweaking them?

errant sundial
#

Pretty much yeah

#

The more you do it the more you'll run into weird typos and things you need to import and weird errors and stuff, and the more you'll understand how to get yourself out of weird states and errors you don't understand

#

You have to fail repeatedly doing the simplest level of things for your mind to really wrap around it completely

#

And unfortunately the simplest level of thing in wayward is not the easiest

flint quarry
#

How long did it take you to fully understand? I feel like you could really teach this stuff lol

errant sundial
#

I started learning programming at like 10 years old and I'm 27. I started working in C# and Java around 17, and JS & TS at like 18-19. I joined the Wayward team at 20 or 21 I think. I set up the current modding system about 4-5 years ago, when I was 22-23

flint quarry
#

oh okay you're around my age. Im 25

errant sundial
#

It does tend to be harder to learn this stuff the older you start — mostly just because it's harder to get the sheer number of hours to catch up, and it starts to feel impossible to invest as much time as you need into it to not be behind anymore — but in actuality, everyone can do it

#

It's the same as any skill

flint quarry
#

Yeah, I didnt start at 10 unfortunately, it's been an off and on thing for me since like 14 but I really enjoy it

#

I've done so many little unfinished things with so many languages

#

But sometimes I feel like I still have the most basic understanding

errant sundial
#

There are lots of people who think "coding is magic I can never do it" but yet they don't think the same about other languages, like spoken ones. And they also don't think it about other kinds of problem solving, like sudoku and crosswords and puzzle games with fresh new kinds of mechanics. You just have to be ready to be stuck on a problem for a long time, making sure you're really learning and understanding why something didn't work each time you mess something up. And you have to be committed to it long-term, too. Committed to being okay with messing up repeatedly and learning from those mistakes so that you can really wrap your head around it.
I've been giving the answers to most of the stuff you've run into, which does make it harder for things to stick, but at the very least it should make it a bit easier for you to be like "wait I've run into this exact problem before" and then figure it out your own way next time

flint quarry
#

Yeah, I should be able to at least look back on it as a reference

#

"When this happened it needed to be imported" etc

errant sundial
#

Yep

#

Whenever you're using something that starts with a capital letter, that you didn't make, you need to import it

#

There are very few things that you'll need that don't start with capital letters

#

The only examples I can think of are the descriptions like itemDescriptions

flint quarry
#

mhm

errant sundial
#

Okay anyway

#

Did you update your .canUse handler to the one I gave you?

#

If you test that in-game it should now only allow you to use the action when you're facing blood

flint quarry
#

Yes

#

let me see

#

Zero errors, running wayward...

#

ey!

#

it does work

#

high-five

#

lol

errant sundial
#

Nice!!

#

Now all that's left is the action handler

#

We need to make it actually turn your container into one of blood

#

And also remove the blood tile event

flint quarry
#

right so it disappears

errant sundial
#

Yep

#

We will need to do one other thing first

flint quarry
#

I felt that coming

#

XD

errant sundial
#

So the other thing canUse handlers do, to prevent you needing to do the same checks or find the same things multiple times, is they can give stuff to the handler itself

#

In this case we want to give the blood tile event from the canUse handler to the main handler

#

In order to do that we need to tell .setCanUse that the resulting usable: true object will also come along with blood: TileEvent

#

To do that, we're going to make our own interface

#
interface ICollectBloodCanUse extends IActionUsable {
    blood: TileEvent;
}
#

This needs to be above your class

#

Between it and your imports

#

You will need to import both IActionUsable and TileEvent probably

#

If they don't auto import try searching for them with the magnifying glass on the docs website I linked previously

flint quarry
#

ok

#

got it

errant sundial
#

IActionUsable looks easy to find. TileEvent is a bit harder, so I'll give you that one — I had to try adding a slash in the front to find it, since there's a bunch of other files that have a tileEvent in them it shows those first for some reason.

flint quarry
#

It let me auto import

errant sundial
#

Oh nice

flint quarry
#

yee

errant sundial
#

Okay in that case

#

If you ctrl + click on IActionUsable you can see what's defined inside it

#

That's what .setCanUse expects by default for the action being usable

#

Our interface extends'ing it means that it's a combination of all of the potential properties in IActionUsable, plus any properties that we define

flint quarry
#

interface and namespace?

errant sundial
#

It should have the properties usable, usableOnMove, and displayLevel inside of it

flint quarry
#

yes

#

is see those

errant sundial
#

Okay cool

#

So now that we have that interface we have to tell .setCanUse to expect that interface as the output instead of just the normal IActionUsable

#

The initial line should now be

.setCanUse<ICollectBloodCanUse>((action, item) => {
#

It should make it get REALLY angry

#

Because you're not returning a blood: TileEvent along with usable: true yet

#

Lastly, we change the last line of the can use handler to return { usable: true, blood };

flint quarry
#

put that after the blood. tileevent?

#

.setCanUse<ICollectBloodCanUse>((action, item) => {

errant sundial
#

replace the existing .setCanUse line

#

<ICollectBloodCanUse> is just being added to it

#

that's all

#

It's something called a "type parameter"

flint quarry
#

oh i see now

#

got that

errant sundial
#

that will make it not error at the top anymore

flint quarry
#

changing the last line of the can use handler greyed out the code under it

errant sundial
#

I'm sorry I need to see the actual code to know what these are referring to

flint quarry
#

sure

errant sundial
#

I straight up never use the problems panel personally

#

The lack of context makes it too hard to use imo

flint quarry
errant sundial
#

lol why did you put that return inside the interface

#

it's for the canuse handler

#

the interface is just for describing what an object looks like

#

return means nothing in that context

#

return is for functions

#

.setCanUse is being given a function

#

that is the can use handler

#

We told .setCanUse what the object we're returning is going to look like

#

Now we need to actually return an object that looks like that

flint quarry
#

Aha

errant sundial
#

That return statement I gave you is to replace return { usable: true };

flint quarry
#

got it

errant sundial
#

Nice chiritongue

flint quarry
#

:p

errant sundial
#

Okay so

flint quarry
#

Im a little slow Hah

errant sundial
#

Nw

#

After all of that now your main handler will have access to that same blood tile event

#

It will be available in action.use.blood

#
const blood = action.use.blood;
#

For now, let's just remove the blood because it's simpler

#

Don't use any of the following code, it's examples again
This grabs the current island that this blood is on. It's basically like a "world" if that makes sense

const island = blood.island;

This gets the full list of tile events:

const tileEvents = island.tileEvents;

This removes the given tile event from the island:

tileEvents.remove(blood);

To simplify this line, we can instead do

blood.island.tileEvents.remove(blood);
#

So your entire main handler atm should be:

const blood = action.use.blood;
blood.island.tileEvents.remove(blood);
#

Also, I have no idea why you can't just do blood.remove(), I guess we just never added support for that for some reason

#

Would be much less confusing lol

flint quarry
#

instead of just having tile events

errant sundial
#

Because it's all on one line instead of storing a bunch of variables that only get used once

#

If you think it's more understandable to save every variable you can

flint quarry
#

oh so if I didnt do that they'd have to be included seperately?

errant sundial
#

it's either

const blood = action.use.blood;
blood.island.tileEvents.remove(blood);

or

const blood = action.use.blood;
const island = blood.island;
const tileEvents = island.tileEvents;
tileEvents.remove(blood);
#

Up to you which you prefer

#

When you have that in your main handler give it a test and it should remove blood tile events

#

It won't be turning the glass bottle into one of blood yet, of course, we still have to implement that

flint quarry
#

do I change the already existing blood constant?

errant sundial
#

the main handler, not the can use handler

#
.setCanUse(() => {
 // you already did this
})
.setHandler(() => {
 // put new stuff here
})
flint quarry
errant sundial
#

oh that's weird

#

Oh

#

We changed the way that part works in runekeeper my bad

#
const canUse = action.canUse();
if (!canUse.usable) {
  return;
}

const blood = canUse.blood;
blood.island.tileEvents.remove(blood);
#

See you can tell we're still trying to simplify this stuff chiriaaaaaaaa

#

It's a slow process

flint quarry
#

Definitely takes time

#

Yep it works

errant sundial
#

Nice!!

flint quarry
#

it only disappears after the next turn though

#

for some reason

errant sundial
#

Oh that's just visual

#

add action.setUpdateView();

flint quarry
#

Usually stuff vanishes right away, no?

errant sundial
#

After removing

flint quarry
#

oh

errant sundial
#

Also should probably add action.setPassTurn()

#

The vanilla GatherLiquid action also does action.setDelay(Delay.LongPause);

flint quarry
#

set pass turn? does that just tell it to pass a tick?

errant sundial
#

yeah

flint quarry
#

ok

#

semicolon after, right?

errant sundial
#

yeah

#

it's not technically necessary but i'd recommend it

#

you can run into some weird bugs by missing semicolons sometimes

flint quarry
#

right

#

both of those work too

#

🙂

errant sundial
#

So all that's left now is converting the item into your blood variant

#

For now let's just make this action always turn the item into the glass bottle of blood

#

After that works we'll add support for respecting the input container type

flint quarry
#

Yeah I didnt do anything for clay yet

#

I figured I'd finish the second one on my own once we're finished

#

try to use what I've learned

errant sundial
#

They'll be using the same action so I need to help a bit with it

flint quarry
#

oh

#

ok

errant sundial
#

You'll be able to copy the glass bottle description and override stuff though for other container types

#

Okay so we unfortunately have to do one new thing

#

As usual lmfao

flint quarry
#

haha

errant sundial
#

So technically, that action? That's actually not inside of your Mod class

#

It looks like it is, but technically it's not

#

So it doesn't actually have access to the stuff that you've registered

#

And that Registry().get() thing doesnt work here, either, unfortunately — the way that works is it's secretly a placeholder value that gets turned into the real value on mod initialisation. So using that placeholder value somewhere else makes no sense because other places in the game don't know how to turn the placeholder value into the real ID

#

So instead, we need to set up a new way for this action to get access to your Mod's "instance"

#

So far you've been registering a whole bunch of new things and their IDs have been getting injected into properties on your mod instance. That's why we need the instance, it allows you to get at all those IDs

#

Argus actually does this I think

#

Yeah it does

#

It's the @Mod.instance thing

#
@Mod.instance<BloodRites>()
public static readonly INSTANCE: BloodRites;
#

Should work to do this

#

We'll find out later

#

Once you've got that lemme know

#

Should just be anywhere inside your class

#

Alongside all your other @Register.whatever stuff

flint quarry
#

Yep got it

errant sundial
#

Nice!

#

Okay

#

So now it's easy

flint quarry
errant sundial
#
item.changeInto(BloodRites.INSTANCE.itemGlassbottleofblood);
flint quarry
#

Yes!

#

epic!

errant sundial
#

At this point I'd recommend trying to work out what properties your item description needs, and then once you're done with that start copying stuff over to clay jugs and coconut containers and stuff

#

waterskins

#

wait no wrong version sec

flint quarry
#

properties like weight, skill, etc?

errant sundial
#

If you wanna see how any item does anything, most of it is in this file

#

this is every item description in the game

flint quarry
#

Oh sweet thanks so much

errant sundial
#

I'd recommend looking at the various liquid filled containers to see what properties they have

flint quarry
#

You're truly a LEGENDLegend

errant sundial
#

I'm seeing inheritWeight, durability, returnOnUseAndDecay, keepDurabilityOnCraft, repairable, use, onUse, worth, tier (this is for using it as a liquid in a recipe), noCraftingQualityBonus, createOnBreak as properties you should care about

#

might be some others

#

If you get stuck on any or want more details about how they work lemme know

flint quarry
#

Thanks so much, Chiri!

errant sundial
#

no worries!

#

one last tip btw, maybe make a backup every time you get something major working, in case you get stuck and typescript gets super angry at you again

flint quarry
#

good idea

signal folio
#

(switched to work account (they look the same) if you get really stuck you can ping me on this one, but otherwise I won't see unreads till later)

#

good luck!

flint quarry
#

How is this set up for different items using the same action?

errant sundial
#

We just need something new that returns a different container of blood based on input container

#

I’ll help you with it later

#

Just woke up the first time a few mins ago

flint quarry
#

Yeah no worries take your time😁

signal folio
#

Okay I can take a bit of time to help now

flint quarry
#

Ok

signal folio
#

wait why did you rename the blood tile event in your canuse to Bloodbottle lol

flint quarry
#

Probably changed the wrong thing

signal folio
#

You shoiuld change that back to blood so it makes a bit more sense

#

Okay continuing to type guide now

flint quarry
#

I have the backup you told me to make I was just tinkering ng with it trying to figure out what I should do

signal folio
#

So normally I would say the the cleanest way to know how to convert between multiple data types is to set up some kind of record/map somewhere. The idea would be you set up a record where, given an item type, it would return the "blood" item type.
In your case, however, you can't do that, because your blood containers are dynamic/registered IDs. So we have to do something a little different.

My recommendation is to make a new method in your class, with a switch statement, that returns a different registered blood container ID for each raw container item type it's given.

public getBloodContainerType(rawContainerType: ItemType) {
  switch (rawContainerType) {
    case ItemType.GlassBottle: return this.itemGlassbottleofblood;
    case ItemType.ClayJug: return this.itemClayjugofblood;

    // if no other container types are applicable, return undefined:
    default: return undefined;
  }
}

This method would then be used in your can use handler, and if the raw container can't be converted into a valid blood container type (ie, the method returns undefined), then it would say it's not usable.

const bloodContainerType = BloodRites.INSTANCE.getBloodContainerType(item.type);
if (bloodContainerType === undefined) {
  // not providing a message I believe means it won't display this action at all in the UI for invalid containers
  return { usable: false }; 
}

And then in your ICollectBloodCanUse, add bloodContainerType: ItemType;

interface ICollectBloodCanUse {
  blood: TileEvent;
  bloodContainerType: ItemType;
}

And then at the end of your can use handler:

return { usable: true, blood, bloodContainerType };

And then in your main handler:

item.changeInto(canUse.bloodContainerType);
flint quarry
#

That should be everything right?

signal folio
#

yep

#

If you can figure out where to put all that stuff it should work

#

The last few things are replacing the previous code you had, mind

#

Look for the lines that are doing similar things and see how they were updated

flint quarry
#

Awesome

#

I'll get to work on that, thanks. After all new items can just be added to the method right?

signal folio
#

yep, that getBloodContainerType method can be extended forever

#

After this stuff you shouldn't need to touch the collect blood action itself again

flint quarry
#

Sweet

#

Thanks

flint quarry
errant sundial
#

I say where each part goes directly above the code in question

#

A method just goes anywhere in your class

#

So not in something else, just in the class

#

Same place you'd put a new registration

#

For the rest of it, just look at where I say to put it

#

Try to understand what I'm telling you, and what the code is doing

#

It's less a "here's all the code you need, figure out where to put it" and more, I have explained all of this and what it's for, so you should be somewhat understanding what each piece is for already and understand why you're putting it in each place

#

If you don't understand one of the things I said in particular, ask me about that

flint quarry
#

idk you called two things handlers and theres only one thing named "handler", and its not being explained in the context of the code; anyone whos pretty new would be confused.

signal folio
#

I understand you getting a little confused sometimes, I have a lot more random knowledge than you, I just need to know which parts are confusing so that I can help better than telling you exactly what to do

#

As far as handlers are concerned, I have mentioned this previously, every time I've talked about the code block inside .setCanUse, I've called it the "can use handler"

#

And I've always called the other one the "main handler"

#

A handler is just a name for a generic function that gets passed to something to handle a specific situation, idk, it's just a programming term

flint quarry
#

so this constant

#

const bloodContainerType = BloodRites.INSTANCE.getBloodContainerType(item.type);
if (bloodContainerType === undefined) {
// not providing a message I believe means it won't display this action at all in the UI for invalid containers
return { usable: false };
}

#

would go below the blood one

signal folio
#

yep! or above it. Doesn't matter too much which

flint quarry
#

oh alright I wasnt sure if the placement mattered

#

load order or whatever

signal folio
#

It's doing the same kind of thing as the blood one, it's just doing another check to verify that the action makes sense in this situation

#

I think personally I would put it above the blood one? But it really doesn't matter. I think it's my personal taste that tells me to put it above lol

flint quarry
#

This now throws an error again

#

becauseblood container type is declared

signal folio
#

I'm going to need a bit more context to know what the problem is :p

flint quarry
#

Argument of type '(action: IActionHandlerApi<Human<number>, IActionUsable>, item: Item) => { usable: false; message?: undefined; blood?: undefined; } | { ...; } | { ...; }' is not assignable to parameter of type '(actionApi: IActionHandlerApi<Human<number>, IActionUsable>, args_0: Item) => IActionNotUsable | ICollectBloodCanUse'.
Type '{ usable: false; message?: undefined; blood?: undefined; } | { usable: false; message: Message.NothingHereToFill; blood?: undefined; } | { usable: true; blood: TileEvent; message?: undefined; }' is not assignable to type 'IActionNotUsable | ICollectBloodCanUse'.
Type '{ usable: true; blood: TileEvent; message?: undefined; }' is not assignable to type 'IActionNotUsable | ICollectBloodCanUse'.
Property 'bloodContainerType' is missing in type '{ usable: true; blood: TileEvent; message?: undefined; }' but required in type 'ICollectBloodCanUse'.

signal folio
#

That last line is the part that matters

#

So it's saying bloodContainerType is required in ICollectBloodCanUse

#

Because you added that like I said

#

So now you have to include that in the result when it is usable

#

So after the checks you have the main result object right?

#

the { usable: true, blood } I think

flint quarry
#

yes

#

oh haha

signal folio
#

yep!

#

nice work

flint quarry
#

Thanks. Sorry if im frustrating to teach lol

signal folio
#

No worries, I just wanted to make sure you were actually learning rather than me just only giving you the answers haha

flint quarry
#

I feel like I am retaining things. It'll just take more time and practice

signal folio
#

It's really annoying but fwiw it is consistent

flint quarry
#

Thats good to know

flint quarry
#

The clay jug still wont pick up blood for some reason

#

is it something with the itemgroup?

errant sundial
#

did you inject the action into clay jug's use using another @Register.override?

flint quarry
#

Like this, right?

errant sundial
#

yep that looks good

flint quarry
#

hmm..

#

let me try building cause I did have to change a thing

#

hmm

#

it turned the clay jug to a glass bottle lol

#

with blood

errant sundial
#

Can I see your whole file?

flint quarry
#

yeah

errant sundial
#

lol you could have just sent the single file...

flint quarry
#

oh sorry

errant sundial
#

you never updated the changeInto line

flint quarry
#

I thought you meant the whole thing

flint quarry
#

the itemchangeinto line?

errant sundial
#

yeah

flint quarry
#

It works now

#

sweet

errant sundial
#

nice!!

flint quarry
#

Im trying to reverse engineer the previous things we did to now make the player pour the blood back onto the ground

#

create(type: TileEventType, tile: Tile): TileEvent | undefined;

#

I see this is a thing you can do. could you explain these perameters more?

errant sundial
#

the type is the type of tile event. if you ctrl click on it and then ctrl click on TileEventType you can see the full list. tile is the position in the world that you create the tile event on

#

TileEventType is also something called an "enum", in case you've never used those in gdscript. It's basically like a list of possible values. In typescript you use one of them with EnumName.ThingInEnum, IE, TileEventType.Blood

#

Previously we've checked if an existing tile event type is TileEventType.Blood

flint quarry
#

so the tile is island?

errant sundial
#

no it's a tile

#

i'm confused

#

you stand on a tile

#

a tree is on a tile

flint quarry
#

maybe this isnt even correct

#

I probably cant do this

errant sundial
#

What is blood in this situation?

#

I don't have much context

#

Are you making like a pour blood action?

#

so you have an item which is, like, for example, a glass bottle of blood?

flint quarry
#

so I registered a new action

errant sundial
#

okay gotcha

flint quarry
#

am I on the right track?

errant sundial
#

Somewhat

#

I'm going to try to guide you to the answers this time instead of giving them to you

flint quarry
#

nods

errant sundial
#

So let's first think about blood in particular. If you hover it, what does it say it is?

flint quarry
#

blood is a tileEvent

errant sundial
#

Yep

#

Okay

#

So do you know what a tile event is

flint quarry
#

anything that has to do with occupying a tile?

errant sundial
#

Hmm, kinda?

#

I would define it something like a temporary "thing" going on on a tile

#

All puddles are tile events

#

Fire is a tile event

#

The fact that a meltable tile (ie, snow) is near a fire source puts an invisible "melting" tile event on the tile

flint quarry
#

oh ok

errant sundial
#

So when you're doing this action, you're trying to make a blood tile event, right?

#

Because the player is pouring it out?

flint quarry
#

right

errant sundial
#

And you're trying to make that tile event on the same island as the island of.... a blood tile event?

flint quarry
#

sorry?

#

What I have now you mean?

errant sundial
#

When the player is trying to pour out blood, you are currently doing "okay, let's use the blood tile event in front of them. yeah let's get its island. now let's make a blood tile event"

flint quarry
#

ok

errant sundial
#

I have no idea if that means you understand

flint quarry
#

yeah the part that I have now

#

the blood.island.tilevents

errant sundial
#

yeah

#

So which blood tile event is blood

flint quarry
#

it removes the blood

errant sundial
#

I'm not sure what you mean

#

Your goal here is pour blood

#

You're trying to make the blood appear on the ground

#

That is a blood tile event

flint quarry
#

this is what it refers to right?

errant sundial
#

Yeah. Does it make sense that you're looking for a blood tile event in front of you in order to pour out a blood container?

flint quarry
#

no, I guess not

#

so I need a different constant

errant sundial
#

Yep!

flint quarry
#

with different statements

errant sundial
#

yeah

#

So what I would do first is just remove the stuff from IPourCanUse and the pour can use handler that won't be relevant for pouring

#

Which means going through and really understanding what each of them were for, and whether you need them for pouring

#

You already know now that you don't need blood

flint quarry
#

so i dont need IPourCanUse at all?

errant sundial
#

Maybe, not sure yet

#

Also, if you want, I just found an easier way to do this that doesn't require a second action at all

flint quarry
#

oh?

errant sundial
#

The normal pour action supports it already

flint quarry
#

interesting

errant sundial
#

All it requires is adding some new stuff to your blood container item descriptions

#

let's look at this vanilla description as an example

itemDescriptions[ItemType.ClayJugOfSeawater] = {
    inheritWeight: ItemType.ClayJug,
    use: [ActionType.Pour, ActionType.PourOnYourself, ActionType.DrinkItem],
    durability: 10,
    returnOnUseAndDecay: {
        type: ItemType.ClayJug,
        damaged: true,
        whenCrafted: true,
    },
    repairable: false,
    onUse: {
        [ActionType.DrinkItem]: [0, -15, 1, -2],
        [ActionType.Pour]: TileEventType.PuddleOfSeawater,
        [ActionType.PourOnYourself]: TileEventType.PuddleOfSeawater,
    },
    worth: 50,
    tier: {
        [ItemTypeGroup.Liquid]: 1,
    },
    spawnOnMerchant: [BiomeType.Arid],
    createOnBreak: {
        tileEventType: TileEventType.PuddleOfSeawater,
    },
    createTileEventOnCraft: TileEventType.PuddleOfSeawater,
    noCraftingQualityBonus: true,
    group: [ItemTypeGroup.ContainerWithLiquid, ItemTypeGroup.ContainerOfSeawater, ItemTypeGroup.FireExtinguisher, ItemTypeGroup.Liquid],
};
flint quarry
#

onUse: {
[ActionType.DrinkItem]: [0, -15, 1, -2],
[ActionType.Pour]: TileEventType.PuddleOfSeawater,
[ActionType.PourOnYourself]: TileEventType.PuddleOfSeawater,
},

#

this bit?

errant sundial
#

Yeah, plus a couple other things in here

#

Also use, returnOnUseAndDecay, createOnBreak, and createTileEventOnCraft

flint quarry
#

Just saw that

#

Yeah I suppose it's redundant to have it say pour blood

#

we already know

#

Since pour already exists

#

I didnt even think of that

errant sundial
#

yep

#

Unfortunately can't do it with fill, that one's hardcoded

#

Luckily pour isn't though

flint quarry
#

fill?

#

wdym?

errant sundial
#

fill container/gather liquid/whatever

flint quarry
#

like when you fill a hol?

#

hole*

#

oh

#

so fill has to be the same for everything

flint quarry
#

Anyway how will it know that it's blood it's pouring out?

#

the bloodtileevent isnt like stored in the bottle right?

#

oh

#

I guess it is nice

#

I should've run it before I asked, sorry

#

I even fixed a bug where when I collected blood with the clay jug it showed an icon of both the glass bottle of blood and the clay jug of blood above the players head, now it only displays the clay variant 😄

flint quarry
#

This all looks right to me however only the clay jug and class bottle allow for the action of collection when facing blood, for the new two it only shows collecting as a use the item is allowed to use if that makes sense

#

I already did the definitions for them and everything

flint quarry
#

idk I give up; as far as I can see everything matches up fine, there's no errors in Visual studio, and the only errors the wayward console throws are weight errors which were there before anyway.

errant sundial
#

Sorry wasn’t available last night. I’ll take a look in a few hours

flint quarry
#

Don't be sorry. it's okay yuudaaGuns

signal folio
#

Not spotting anything else so maybe this was the bug you were talking about?

flint quarry
#

Oh my god Im so dumb 🤣 🤣

signal folio
#

:p

flint quarry
#

:p

#

thank you, again.

signal folio
#

nw!

flint quarry
#

I keep getting this error in the wayward console and no matter what I do; weight, inheritweight, the weight is never changed to what i'd like it to be. The game keeps switching it to some default.

#

I cant see any other ways to change weight those two should be the only ones, right? weight and inheritweight

errant sundial
#

@main merlin I dunno how to help with this one

tame idol
#

looking at code, static weightTree(, inheritWeight works only for depth 1, eg. it takes weight property from referrenced item, or calculates it from its recipe if weight is not available, but does not recursively check for inheritWeight if neither weight or recipe are present
from your screenshot, you inherit from *OfGoatMilk, which has neither weight or recipe defined, so you could try something that has recipe like ClayJugOfDesalinatedWater, or just straight up empty container ClayJug

flint quarry
#

How come I get the same type of error with the regular weight modifier in that case?

#

So I want the weight to increase just slightly when the texture is switched from the items non filled variant to the filled one. And then decrease back to the regular empty weight when poured out

#

For example the regular clay jug is ±1.2 I believe, when I tried setting the regular weight of the filled variant I get a basically identical error in the wayward console.

tame idol
#

dont know, maybe weight calculation fails at some point due to unexpected combination of parameters, returning wrong numbers for min and max weight
in general weight parameter is set for raw resources like Granite, and crafted items calculate their weight according to recipes
inheritWeight is used by items that change state, like lit/unlit torch or filled/empty container, with no change in weight except for cages contaning monsters
there is reducedWeight parameter, that is used to reduce weight of product to lower value than its components allow, but it is always used with positive number for weight reduction
you could try using inheritWeight with empty container and reducedWeight with -0.2 or something to increase weight, but it might increase it by 0.2 permanently with each filling

flint quarry
#

Well I definitely don't want the weight to go up permanently, that doesn't make any sense. There's gotta be a way to make this work properly.

flint quarry
#

From what you said it sounds like I would in fact need inherit weight, so what exactly is the issue with the code

#

I mean this is bs. It should apply the weight I assign to it. Period

#

If I want it to be 100 fricking pounds I should be able to do that

errant sundial
#

Since you craft the item it can’t work like that

#

The crafting system of the game is entirely based on the weights of ingredients

#

That’s why groups need default items I’m pretty sure, so that item weights can be determined based on it

#

Hmm, actually, you didn’t add a recipe.. there must be some other weight property it’s based on then

flint quarry
#

Yeah there's no "recipe" it just looks to see if blood is available to pick up

errant sundial
#

I’m not sure I don’t really understand how weight is done right now tbqh

flint quarry
#

Rip

errant sundial
#

Part of the reason I pinged Drathy

flint quarry
#

Thanks for trying lol

#

I'll just leave it til drathy sees. It's not really breaking anything. Just a personal preference thing to have it have different weights

flint quarry
#

I'm noticing something very strange about weight of items in general now that I'm messing with it. I have three regular waterskins both spawned in with their qualities set to "normal", yet all three of them differ from each other in weight. Two of them even have the same durability but one of them weighs more than the other for some reason. This is with all the weight modifiers removed from my code.

main merlin
#

there is a random variance between all items

#

if there's no recipe/inheritWeight set, you should be able to set the weight to whatever you want

flint quarry
#

I can do that but then when the liquid is dumped out the weight isn't corrected which doesn't make sense

#

So for instance say the glass bottle is ±1 and I set the glass bottle of blood to be ±1.3, it does change it but when I pour out the liquid the glass container will still return as the filled bottles weight

main merlin
#

ah, true

#

there's no system for this currently - as mentioned, everything is based on crafting component weights

errant sundial
#

How does the container of milk work? Since that’s not crafted?

flint quarry
#

Oh, okay. I'll just leave it and let everything default out then lol

main merlin
#

it uses inheritWeight

errant sundial
#

So does that mean milk is weightless?

main merlin
#

all liquids are

flint quarry
#

Interesting

errant sundial
#

Ah gotcha

flint quarry
#

That makes more sense