#Help with modding

1 messages Β· Page 2 of 1

storm imp
#

I can test it again in a few hr

#

With a clean save

storm imp
#

Yeah, not working before and after breakthrough

#

No error messages in devmode's log, and nothing unusual in combat log

#

Not sure if its correct, but the buff displays only in breakthrough bonuses, not in the art itself

#

Just like stats do

outer jay
#

Hmmm

#

Bug it

#

With repro mod plz

minor flame
#

I have Multiple technique crystals, is there a better way to add fallback techniques then to just copy paste them from the previous ones?

outer jay
#

Sadly no

minor flame
#

urg, thats gona look so awkward in tho code... well I only need to see it once..

#

is there a limit of techniques that can go in to the fallback?

#

there seams to be, I can put in the 7 from my T1 Crystal but if I try to put in the ones from my T2 Crystal then my inventory imediatly fades to black and throw me out when I try to open it

outer jay
#

That means the game crashed

#

It's not a limit though, it's likely some other bug

minor flame
#

it was, my smooth brain forgot to add one of the the techniques... odd thing is the crystal where that technique is in was fine

storm imp
#

another question, can we reach current game flags with modAPI? I've seen how the mundane ascension mod does it, using a .tsx with ModScreenFC to reach ModReduxAPI that can select stuff like player current realm

outer jay
#

If you want to actively read, so run some code, then I has to be attached to a screen like the example mod does

#

Otherwise just use them in conditions

storm imp
#

ah, got it

#

so, I can like use an invisible screen after a trigger like combat end to update stuff, for example?

outer jay
#

There's after combat end hooks

storm imp
#

yeah, I'm imagining using them to summon the screen that has the code

#

just not sure how it would interact with current context, if you need to set another screen after it

outer jay
#

The hooks have all the game state too

#

No need for a screen in that case

storm imp
#

ah, thats cool

#

thanks again

#

I'll make a little pause in modmaking to experience new cloud, thanks for the update

minor flame
#

is there a way to make a image aper in front of the char? the overlay only shows the image where the char is but I want to create a bubble around it

outer jay
rustic mist
#

hello every one I'm starting up on trying to make a mod,

might need help so I'm just saying hi first πŸ˜„ .

outer jay
#

Good luck!

hollow light
formal ocean
#

is the SimpleWelcomeScreen example outdated or im missing something?

outer jay
#

Can you give more context ?

formal ocean
#

sorry trying to figure out screens so i thought ill just give the example a try so i copied 1:1 from the example to index.ts

#

copied from docs\advanced-mods\adding-screens.md

#

i assumed it was outdated because 'Click' is not a valid arg for playSfx() at least from my editor might be wrong though not familiar with js and ts

#

inb4 the project setup was allg

#

no errors or anything

sonic stratus
#

you can check the list of acceptable values, you even have part of it displayed in the warning

outer jay
#

Also it needs to be in a .tsx fike

#

Not a .ts

#

Bug it, I'll update the docs when I'm back

sonic stratus
outer jay
#

I didn't read it lol

#

My mistake sorry

formal ocean
#

also in the example inside the return statement player.name doesnt exist and GameButton expects 2 args but only got 1

#

already changed the player.name to player.forename so thats good

#

'GameButton' cannot be used as a JSX component.
Its type 'GameButtonFC' is not a valid JSX element type.
Type 'ForwardRefRenderFunction<HTMLButtonElement, ButtonOwnProps & Omit<ButtonBaseOwnProps, "classes"> & CommonProps & Omit<...> & { ...; } & { ...; }>' is not assignable to type '(props: any) => ReactNode | Promise<ReactNode>'.
Target signature provides too few arguments. Expected 2 or more, but got 1.ts(2786)

outer jay
#

Okay, it should be better to look at the sources for the example mod mundane ascension

#

That has a screen

formal ocean
#

alright thank you!

outer jay
formal ocean
#

Oh btw is it possible to modify an existing screen using the api? i gave a quick look through docs it seems to suggest only creating new screens.
if yes,
do you have an example of modifying existing screen? if no, if you dont mind could you point to me the folder or file that handles the screen for crossroads or other exploring locations,

#

inb4 been scouring node_modules cant seem to find it prolly cus im blind
been scouring the non-minified code too prolly and cant find it prolly cus im definitely blind

outer jay
#

You can't currently modify an existing screen no

formal ocean
#

ah dang hahah welp

outer jay
#

For the exploring locations, that's SelectedLocationDialog opening an event, so EventScreen

#

What did you want to do?

formal ocean
#

automating the explore button xd

#

was thinking of adding another button or modify the current explore button

outer jay
#

So currently that isn't possible through the mod api

#

Put in a feature request though, I'll add more API extension points

#

Add new buttons to location dialogs maybe

formal ocean
#

Alrighty thanks!

#

alright already made a request, thanks for answering my questions so openly btw if i knew you were this cool i wouldve bought this game at full price xd looking foward to full release!

outer jay
#

I always appreciate someone interested in modding!

#

Mods are awesome

formal ocean
#

No truer words have been spokenπŸ’―

fading ginkgo
#

Yo yo, is there a way to check if a certain item has been consumed? Like adding a flag when you consume it from the inventory, or something?

outer jay
#

Currently not. ATM the only thing we do that with is the stat pills and those write their own flags directly

#

Is there a particular one you'd like to track? Feature request it

fading ginkgo
#

I wanted to lock breakthroughs behind the consumption of a pill, but I could just make it an advancement material or check if the player has a certain amount of stats

#

Thanks :)

fading ginkgo
#

On that note, where could we possibly find portraits and such in the style of AFNM?

outer jay
#

Currently you'll have to use models like nano banana or qwen image (or sdxl) with a reference image for style transfer

#

I don't have a easy to share workflow atm

fading ginkgo
#

why does this happen and how do i resolve it?

outer jay
#

Got a GitHub repo I can look at?

fading ginkgo
#

Sorry, just got back home

#

I also changed the names to include both .png and without, didn't change anything

#

Also tried the example vigorpill from the mod documentation and it didn't work, same error

outer jay
fading ginkgo
outer jay
#

yep i see it, ill ake a look now

#

ah i see the issue

#

your relative path was wrong

#

given you moved it to a subfolder, you need to path out one extra level

fading ginkgo
#

ah

#

thank you :)

outer jay
#

np, happy modding πŸ˜„

thin pine
#

Are player sprites hardcoded?

outer jay
#

Currently yes

#

Put in a feature request and I can add a mod api to add more

storm imp
#

Is the only way to upgrade items by swapping them to new ones with the different stats? I'm thinking of condensation arts that can evolve, but adding more arts increase the QC to CF breakthrough art list, flooding it with unknown arts

#

There is also the issue of unequipping current art and force equipping the new that I'm not sure about how to do, even if that is the only way

sonic stratus
#

I asked Lyeeedar for this feature and he added it iirc

storm imp
#

This should solve part of my problems, now only lost about force equipping something and deleting the previous art, need to dig some more

#

I'm also having a strange hover bug/glitch when I hover over a custom art tooltip for some reason, but this only happens in 1 line of the breakthrough text

sonic stratus
storm imp
storm imp
#

here, its a test condensation art I'm using as a base , when I hover over the top one (below Qi Vessel) the game blinks black and returns this in the devlog

#

when you hover over the art itself in the slot

#

its mostly to test, and for some reason it also has one of its effects hidden, it gives ripple/round

sonic stratus
#

i'm about defense

#

smth like: on combat start gives defensePerRippleBuff

#

and defensePerRippleBuff contains defense buff per ripple

#

i'm not sure if this is related to the problem, but the current version looks weird

#

ah, it's already combat effect, sry

#

i'm blind

storm imp
#

Current effect inbattle seems to be working as intended as well

#

I created a buff with 3 effects that this cond art adds

#

The max hp, def scaling on ripple and ripple/ round

#

It seems to be complaining about this buff stat field when I added it to the art (or not lol, changed this and nothing changed, idk idk)

#

Ah, its the same thing I placed at the other buff that is hidden

outer jay
#

Make a bug and share your mod. I will fix

sonic stratus
#

I'm still not very sure about difference, but it seems like defense is something you get in various ways before the fight, and protection is something you get during the fight

outer jay
#

Defense is a flat number, so can be used to provide realm specific damage reduction (e.g. on equipment). Protection is a percentage so works the same no matter the realm, so best for techniques that aren't supposed to be realm gated

sonic stratus
#

and does +X% defense work the same as before?

outer jay
#

If it's on a buff yes

#

And yes

sonic stratus
outer jay
#

It's better now because the damage reduction is best on realm, not hp

sonic stratus
storm imp
#

also, it seems that condensation art isn't stored as an item (equipped) like others (clothing,flame,artifact,talisman...)

#

maybe thats why we can't directly equip it, but it changes when we change it in breakthrough screen

#

managed to hide the other arts breakthroughs (for the evolved higher realm versions) by changing the created breakthrough hidden property, but to swap an art it seems I need to change the state of the breakthrough, wherever it is stored at

#

there is also the issue of transferring enchantment, even if it is done

arctic sundial
#

is it possible to reuse assets already in the game and how to do so? was trying to add a test item using an existing icon.

sonic stratus
#

u can use smth like this

arctic sundial
#

ah great, thank you!

sonic stratus
trim ether
#

Hi, i tried adding a Healer to the Yinying Mine, but the healer icon does not appear. the mod loads without errors.

#

i used this code to do this: window.modAPI.actions.addBuildingsToLocation('Yinying Mine',[{ kind: 'healer' }]);

#

what am i doing wrong?

trim ether
#

i guess the name is wrong, how do i find the real name of a location?

#

i found the real name in the non minified code, its called 'Spirit Ore Mine'.

is there a way to find these information in the ingame dev console?

outer jay
#

Currently no. You'd have to just look at the non minified code or print the locations from your mod to inspect

trim ether
#

ok thank you πŸ™‚

minor flame
#

what image formats are accepted by the mod api? it seams not to like webp.

outer jay
#

Webp should work. Gif, PNG, jpeg also should work

minor flame
#

I have a image as png and webp in the same folder, the png works without problem but it cannot find the webp

outer jay
#

Raise a bug about that please

minor flame
#

The mod api now handels webp's in the code editor but when I try to build I et this error for all my webp's

#

any solutions?

outer jay
#

I added a fix to the main branch

#

You might want to fully update yours to ensure it works

#

If that doesn't work, get the changes to webpack

minor flame
#

worked after manualy updating the webpack file

#

also is there a way to create a new tab for techniques?

#

just throwing them all in neutral makes it a bit cluttered

outer jay
#

Currently no, but I may add something

minor flame
#

Is there something specific I need to do with a location to use it as a root location?
const Root_test: RootLocation = {
locationName: 'Essence Chamber (WIP)',
condition: '1',
}
That alone dos not put it on the map for me.

outer jay
#

You need to add the location first

#

Then set it as a root

minor flame
#

its already added and acceseble with a tp

#

when inside that location, pressing travel sends me back to the sect

outer jay
#

Oh it's on the map, but there's a bug

#

That'd different

#

Bug it, please provide the mod

minor flame
#

kk

crimson gazelle
#

It seems like when using custom sprites, (re)starting the game is missing the sprite from the main screen overview. I'm not sure if I'm doing something wrong with my mod (which gives neither errors when building, nor problems when starting a new character or when actually in the game or returning to the main menu after mods were loaded) or if its a basic problem with the game loading the mod after the sprite of the last continue option gets displayed when starting up for the first time.

Is there a way to refresh the sprite after loading mods perhaps? Or to somehow affect the loading order.

outer jay
crimson gazelle
#

ok thank you

crimson gazelle
#

Just tried uploading my mod. It does seem to have troubles with the image paths.
The build .zip file works fine if I add it locally in the mod folder, but does not find the images when going through steam/mod uploader.

I'm importing the images in index.ts like this:

import { PlayerSpriteImages, PlayerSprite } from 'afnm-types';

//importing female sprite images
import fopFemale1base from '../assets/female/fopFemale1base.png';
import fopFemale1agg from '../assets/female/fopFemale1agg.png';
import fopFemale1def from '../assets/female/fopFemale1def.png';
import fopFemale1hit from '../assets/female/fopFemale1hit.png';
import fopFemale1off from '../assets/female/fopFemale1off.png';
import fopFemale1sup from '../assets/female/fopFemale1sup.png';
import fopFemale1uti from '../assets/female/fopFemale1uti.png';

Then using them:

window.modAPI.actions.addPlayerSprite({
id: 'fopFemale1',
name: 'FOP Female 1',
gender: 'female',
sprites: {
base: fopFemale1base,
aggressive: fopFemale1agg,
defensive: fopFemale1def,
hit: fopFemale1hit,
offensive: fopFemale1off,
support: fopFemale1sup,
utility: fopFemale1uti,
}
});

Which seems to work just fine locally.

The mod uploader tells me the following, which I find odd:

[22:56:30] Selected ZIP: faces-of-plenty-1.0.0.zip
[22:56:30] Extracting mod information from ZIP...
[22:56:30] No mod.js found in ZIP file or could not extract metadata

The inagme description of what it loads / paths seem to be identical with both adding the build .zip file locally into the mod folder and with subscribing to steam, except that one shows the sprite, the other is missing the sprite as if it could not find the image.

Any ideas?

outer jay
#

Can you share the repo?

crimson gazelle
#

holy moly, I try πŸ˜„

outer jay
#

Can confirm, the mod itself is missing all it's content

#

Not sure why, but I'd need the repo to trace it through from the start

crimson gazelle
outer jay
#

Oh the mod you've uploaded is fine, the issue is game end

crimson gazelle
#

but locally it works? O.o is it using steam mods differently than local mods?

outer jay
#

Yeh that's what I need to look into

#

Given the other workshop mods work fine

#

So something about your mod is breaking the laoder

#

But I'll fix it

#

In the morning πŸ˜‚

crimson gazelle
#

take your time. I'm already happy that you provide so much help ❀️

outer jay
#

I have a fix, will push it to the beta branch in the morning

crimson gazelle
#

Thanks

outer jay
#

its on the beta branch

#

will do a proper release (and you can make your mod public) later this week

crimson gazelle
#

tried uploading with Mod Uploader 1.4.4, which still fails. There is a version 1.4.5 showing up in the modloader bar at the top, but when I select download it fails hanging at 0% permanently. Not sure if that would even fix the issue, but is there a way to manually grab 1.4.5?

outer jay
#

Yeh it's on the GitHub releases of the mod uploader

#

Does it show what the error is?

crimson gazelle
#

the download just never goes beyond 0%, no error or even timeout.
as for the mod itself it gives the following output at the debug console

[12:52:56] Editing workshop item: Faces of Plenty
[12:52:57] Opening file selector for ZIP...
[12:53:00] Selected ZIP: faces-of-plenty-1.0.0.zip
[12:53:00] Extracting mod information from ZIP...
[12:53:00] No mod.js found in ZIP file or could not extract metadata

Found the GitHub release, thanks. Same error though sadly.

outer jay
#

No mod.js found, that's not ideal

#

Mind sharing the mod zip you are trying to upload?

#

Btw I love your mod, I'm using it for my test playthroughs πŸ˜‚

crimson gazelle
outer jay
#

Ty, definitely the uploader thats at fault. I'll look into it

crimson gazelle
#

hi, just checked again, while the mod uploader still gives me the same error, in the game it seems to work now. At least I no longer have the local version added and it's properly under the loaded folder from steam. Might just be an odd thing with the loader

#

the thing I noticed that's different compared to other mods, is that icons etc. in other mods are loaded with a file:///.. path
while my images load with a mod://faces-of-plenty-... path

As I have no other sprite changing mods to compare with, not sure if that's the difference.

#

I will test some more ingame if everything is working as expected and if I see no other problems ingame, I turn the mod from Unlisted to public later today. Thanks again.

outer jay
#

The mod path is correct

outer jay
minor flame
#

Around when will the updated non minified Code be relesed? I am interested to 'borrow' some things from the new weapon system

outer jay
#

but you can use all the new mecahnics, they are in the types

minor flame
#

guess I will have to actually try and not just 'borrow' from your code

outer jay
#

happy to share the stuff you want to see if you request

#

but i wont psot the whole zip as its riddled with spoilers

minor flame
#

I mean If you can share some example code for the new puppets and the tempering, that would be great

outer jay
minor flame
#

what is the curent afnm-types version? 0.6.38?

outer jay
#

Oh wait

#

I forgot to publish it

#

Gimme a mo

#

Okay it's now 0.6.40

minor flame
#

got it now, thx

#

and may have some unstable automaton code : D

#

if you have time of course

outer jay
minor flame
#

thank you : D
This will work well with my summon techniques, once I compleatly remade them that is

#

is there a hard cap for the amount of guardian bufs?

outer jay
#

Nope

minor flame
#

good to know, I will try to not over do it

outer jay
#

Should be fine, they stack multiplicatively so unless you give them insane hp shouldn't be op

crimson gazelle
#

has different hashes, so maybe just forgot to rename them?

#

works like a charm now in the debug console ❀️

#

1:38am here so I test it properly tomorrow, looks good though

round marten
#

@outer jay Is there a way I can use base-game ingredients in modded recipes? Looking through exposed data and it doesn't seem like they're available unless I'm missing them.

outer jay
#

Yeh, look then up by name from the items in the mod.data

#

So like mod.data.items["Lesser Spirit Grass"]

round marten
#

Cool, that looks to work, thanks.

outer jay
#

Note that goes for all base game assets

#

And mod assets for that matter

#

Just look then up from the data maps

#

For mods if you want to use another mods resources you have to ensure yours is loaded after the other one

round marten
#

Where are data maps for base game stuff? I was just going to load up game and look for the item, is it a devmode thing?

outer jay
#

ModApi.data

#

That's where everything is exposed

round marten
#

@outer jay For the onCompleteCombat hook, is it possible to get the creature (more specifically the drop table) that was being fought? As far as I can tell that doesn't seem to get exposed.

outer jay
round marten
outer jay
#

oh thats a good idea. Yeh request it

round marten
#

@outer jay Can you confirm you managed to get the registerOptionsUI working? Trying to test it just now with the documentation example and tried a few tweaks but all result in same console error:

#

Error occurs when hitting the cog icon, screen goes full black with no controls.

outer jay
#

Darn no I didn't test

#

Mind sharing your mod?

#

I'll take a look

#

Ideally, the mod code you have too

round marten
#

I think also I should've been more clear in my feature request for the onCompleteCombat stuff since it doesn't do what I needed still, I needed to get the items that were dropped from the fight, but with this I can just get what can be dropped. Can still technically do what I wanted to do but would be good if we could get the exact items dropped from the combat.

outer jay
#

ill take a tstab

outer jay
#

again, and easy add

round marten
# outer jay ah feature request THAT too πŸ˜„

Just thinking on from what I was testing, the technique shards aren't part of any drop tables but are of course dropping from combat, didn't include that in the request but if those can be included as well that'd be good, unsure how those drops are decided.

outer jay
#

yeh add it to the request too

outer jay
#

Fix to the config will be in the nightly

round marten
#

@outer jay Just want to confirm, I'm trying to add a new breakthrough for Mundane realm, but I can't get the new breakthrough item I've added to be accepted for the Pill slot. Looking at the non-minified code for 0.6.22 it looks like it's hardcoded to only accept the True Awakening Pill so i think that might be the issue, but unsure if it's changed since that update.

outer jay
#

thers a new field:

export const trueAwakeningBreakthrough: Breakthrough = {
  allowedSlotItems: {
    awakeningPill: [trueAwakeningPill.name],
  },
  name: 'True Awakening',
  description:
    'The first step that any mortal must take on the path to immortality. With the use of the True Awakening Pill, reshape your body and soul to accept Qi into its very essence.',
  requirements: [
    (args) => ({
      done: args.breakthrough.mundane?.pill === trueAwakeningPill.name,
      preview: (
        <GameTooltip
          provider={() => <ItemTooltipWithLocation item={trueAwakeningPill} location={``} />}
        >
          <Box display="flex">
            <Typography fontSize="120%">
              {parseTooltipLine(t('<itm>{itemName}</itm> in the Pill slot', { itemName: trueAwakeningPill.name }))}
            </Typography>
          </Box>
        </GameTooltip>
      ),
    }),
  ],
  totalRequirements: 1,
  getNumDone: (args: RequirementArgs): number => {
    return args.breakthrough.mundane?.pill === trueAwakeningPill.name ? 1 : 0;
  },
  physicalStats: {
    flesh: 1,
  },
  socialStats: {
    lifespan: 30,
    charisma: getBreakthroughCharisma('bodyForging', 1),
  },
};
#

allowed slot items

#

add that to your breakthrough and it should populate

round marten
#

Did that, even threw it in all of them to just make sure, but it still doesn't show up.

outer jay
#

by doesnt show up, what do you mean?

round marten
#

Breakthrough is there, but pill doesn't show as an option.

outer jay
#

have you added it to the inventory?

round marten
#

It is in inventory as well.

outer jay
#

hmmm

#

bug it with the mod code. will debug πŸ˜„

round marten
round marten
#

@outer jay Does the API expose what the enemy stances are during combat rounds? Trying to make a technique that has conditional logic based on what the next technique the enemy is going to do but don't think I can grab that information.

outer jay
#

No there's no way to read that atm

round marten
#

Ah, alright. I'll throw a request in.

tardy heron
#

I would be interested in making new schools if we can get an addElement method exposed on the ModAPI.

tardy heron
#

Any ideas on why my technique isn't loading? Trying to just get a proof of concept on body forging.

outer jay
#

Raise a bug

#

It should still be addable if you do add all techniques

tardy heron
#

Confirmed learning all techniques makes it available for testing.

round marten
#

@outer jay How are request boards setup? Trying to make a mod that increases the amount of quests that can be taken at once but, unless I'm missing it, that's not currently possible with the API?

outer jay
misty forge
#

is there a way to see the structure of backgrounds ?

outer jay
#

They are in the newgame.ts file in the non minified code

misty forge
#

i cant seem to find that file

outer jay
#

data/newGame.ts

misty forge
#

i dont have a data folder

outer jay
#

In the non minified code?

#

#1279052223690834000 message

misty forge
#

i have the game folder from steam and the modding guide fro github

#

thx

misty forge
#

can somne help me on why birth background appears twice ?

#

it seems that the child background did not appear to work

#

or is the child background only meant to apply physical stats with a limit to each ?

outer jay
#

Likely the same issue for the next one. You need to give it a unique name

misty forge
#

oh thx

nova cloud
#

had an idea for a classic wuxia pill where you get a powerful boost for a while but you pay for it dearly afterwards. the buff/debuff cycle comes out pretty easy so far. but can't find a way to reduce lifespan as well.
is combatItem only temporary buffs or there's a way to make the change permanent?

outer jay
#

Only temporary atm

#

You can put in a request for certain parts to become permanent

nova cloud
nova cloud
rancid surge
#

is there anyone that can explain how to add custom player character sprites for people not good with modding SusGuilty

rancid surge
placid monolith
#

in hooks.onReduxAction it says I can't modify a read only property of some inner state, how do I even modify the state if I can't do that?

placid monolith
#

hmm had to create a new object from existing one with just the specific field modified... so much for trying to keep the callback simple

#

well, it' s a shallow copy I think so shouldn't be that big of a deal

outer jay
#

Yeh redux you always need to make shallow copies

#

That's how it determines that you changed something

placid monolith
#

I can't modify gamedata? It doesn't seem to have any effect, ig it's returning a copy?

for (const [key, value] of Object.entries(window.modAPI.gameData.crops)) {
  window.modAPI.gameData.crops[key as Realm] = value.map(it => ({ ...it, growthDays: 1 }))
}
outer jay
#

for gamedata you need to modify the object itself, so like:

window.modAPI.gameData.crops.bodyForging.forEach(e => { e.growthDays = 1 })

#

otherwise all the existing references wont see your new version

placid monolith
outer jay
#

yeh redux is the only place you should mutate because thats how it works internally

#

generally outside that editing the object itself is best

placid monolith
#

why's access to redux action's payload not provided in the onReduxAction api? Would be useful to know what's actually being changed

{
  "type": "inventory/removeItem",
  "payload": {
    "name": "Blueprint: Compendium Room",
    "stacks": 1
  }
}
outer jay
#

What do you mean, looks like the payload is there?

placid monolith
#

I'm asking for payload being made available to the callback passed to onReduxAction if it wasn't clear before

#

would be even better to be able to directly modify the payload for the action, instead of messing with stateBefore and stateAfter

#

in some cases

outer jay
#

Oohhh

#

Request it

placid monolith
placid monolith
#

it doesn't look like location links (LinkBase variants) are available for modification via .gameData?

#

well, can't even get a readonly copy of them, let alone modify

#

unless I missed it

outer jay
#

They are on locations themselves

#

So you find the location, look at unlocks, that's where they are

placid monolith
#

ig I didn't look at field types but only the names, welp

placid monolith
#

is there a way I can check which UIs are opened currently? Like I want to know whether the equipment upgrade dialog is opened or not at a given moment

#

there's no element id that I could target, and class names are mangled as css-*

outer jay
#

Currently no

#

Request it

placid monolith
#

what does multiple interceptors here mean exactly?

// When multiple interceptors are chained, each one receives the payload returned by the previous one.
onReduxActionPayload: (interceptor: (actionType: string, payload: unknown) => unknown) => void
outer jay
#

So if multiple mods intercept, the value is chained along so each one can modify it

#

In mod load order

placid monolith
outer jay
#

admittedly not the clearest of comments

placid monolith
#

not sure how mod translations with afnm-extract-translations work, but can I exclude some strings from being included in the template.json? Since they're not really display strings and must not be changed.

  "arrays": {
    "src/modContent/index": {
      "[string] Empowered": "",
      "[string] Incandescent": "",
      "[string] Mundane": "",
      "[string] Qi Touched": "",
      "[string] Resplendent": "",
      "[string] Transcendent": ""
    }
  }
outer jay
#

So they won't be changed unless you actually try to render them

#

Where do those strings appear in your mod?

placid monolith
outer jay
#

Tbh you can probably ignore it

#

That part of the string extraction is there to try to catch shared stuff

#

Again, if you never actually render them they will never be used

#

(as in, pass it to the t() function)

placid monolith
#

ah it's example of some tea related mod lol, nvm, this is what I get for skimming

#

I was starting to wonder where's tea in afnm...

outer jay
#

The true British cultivation

placid monolith
#

moving over the discussion here from: #1497938529869627392 message

Oh and for TS/IDE support, just keep the global.d.ts (the one with the modAPI types) at the root, include it in a tsconfig.base.json, and have your child mods extend that base config with a one-liner
@jagged parcel it's not working, so I'll just have the tsconfig.json be a symlink, wouldn't be able to customize individual package's tsconfig that way but I don't see my self needing that rn anyways

#

as for package.json, it still has some duplicate stuff but ig I'll live with it

{
  "name": "mythical-tweaks",
  "version": "0.0.1",
  "description": "",
  "author": {
    "name": "loremaster"
  },
  "main": "dist/mod.js",
  "scripts": {
    "extract-translations": "afnm-extract-translations",
    "prebuild": "afnm-extract-translations",
    "build": "webpack --config ../../webpack.base.config.js --mode=production",
    "postbuild": "node ../../scripts/copy-translations.js && node ../../scripts/zip-dist.js"
  }
}
jagged parcel
# placid monolith moving over the discussion here from: https://discord.com/channels/1208332427618...

Yeah, that makes sense. I think my earlier tsconfig.base.json suggestion was incomplete.

The annoying bit with TS config inheritance is that include, exclude, rootDir, outDir, etc. are path-sensitive, and inherited relative paths stay relative to the config file they came from, not magically relative to each package. So if the base config has something like:

"rootDir": "./src",
"include": ["src/**/*"]

and a package extends it, those paths can still effectively point at the wrong place. That is probably why it β€œdidn’t work.”

I would avoid symlinking tsconfig.json if possible. It’ll work until you need one package to differ, then it becomes annoying again.

I think the better split is:

Root tsconfig.base.json should only contain shared compiler options:

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "sourceMap": true,
    "inlineSourceMap": false,
    "preserveConstEnums": true,
    "removeComments": false,
    "jsx": "react-jsx",
    "lib": ["DOM", "ES2023"]
  }
}

Then each mod has a tiny real tsconfig.json:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "./src",
    "outDir": "./dist"
  },
  "include": [
    "src/**/*",
    "../../global.d.ts"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

That keeps package customization open, but still avoids duplicating all the actual TS options.

#

(once second discord char limit holding me back lmao)

placid monolith
#

I think I should just bite the bullet and have bun run build only be available in the root and just be fine with every build command building all the packages/mods

#

won't have to include scripts property in each packages package.json that way

jagged parcel
#

For package.json, I’d also avoid putting build scripts in every mod package. That’s where most of the duplication is coming from. Since AFNM’s example config already uses package.json for metadata injection and outputs dist/<package-name>/mod.js, I’d keep the per-mod package.json as metadata only, then make the root build script accept a mod name.

Per mod:

{
  "name": "mythical-tweaks",
  "version": "0.0.1",
  "description": "",
  "author": {
    "name": "loremaster"
  },
  "main": "mod.js"
}

Root package:

{
  "private": true,
  "workspaces": ["packages/*"],
  "scripts": {
    "build:mod": "node scripts/build-mod.cjs",
    "package:mod": "node scripts/package-mod.cjs"
  }
}

Usage:

pnpm build:mod mythical-tweaks
# or
bun run build:mod mythical-tweaks

Then the root webpack config receives the target explicitly instead of relying on __dirname from a symlink:

#

And scripts/build-mod.cjs:

const { spawnSync } = require("node:child_process");

const modName = process.argv[2];

if (!modName) {
  console.error("Usage: build:mod <mod-name>");
  process.exit(1);
}

const result = spawnSync(
  "webpack",
  [
    "--config",
    "webpack.base.config.cjs",
    "--mode",
    "production",
    "--env",
    `mod=${modName}`
  ],
  {
    stdio: "inherit",
    shell: true
  }
);

process.exit(result.status ?? 1);

So instead of this inside every package:

"scripts": {
  "extract-translations": "afnm-extract-translations",
  "prebuild": "afnm-extract-translations",
  "build": "webpack --config ../../webpack.base.config.js --mode=production",
  "postbuild": "node ../../scripts/copy-translations.js && node ../../scripts/zip-dist.js"
}

you move that orchestration to the root and parameterize it by mod name.

For translations/zip, same idea:

pnpm package:mod mythical-tweaks

and the root script knows to operate on:

packages/mythical-tweaks/

That gives you:

  • no symlinked webpack config
  • no symlinked tsconfig
  • one-mod-at-a-time builds
  • mostly metadata-only package files
  • still compatible with the AFNM example shape: src/mod.ts β†’ dist/<mod-name>/mod.js
  • room for per-mod tsconfig overrides later
#

Yeah I can't really think of a clean solution, that was the best I could come up with.

placid monolith
#

hmm

empty folio
#

so... i'm on the basic level of modding. I've created my environment, pulled the example mod, and completed a successful build (of the example).

Which part of the documentation should i review if i have two goals for the mod?

Add a small calendar window to the screen. ideally top left, that shows the current year, day, and month (and information based on the date)

utilize the current day, year, and month - to adjust character stats like luck, probability to complete crafts, and crit chance?

P.S. This is in shell/arch/bash

jagged parcel
# placid monolith won't have to include `scripts` property in each packages package.json that way

Yeah honestly, that’s a pretty sensible tradeoff.

If the main goal is removing duplicate scripts from every package, then I’d make builds root-only and let:

bun run build

build every mod under packages/.

That keeps each package’s package.json basically metadata-only, which is much cleaner.

I’d still structure the root build script so it can optionally take a mod name later, even if you don’t use that path much right now:

bun run build
bun run build mythical-tweaks

So the root script could behave like:

  • no argument = build all mods
  • argument = build only that mod

That way you get the simple workflow you want now, but you’re not locked into β€œalways build everything” forever.

Something like:

// scripts/build.cjs
const fs = require("node:fs");
const path = require("node:path");
const { spawnSync } = require("node:child_process");

const packagesDir = path.resolve(__dirname, "../packages");
const requestedMod = process.argv[2];

const mods = requestedMod
  ? [requestedMod]
  : fs.readdirSync(packagesDir).filter((name) => {
      return fs.existsSync(path.join(packagesDir, name, "package.json"));
    });

for (const mod of mods) {
  console.log(`Building ${mod}...`);

  const result = spawnSync(
    "webpack",
    [
      "--config",
      "webpack.base.config.cjs",
      "--mode",
      "production",
      "--env",
      `mod=${mod}`
    ],
    {
      stdio: "inherit",
      shell: true
    }
  );

  if (result.status !== 0) {
    process.exit(result.status ?? 1);
  }
}

Then root package.json only needs:

{
  "scripts": {
    "build": "node scripts/build.cjs"
  }
}

And each mod package can drop the scripts block entirely.

So yeah, I’d say root-only commands are the right call. Just make the root build script accept an optional target mod internally, because that costs almost nothing and saves you later if the monorepo gets bigger.

jagged parcel
# empty folio so... i'm on the basic level of modding. I've created my environment, pulled the...

That’s a good next step after getting the example mod building. We can open up a seperate thread if you want more help with this. Here's my take.
I’d look at the docs in roughly this order:

  1. Core Concepts β†’ ModAPI Reference
    This is the base layer. You’ll want to understand window.modAPI, gameData, actions, and especially hooks.

  2. Core Concepts β†’ Flags System
    This is probably the most important part for the date logic. AFNM exposes time-related flags like year, yearMonth, day, and month.

Small warning: I believe month is total months elapsed, not the display month from 1-12. So for a calendar UI, you probably want year, yearMonth, and day. For elapsed-time calculations, use month.

  1. Advanced Mods β†’ Adding Screens
    For a small calendar in the top-left, don’t start with a full custom screen unless you want to replace the whole UI. Look specifically at the Persistent Overlays section. That’s closer to what you want: a little always-visible UI mounted to the page.

  2. Advanced Mods β†’ Lifecycle Hooks
    This is the part for changing gameplay based on date.

For crafting, look at onDeriveRecipeDifficulty. That lets you adjust recipe completion/perfection/stability, which is probably the cleanest way to make certain dates better or worse for crafting.

For combat stats/crit-style effects, look at combat hooks like onBeforeCombat, onCreateEnemyCombatEntity, or onCalculateDamage. I’m not sure if crit chance itself is directly exposed, so you may need to approximate it by adjusting combat stats or damage on certain dates.

#

I’d probably build it in this order:

function getDateModifier(gameFlags: Record<string, number>) {
  const year = gameFlags.year;
  const month = gameFlags.yearMonth;
  const day = gameFlags.day;

  // Example idea:
  // lucky on first day of each month
  const luckyDay = day === 1;

  return {
    year,
    month,
    day,
    craftMultiplier: luckyDay ? 0.9 : 1,
    damageMultiplier: luckyDay ? 1.05 : 1,
  };
}

Then use that same helper in both places:

window.modAPI.hooks.onDeriveRecipeDifficulty((recipe, recipeStats, gameFlags) => {
  const date = getDateModifier(gameFlags);

  return {
    ...recipeStats,
    completion: recipeStats.completion * date.craftMultiplier,
    perfection: recipeStats.perfection * date.craftMultiplier,
  };
});

And for combat:

window.modAPI.hooks.onCalculateDamage((attacker, defender, damage, damageType, gameFlags) => {
  const date = getDateModifier(gameFlags);

  if (attacker.entityType === "Player") {
    return Math.floor(damage * date.damageMultiplier);
  }

  return damage;
});

Short version would be..

  • calendar display = Advanced Mods β†’ Adding Screens β†’ Persistent Overlays
  • current date values = Flags System
  • crafting changes = Lifecycle Hooks β†’ onDeriveRecipeDifficulty
  • combat/stat changes = Lifecycle Hooks β†’ Combat hooks
  • date-based events/content = Events System β†’ Calendar Events, but that’s more for festivals/events than an always-on UI/stat modifier
placid monolith
empty folio
#

I'm not sure when the calculation happens

placid monolith
#

for boost during recipe crafting, there's modAPI.hooks.onDeriveRecipeDifficulty

#

for others a ready made hook may not be available

empty folio
#

I'm mostly interested in luck statistics , crit chance, craft chance, accuracy, maybe power, damage reduction.... but for the most part, this is intended as a globally affective mod that will adjust stats (only slightly) based on the date

placid monolith
#

so you'll have to use hooks.onReduxAction or onReduxActionPayload for when ready made hooks aren't available, which triggers when game state changes or is about to be changed

placid monolith
empty folio
placid monolith
#

I see something like window.modAPI.getGameStateSnapshot()?.player.player.monthBuffs, ig you could have your own custom buffs that you add in there and remove when you want

#

though I'm not sure how to actually modify game state (RootState) outside of onReduxAction* apis

#

snapshot only gives a read only copy

empty folio
#

i can't expect your average joe to know whether it's a good day or not, but the readout should be helpful

placid monolith
empty folio
#

that makes sense. crafting(etc) takes more than one day after a little while. there'd need to be a new calculation, or new base-stat-modifier for each day, whatever it happens to be

placid monolith
#

you can see what redux actions types are available for you to "hook" on with:

function deepDiff(prev, next) {
  const result = {};
  const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);
  keys.forEach(key => {
    if (typeof prev[key] === 'object' && typeof next[key] === 'object') {
      const nested = deepDiff(prev[key] || {}, next[key] || {});
      if (Object.keys(nested).length) {
        result[key] = nested;
      }
    } else if (prev[key] !== next[key]) {
      result[key] = {
        prev: prev[key],
        next: next[key]
      };
    }
  });
  return result;
}

window.modAPI.hooks.onReduxAction((action, prevState, state) => {
  console.log("[REDUX STATE CHANGED] ", { action: action, diff: deepDiff(prevState, state), state: state });
  return state;
});

window.modAPI.hooks.onReduxActionPayload((action, payload) => {
  console.log("[REDUX PAYLOAD]", {action: action, payload: payload});
  return payload;
});
#

and then observe the logs in the devtools console

placid monolith
empty folio
#

is there any documentation for AI assistance? I know it likes to over-complicate things

empty folio
placid monolith
empty folio
#

@jagged parcel i remember seeing documentation for AI assistants and mods. do you remember where?

placid monolith
jagged parcel
#

If you have any issues with it let me know

#

Psst, don't forget to signup for the competition here: #mod-contest-sign-up

outer jay
#

I'll add more hooks to make this mod easier

placid monolith
# outer jay I'll add more hooks to make this mod easier

btw, how'd I mutate RootState outside of something like onReduxAction*?
Don't think I could just grab reference to it and mutate freely, probably has to do that via existing redux reducers that are in place, so then how to emit my own action payloads?

outer jay
#

You have to do it via a dispatch

placid monolith
outer jay
#

Yes

#

You have to be in the redux context

#

And in a react component

placid monolith
#

And in a react component
seems quite limiting

outer jay
#

So from inject UI or add screen

#

ATM you can't just do it globally

#

What are you trying to do?

placid monolith
#

nothing rn, was just curious

outer jay
#

Note, both of those contexts already pass through a dispatch function to use

placid monolith
#

I see, so don't need to create my own dispatch

outer jay
#

Yep. Generally there's 2 ways to modify state:

Do it via a user action in a UI (via dispatch)
Do it by injecting event steps after something happened (by setting flags)

placid monolith
#

is there a toast/notification component in-game that I could reuse? or do I either make my own or reuse the modal dialgos?

outer jay
#

Currently I don't have one

#

I can add one though

#

You can make you own with inject UI

#

Or just attach it globally

placid monolith
#

would be nice if there's a common component in-game that others mods could also use, just for consistency, but if you don't want to maintain one since it's not being used in game that's understandable too

outer jay
#

Throw in a request, I can chuck a library in and expose it

#

Low cost

placid monolith
#

why's it showing old mods? As in mod zips that had previously -{version} suffix in filename, and this is after I deleted the -{version} suffixed mod folders from mods/loaded/

outer jay
#

its gone from the root folder and mods/loaded?

placid monolith
# outer jay its gone from the root folder and mods/loaded?

yeah

.
β”‚   afnm-craftbuddy.zip
β”‚   afnm-lucky-all-around.zip
β”‚   debug-0.0.1.zip
β”‚   mythical-tweaks.zip
β”‚   quicksaves.zip
β”‚   stat-boosts-0.0.2.zip
β”‚   stats-boost-stability-1.1.0.zip
β”‚   
└───loaded
    β”œβ”€β”€β”€afnm-craftbuddy_923e1c220444ab0f
    β”‚   β”‚   mod.js
    β”‚   β”‚   mod.js.LICENSE.txt
    β”‚   β”‚   package.json
    β”‚   β”‚   
    β”‚   └───translations
    β”‚           en.json
    β”‚           
    β”œβ”€β”€β”€afnm-lucky-all-around_15c9322be32fe424
    β”‚       mod.js
    β”‚       package.json
    β”‚       
    β”œβ”€β”€β”€debug-0.0.1_4be8d1cb11a965ba
    β”‚       mod.js
    β”‚       
    β”œβ”€β”€β”€mythical-tweaks_6cce2d3e07483454
    β”‚   β”‚   mod.js
    β”‚   β”‚   mod.js.map
    β”‚   β”‚   
    β”‚   └───translations
    β”‚           template.json
    β”‚           
    β”œβ”€β”€β”€quicksaves_a7d319e944b07cfc
    β”‚   β”‚   mod.js
    β”‚   β”‚   mod.js.map
    β”‚   β”‚   
    β”‚   └───translations
    β”‚           template.json
    β”‚           
    β”œβ”€β”€β”€stat-boosts-0.0.2_5d68390288ba00bd
    β”‚       mod.js
    β”‚       mod.js.map
    β”‚       
    └───stats-boost-stability-1.1.0_8a2c397edbc547fb
            mod.js
            mod.js.map
outer jay
#

wtf

#

bug it

placid monolith
#

done

#

Btw, does it make sense to commit the translations/template.json? I'm not sure

outer jay
#

helps you track when things changed i guess

placid monolith
#

lyeedar maybe add these dev deps to the example mod

    "@types/react": "^19.2.14",
    "@types/react-dom": "^19.2.3",

couldn't even get the actions.registerOptionsUI tsx example working without it throwing type errors

outer jay
honest viper
empty folio
#

Is there an api file I can dig into? Is it part of the game-files (or a list of all of the available commands/hooks... Or a way to generate a list πŸ€” )?

I'm trying to figure out the available uses/triggers and see what parts of the game stats are exposed for pre-calculations before character actions - so I can start planning my mod out. daogreeting

outer jay
#

Or just the modapi type for what is directly exposed

#

You can do that in vscode

empty folio
#

Thanks. Guess I should get that installed again. I've been using Vim like a crazy person 🀣

placid monolith
#

the one reason I don't use it for everything, to lazy to configure and manage it... so I just use vscode with vim motions

empty folio
#

I'm not that crazy 🀣
I plan to install vscode and run an instance of SonarQube. Do we have a schema doc I can look at?

empty folio
#

Having an ide linter is convenient

placid monolith
#

you have typescript, you'll get enough static analysis if you use it properly

outer jay
#

typescript type checking will do like 90% of that for you

placid monolith
#

I don't see the point of sonarqube etc

empty folio
#

(and I'm familiar with it)
Static code analysis

outer jay
#

what do you mean 'schema doc'?

empty folio
#

An example of tabs and formatting. Can probably make one from existing mods ThonkCursed

outer jay
#

ah, theres no standards yet πŸ˜„

empty folio
#

But if it's just TS, probably don't need anything special

placid monolith
#

just slap prettier in

empty folio
#

That's the word "style guide"

outer jay
#

i think the example mod has prettier preconfigured?

placid monolith
#

it does

empty folio
#

Nice

#

I read TS at my last job, but I was the CI/CD devsecops guy, so I mostly handled the build pipelines and SonarQube integration. Writing it will be new πŸ˜‹

outer jay
#

ahhhh thats why sonar πŸ˜„

empty folio
#

Yea. It slapped a lot of wrists and pull requests

outer jay
#

typescript will make it hard to go wrong. if it has an underline, fix it! πŸ˜„

empty folio
#

Nice vibe
I'll have to take some time and work through the docs before I have more questions. Don't know what I don't know yet

outer jay
#

thats fair

empty folio
#

This has been most helpful so far daogreeting

outer jay
#

but yeh if you open the example mod, go to index.ts, right click on the modApi and go to type definition you can see the whole mod api

#

oh, i should document my super awesome new image generation plugin

placid monolith
outer jay
#

vscode

#

gives you a sidepanel like

placid monolith
#

lyeeder I don't think there's a way to have persistent mod data not coupled with a save outside of global flags? Need that for settings, flags are fine when it's a number, but if it has to be a string, I don't think there's anything in place?

outer jay
#

you can just use local storage then

placid monolith
outer jay
#

also global flags are save file linked

outer jay
#

theres a docs page on it

#

under guides

placid monolith
outer jay
#

hmmm, maybe I forgot i implemented something

#

lemme go check πŸ˜„

#

oohhhhh

#

yes, i mad global flags

#

why did i do that, thats weird πŸ˜„

#

anyway, yeh local storage is the shout

placid monolith
outer jay
#

its because they are merged into the game flags

placid monolith
#

oh right

#

forgot about that part

placid monolith
#

git rebase breaks symlinks on windows... they're turned into plain files with the path to the target file... lovely

#

probably some mess with git for windows

placid monolith
#

I want to add some GameIconButtons in here, how do I know in a reliable way when this layout changes from this:

#

to this:

#

screen in rootstate is same so can't use that

outer jay
#

the bottom is inside events

#

the other is the rest of the time

#

screen should be event

placid monolith
outer jay
#

the top one is 'playercomponent'

outer jay
#

hmmm

placid monolith
#

printing game state after this has "location" in screen

outer jay
#

yes

#

this is a 'derived' screen

#

ill add it to the mod utils

placid monolith
#

could this be done better?

window.modAPI.injectUI('location', (api, element, inject) => {
  return inject(
    '#backgroundImage',
    <Stack
      id="quicksaveButtons"
      position="absolute"
      zIndex={9999}
      left="230px"
      bottom="75px"
      direction="row"
      spacing={1}
    >
      <api.components.GameIconButton
        title="Quicksasve"
        onClick={() => {
          if (api.hasSave) QuickSaves.makeQuickSave();
        }}
      >
        <SaveIcon />
      </api.components.GameIconButton>
      <api.components.GameIconButton
        title="Load Last Quicksasve"
        onClick={() => {
          if (api.hasSave) QuickSaves.loadLastQuickSave();
        }}
      >
        <LoadIcon />
      </api.components.GameIconButton>
    </Stack>,
    'inline'
  );
});
#

btw, I wasn't expecting I'll be messing around with absolute positions again... lol

#

Slot names for dialogs are the id (e.g. 'combat-victory'). You can find these by inspecting the DOM in dev mode. Slot names for screens match the ScreenType value (e.g. 'combat').
There's no id for this player UI in location and other screens I believe? I could just target that then, in injectUI

#

lol, the buttons appear over even dialogs

placid monolith
outer jay
#

Not ATM. Request it, I didn't think people would want to inject there πŸ˜‚

placid monolith
empty folio
#

Speaking of injecting ui elements? What page is that on πŸ˜…

#

Actually, that code block might be enough ThonkCursed

empty folio
#

In the wiki(git page?) , or the file

placid monolith
#

it's scrollable

empty folio
#

How does it handle the player scaling slider for size? Do I need specific image sizes or does the ui do that on its own based on the bounds of the element?

placid monolith
#

with css properties

empty folio
#

Lovely πŸ˜…

#

It'll be like my high school "programming" class all over πŸ˜‚

empty folio
outer jay
#

That's font size

#

Or should I say, font scaling

#

Everything hooks off it

empty folio
#

It affects the ui elements in the corners too, probably through font, but it ends up covering a couple needle locations when you do

outer jay
#

You can override the theme if you want to

placid monolith
#

much better here

#

lyeeder how do I use game's styling for the tooltips?

#

lol quick sasve

empty folio
#

Maybe an a future iteration I'll change ui colors based on the numerology ThonkCursed
Now I just want to add a drawer style element that opens up and shows the numerology calendar and it's affects, and can close again to make it go away

outer jay
#

I'll probs do a release tomorrow with all these new apis

placid monolith
outer jay
#

The player component override the default styke

#

They make the buttons gold

#

Everything else should be using the default more faded style

placid monolith
#

oh I see

placid monolith
#

lyeeder, the afnm-extract-translations is not able to extract these string into the template.json

Wrote template: C:\Users\user\repos\afnm-mods\packages\quicksaves\translations\template.json

βœ“ Extraction complete!
#

does it not support tsx maybe?

outer jay
#

You need to wrap those in t()

#

Or it won't translate or extraxt

placid monolith
#

I thought it'd do it automatically, given it tracked those strings in the array before

outer jay
#

It tracks arrays specifically on the assumption that those are a more 'useful' source for the string context

#

E.g. in the main game the realm array tells it 'this string is a realm and here's the others' Vs scattered usages throughout the codebase

placid monolith
outer jay
#

Hmmm

#

I'd have to debug

placid monolith
# outer jay I'd have to debug

wait... is this script "extract-translations": "afnm-extract-translations", in package.json important... I had it removed lol

outer jay
#

Lol

#

You mean the translation extraction script?

#

πŸ˜‚

placid monolith
#

hmm not sure how'd I make it work for my mono repo setup, the build script is only present in the root package.json

What's calling extract-translations? Can I do it manually for the package?

#

manually somewhere in here

  const buildPromises = packageDirs.map(async (packageDir) => {
    console.log(`Building ${path.basename(packageDir)}...`);

    await fs.promises.rm(path.join(packageDir, 'dist'), {
      recursive: true,
      force: true,
    });

    await spawnAsync('afnm-extract-translations', [], {
      stdio: 'inherit',
      cwd: packageDir,
    });

    await spawnAsync(
      'webpack',
      ['--config', '../../webpack.base.config.js', '--mode', 'production'],
      {
        stdio: 'inherit',
        cwd: packageDir,
      },
    );

    await copyTranslations(packageDir);

    const zipPath = await zipDist(packageDir);
    if (args.values.copyMod) {
      const package = require(`${packageDir}/package.json`);
      const target = path.join(
        process.env.AFNM_MODS_PATH,
        `${package.name}.zip`,
      );

      console.log(`Copying mod "${path.basename(zipPath)}" to "${target}"`);
      await fs.promises.copyFile(zipPath, target);
    }
  });
outer jay
#

The pre-build calls it

placid monolith
outer jay
#

Oh, the standalone script isn't useful no

#

Just the pre-build

#

So removing that line was fine

#

It's only there so the user can trigger it early if they want to test

#

The script itself is part of the types package

placid monolith
# outer jay So removing that line was fine

so I'm running the extraction script here (in the build script for root package.json)

    await spawnAsync('afnm-extract-translations', [], {
      stdio: 'inherit',
      cwd: packageDir,
    });

extraction still isn't working properly though for some reason, 0 strings extracted

#

does it expect some env or something idk

outer jay
#

Shouldn't do

#

Afaik

#

I guess first question

#

Does it work in the normal setup?

#

Is it only broken in the spawnasync

placid monolith
placid monolith
#
  "scripts": {
    "prebuild": "afnm-extract-translations",
    "build": "webpack --config ../../webpack.base.config.js --mode production"
  }
outer jay
#

Okay well

placid monolith
#
Found 5 source file(s) to scan.

Pass 1: Building string export registry...
Pass 2: Building import registry...
Pass 3: Building name export registry...
Pass 4: Building realm map registry...
Pass 5: Extracting strings...
Pass 5.5: Extracting from xxxToName maps...
  Found 0 strings in xxxToName maps.

Total extracted strings: 0
Template-ready strings : 0

Generating translation template...
  42 unique translatable entries found.
outer jay
#

At least it's consistent

#

42?

placid monolith
#

idk some junk

outer jay
#

Darn

#

Got a repo I can test?

outer jay
#

ah you have to do:

#

an issue with my regexes I guess

placid monolith
#

in the tool itself

outer jay
#

maybe? feature request it. The whole set of scripts are a vibecoded mess so who knows πŸ˜„

placid monolith
outer jay
#

technically the main game needs it

#

but both forums get scraped by my script so it doesnt matter which it goes in to

placid monolith
#

threw it in requests

empty folio
#

is the crossroads window a static asset with a title at the top? how do i use that theme for my injected UI element?

placid monolith
empty folio
#

how do i find out the workshop ID?
I found the window information i was looking for
(also i ran out of tokens. i can't vibe-code any more hahahaha )

placid monolith
#

what workshop id...?

empty folio
#

the one in package.json

#
  "name": "auspicious-days",
  "version": "0.1.0",
  "description": "An AFNM Mod that changes character stats based on Numerology",
  "author": {
    "name": "tristen-sinanju"
  },
  "gameVersion": "0.6.52",
  "packageManager": "[email protected]",
  "afnmWorkshop": {
    "workshopId": "", //This ID
    "title": "Auspicious Days",
    "description": "This mod is intended to implement some basic numerology modifiers to the character. Luck, crafting, and other effects.",
    "tags": [
      "Gameplay"
    ],
    "visibility": "private",
    "previewImagePath": "src/modContent/imagePreview.jpg"
  },
placid monolith
#

personally I don't like it, as having a whole ass workshop description in json is annoying, I'd personally keep the description in a markdown file and use a markdown to steam markup converter in the upload pipeline (or make your own if a good one doesn't exist)

#

once you've uploaded the mod though, id is is in the link for the workshop page, e.g. 3689709015 for:

https://steamcommunity.com/sharedfiles/filedetails/?id=3689709015
empty folio
#

thanks for the info. i'm not really a code writer. i can read it, and generally understand what it's doing, but i'm no good at writing my own 🀣
i write cybersecurity policy, not code AdjustGlasses

jagged parcel
jagged parcel
empty folio
#

i'm used to seeing big json configuration files, so it didn't even catch my eye that there might be a different method. .. but a flat file that's easy to edit wouldn't be a bad idea

#

in linux it'd just be like touch SeamWorkshopInfo or something simple

jagged parcel
#

It's a good idea. Kind of an oversight on my end since the template was worked from my existing mods I threw together and yk, those mods are already near completion and were kind of in a "don't break what already works" stage

placid monolith
#

and it's not hard to write a converter to steam's markup

jagged parcel
#

Is there a MD to bbcode converter/transpiler thing?

#

Would make it easier to have one source of truth for both

#

I don't fancy the idea of having to maintain both a MD file and bbcode

empty folio
#

i understand those words owoYEE

placid monolith
#

just got into doing other stuff, so it's catching dust rn

empty folio
jagged parcel
empty folio
#

it sure is

#

it even works most of the time

jagged parcel
#

Yk my very first mod was me coming here and trying to ai generate a mod as a joke?

placid monolith
jagged parcel
#

It didn't work.. at all

empty folio
#

and look how far we've come πŸ˜„

jagged parcel
#

Then I actually rewrote a working mod from scratch. Which sorta worked! But it was crap. So I did it again. And improved the docs and such I had every iteration. πŸ˜‚

#

Craftbuddy had at least 4 full rewrites. I spent much time banging my head against things till they worked

#

Im hindsight I should have started with a simpler mod

empty folio
#

it's not like mine is exatcly simple either. at least it doesn't need to make decisions or recommendations

jagged parcel
# empty folio and look how far we've come πŸ˜„

Right! Eldergpt spirit ring also started as a meme mod to see if I could entirely ai generate a mod using a template built from what I learned. It used a very early version of the template you're using now, the first few versions were actually entirely ai generated. Then I started sticking my hand in places to improve things, and give it a good context engine, compacting etc. Basically built it like an ai agent, like you would with a coding agent or build your own claw. Still I was surprised how far ai got with the mod on its own

empty folio
#

slightly offtopic... but i wonder how AIRogueLite is doing these daysThonkCursed

jagged parcel
#

That's a thing?

empty folio
jagged parcel
#

Your mod will find greatness

empty folio
#

Introducing AI Roguelite, the world's first text-based RPG where every location, NPC, enemy, item, crafting recipe, and game mechanic is 100% determined by artificial intelligence.

If you've ever played other AI "games" such as AI Dungeon and were frustrated by how they didn't feel like a game, then AI Roguelite might be the perfect game for you…

Price

$14.99

Recommendations

564

jagged parcel
#

Oh it actually uses LLM

#

Not just ai generated

empty folio
#

i registered my novelaiAPI token with it

jagged parcel
#

That sounds kind of cool

#

Does it support BYOK?

placid monolith
#

network issue

empty folio
#

oh yea, i remember the auth loop taking a while earlier . forgot discord was on fire

#

i'd have to look, but i think it can connect to almost any AI api

placid monolith
placid monolith
empty folio
#

yep. looks like it was resolved a little while ago

also, yes. slop+brainrot. good to have a laugh at how rediculous some of the game is 🀣

placid monolith
#

I'm surprised (but maybe not too much lol) some people bought it and actually thought to spend their time on it

empty folio
#

i get bored, and try games. it's not that expensive

#

that's the price of pickles the bbq place down the road... and i got way more replayability than the pickles HAHA

placid monolith
#

surely there are better games you could play instead

empty folio
#

i play those too

empty folio
#

how do i update my mod on the workshop (replace it with the current build)

outer jay
empty folio
jagged parcel
empty folio
#

I got the upload to work from lyeeedar uploader. I need to dig into the script in the mod example to see why it's failing. Made a lot of process once I fixed the game instance path πŸ˜…

jagged parcel
#

The agent would have prompted you to download it otherwise

#

The sibling ../ModUploader-AFNM repo must exist. Run scripts/setup.sh if missing.

#

From the skill file ^

empty folio
#

It did, it just doesn't run through the process. I think moving the workshop info to a new file might have done some things. I pointed it back to the file though, so idk.
afnm-workshop.json on my git

jagged parcel
#

Oh yeah, as you change things around you have to modify things to work together a little

empty folio
#

It's probably called a few places I need to find

jagged parcel
#

It is just a template, so if you figured out a way that works for you that's all that matters

#

I'm going to be updating the template today for the new afnm-types. I'll probably address the workshop description thing

empty folio
#

Nice. I'll have to update my fork and... I think just replacing /src and adding my new root files, and updating package.json should be all I need, right?

jagged parcel
#

Lot's of improvements now. Including having workshop description in it's own place as a single source of truth, updated for 0.6.53, and lot's of other fixes, improvements, and cleaning up:

dd6c3ca β€” docs: deduplicate, consolidate, and soften guidelines across all docs and skills

  • Added Working Principles section (code design, debugging, comments) to AGENTS.md
  • Added lean-docs/single-source-of-truth principle and user notification to doc stewardship
  • Softened rules to suggestive tone where strictness isn't required
  • Removed 4 redundant stub sections from SUPPLEMENTARY_GUIDE.md, renumbered
  • Trimmed afnm-modding skill from 120 to 43 lines
  • Replaced duplicated facts across 7 skill files with cross-references
  • Merged AFNM_MODDING.md changelog into categorized sections
  • Slimmed README agent list, removed EOL entries
  • 11 files, -166 net lines
    68008c5 β€” chore: upgrade afnm-types to 0.6.53 and document new ModAPI features
  • Upgraded afnm-types from 0.6.52-v2 to 0.6.53
  • Documented new hooks (onCreatePlayerCombatEntity, onBeforeCraft, etc.), registerKeybinding, showToast, tooltip components, injectUI sub-slots
  • Fixed inaccurate API paths (addScreen, setGlobalFlag, listSaves)
  • Updated stale version references across all docs
  • 13 files, +69 net lines
    0b89e4f β€” feat: add DESCRIPTION.md as canonical mod description source
  • Added DESCRIPTION.md as single source of truth for public mod copy (Markdown on GitHub, auto-converted to BBCode for Workshop)
  • Added scripts/markdown-to-bbcode.ts zero-dep converter
  • Workshop upload resolves description via priority chain: CLI flag > DESCRIPTION.md > package.json (legacy)
  • Release workflow composes body from DESCRIPTION.md + auto-generated commit notes
  • 8 files, +316 net lines
#

Including a no dependancy MD -> BBCode converter, specifically for steam workshop bbcode.

#

Carried over some guideline stuff to improve agent effectiveness from some of my more serious projects.

placid monolith
#

regex for parsing?? seriously?

#

lol

outer jay
#

love me some regex

jagged parcel
empty folio
#

I stole a script once so I wouldn't have to do regex any more πŸ˜‚

jagged parcel
#

I think regex is fine here though, the output is lossy. Steam Workshop BBCode supports a tiny subset of Markdown, a full AST parser would be structural overkill for a target format that can't even represent half of what Markdown can.. Plus I kept the regexes are individually simple. Each one matches a single, well-defined pattern. None of them attempt recursive, context-sensitive parsing, or anything crazy.

#

I also made sure unsupported Markdown passes through as plain text

#

I couldn't find a good tool to do MD -> BBCode, at least what steam supports so I ended up making that

placid monolith
#

but yes, regex for md should be fine for many cases, it's just a mess to read through it

#

or debug

jagged parcel
#

If you mean the post, parts of it were copy and pasted from the specs I gave it, lol

#

The code it self is 100% LLM

placid monolith
#

yess steam markup is different from bbcode, which is why I never called it bbcode

placid monolith
outer jay
#

mim is an AI model let loose on the internet

#

he is MYTHOS

placid monolith
#

lol

#

oh that makes sense then

#

if mim is the llm model itself

jagged parcel
#

I dont believe in anthropic anymore

outer jay
#

yeh same πŸ™

jagged parcel
placid monolith
#

how can I add a jsx element to HtmlElement?

if I want to directly mess with the element in injectUI instead of using inject() since I want to add my stuff in two places, not just one

outer jay
#

with difficulty πŸ˜„ you need to render it, then re-parent it later

placid monolith
#

I don't think game's react dom is available for rendering to mods?

outer jay
#

probably better to just use fixed positioning to move it ot he same place

#

should be? its just react after all

placid monolith
outer jay
#

probably? I honestly have no idea πŸ˜„

#

what specifically are you trying to do?

placid monolith
outer jay
#

why not inject to each?

placid monolith
#

would need different injectUI but that'd work

placid monolith
#

hmm it's still not good, it doesn't work if I wanted the button to be the first sibling in the container element

#

ideally this would be the first sibling

window.modAPI.injectUI('combat', (api, element, inject) => {
  return inject('#topBarRightButtons', loadQuickSaveButton(api));
});
outer jay
#

ah i see. youd have to reparent and add it to the actual dom probably

#

or grab the element for the row with some sort of element path selector and reverse its order

placid monolith
#

probably not, injection likely happens after the callback has returned the node

outer jay
#

the inject is a function called every time it rerenders

placid monolith
#

hmm

placid monolith
outer jay
#

you might need 'pointer events: all'

placid monolith
outer jay
#

sx={{ pointerEvents: "all" }}

placid monolith
#

works

outer jay
#

this is how the actual game stuff looks

#

with tooltips

placid monolith
#

I was going to do the tooltips soon, so that's helpful

#

maybe in the future if inject could allow for setting the injected element (inside the targeted element in non-inline mode) as the first sibling as well, it'd be nice (or any nth position)

outer jay
#

its a LOT more complex to do though so probably wont be as quick to add

placid monolith
placid monolith
outer jay
#

looks like youve removed the pointer events thing?

#

try wrapping the tooltip in a box

placid monolith
#

hmm

placid monolith
outer jay
#

ah root level in combat probably has pointer events disabled

placid monolith
#

so every screen that I add it to

#

anyways I'll try pointerEvents on box

outer jay
#

no guarantee itll work πŸ˜„

#

i always just use inspect to check if its getting my mouse events or not

placid monolith
#

didn't work

placid monolith
outer jay
#

oh wait

#

:

{
<api.components.GameTooltipBox>
<Typography fontSize="120%">{t('Quick-save')}</Typography>
</api.components.GameTooltipBox>;
}

#

those should be () not {}

#

atm you arent returning anything

placid monolith
#

lol

outer jay
#

because {}

placid monolith
#

lovely stuff

#

is there a hotkey for devtools in devmode btw?

#

I tried all f keys I think

#

and the usual inspect hotkeys from browsers

outer jay
#

no hotkey. but in the dev menu theres an option to open

#

the top left one

placid monolith
outer jay
#

?

#

this thing up here

placid monolith
#

because the button gets covered by the modal dialog

outer jay
#

ah. yeh you need to close the dialogs

#

then reopen dev tools, and reopen the dialog

#

tbh i just permanently play with dev tools open

placid monolith
#

yeh sometimes I've been in situations where I want to inspect the dialog or whatever, but devtools was closed

outer jay
#

well you can always request a keybinding!

placid monolith
#

yeah

placid monolith
#

so I close it sometimes

outer jay
#

change to the console tab

placid monolith
#

ah

outer jay
#

if you have inspect open its CONSTANTLY rerendering the tree

placid monolith
#

where is this in 0.6.53?

#

I don't see it in ModReduxAPI.components

outer jay
#

in the actions

#

and that ui is in the options

#

there will be a mod sectio at the bottom is any are registered

placid monolith
#

interesting, so ModReduxAPI.useKeybinding is obsolete now

outer jay
#

no thats how you USE it

#

so register a keybinding

placid monolith
#

oh lol

outer jay
#

then in your component to use the keybinding add the useKeybinding hook

placid monolith
outer jay
#

yeh

#

heres an example if you want to namespace it too:

useKeybinding(0, { A: () => {} }, false, 'crafting');

#

so whatever crafting.A is mapped to is the key that run the fucntion on A

placid monolith
#

how do I do set useKeybinding once outside of registerOptionsUI (assuming I don't have settings for the mod), or injectUI, since only those give access to useKeybinding

outer jay
#

you cant, it has to be in the react tree

#

so just mount it any time you mount your buttons

#

probably combine them into a shared function

#

shared component sorry

placid monolith
outer jay
#

itll be mounted and available when then particular component is mounted

#

and unmounted once its unmounted

placid monolith
#

hmm oh, damn so only available when the componenet is visible

outer jay
#

you probably should hahve it be linked to be availabel when your new buttons are available

#

so have it always mount that

placid monolith
#

yeah it'll work for my case here, I can just have it alongside the buttons, but if I were not having UI buttons for quick save/load but only hotkeys, no rebinding for me lol

#

unless I want to make make my own key rebinding UI component

outer jay
#

something like:

const QuicksaveButton: React.FC<ModReduxAPI> = (api) => {
    const doSave = () => {
        window.modAPI.utils.showToast("Saved!", 10000, "success")
    }

    api.useKeybinding(0, { "F5": doSave })

    const GameIconButton = api.components.GameIconButton
    return (
        <GameIconButton onClick={doSave}>
            A
        </GameIconButton>
    )
}
placid monolith
outer jay
#

and heres using it:

export const injectPlayerButton = () => {
    window.modAPI.injectUI("player-ui", (api) => {
        return <QuicksaveButton {...api} />
    });

}
#

just noticed im not exposing the option to set context on useKeybinding. Will be in the next release

placid monolith
# outer jay something like: ``` const QuicksaveButton: React.FC<ModReduxAPI> = (api) => { ...

already have it, can add the useKeybinding here, just that it's a function

function makeQuickSaveButton(api: ModReduxAPI) {
  return (
    // TODO: Add keybind key in tooltip `(${key})`
    <api.components.GameTooltip
      provider={() => (
        <api.components.GameTooltipBox>
          <Typography fontSize="120%">{t('Quick-save')}</Typography>
        </api.components.GameTooltipBox>
      )}
    >
      <api.components.GameIconButton onClick={() => makeQuickSave(api)}>
        <SaveIcon />
      </api.components.GameIconButton>
    </api.components.GameTooltip>
  );
}
outer jay
#

yeh that should be fine

#

generally i like to use the function component syntax (React.FC) as it keeps it clearer to read

#

and enforces you dont mess up the return types

outer jay
#

so if you want to say 'this F5 here is different from the F5 used in that other thing'

#

in your case probably not important

#

but if you are using more common keys its useful

placid monolith
#

much nicer

  window.modAPI.injectUI('event-player-ui', (api) => (
    <QuickSaveLoadButtons api={api} left="3px" bottom="140px" spacing="5px" />
  ));
#

But any idea how I can make the FC props have props for top Stack so I don't have to manually define bottom etc...

const QuickSaveLoadButtons: React.FC<{
  api: ModReduxAPI;
  left?: string;
  bottom?: string;
  spacing?: string;
}> = ({ api, left, bottom, spacing }) => {
  left = left ?? '62px';
  bottom = bottom ?? '0px';
  spacing = spacing ?? '0px';
  return (
    <Stack
      id="quicksaveButtons"
      position="absolute"
      zIndex={100}
      left={left}
      bottom={bottom}
      direction="row"
      spacing={spacing}
    >
      <QuickSaveButton {...api} />
      <QuickLoadButton {...api} />
    </Stack>
  );
};

So I could just do?

<Stack id="..." {...stackProps}>...</Stack>
outer jay
#

those are StackProps

#
interface QuicksaveButtonProps {
    api: ModReduxAPI,
    stackProps?: StackProps
}

const QuicksaveButton: React.FC<QuicksaveButtonProps> = ({ api, stackProps }) => {
    const doSave = () => {
        window.modAPI.utils.showToast("Saved!", 10000, "success")
    }

    api.useKeybinding(0, { "F5": doSave })

    const GameIconButton = api.components.GameIconButton
    return (
        <Stack {...stackProps}>
            <GameIconButton onClick={doSave}>
            A
        </GameIconButton>
        </Stack>
    )
}
placid monolith
#

oh yeah I see it

#

{...stackProps} will overwrite preceding properties if any I think? so these as defaults should work

<Stack
      id="..."
      left="62px"
      bottom="0px"
      spacing="0px"
      {...stackProps}
>
#

yeah it works nice

placid monolith
#

not sure how to use registerKeybinding, what to put in .action? The example doesn't work

registerKeybinding({
  action: 'myMod.specialAction',
  category: 'general',
  displayName: 'Special Action',
  description: 'Performs a special action',
  defaultKey: 'F',
  allowRebind: true,
});

Since 'myMod.*' is not a valid action: KeybindingAction

#

action doesn't seem to make sense here, it should've been id: string or something

placid monolith
#

rebinding doesn't seem to work (well the UI works but its change is not reflected in useKeybinding), first I tried just having the default keybind F9 mapped to callback in here, but then I changed it to the action id (registering of which works because I'm calling it in a .js file) which makes the keybinding not work at all, makes sense ig since useKeybinding expects a key, and not action id

const QuickLoadButton: React.FC<ModReduxAPI> = (api) => {
  const id: string = `${MOD_ID}.quickload`;
  const keybindings: Record<string, () => void> = {};
  keybindings[id] = () => loadLastQuickSave(api);
  api.useKeybinding(0, keybindings);
/// ...
};
// imported in index.ts
window.modAPI.actions.registerKeybinding({
  action: `${MOD_ID}.quickload`,
  category: 'ui',
  displayName: 'Quick Load',
  description: '',
  defaultKey: 'F9',
  allowRebind: true,
});
placid monolith
# outer jay Bug plz

in a bit

btw, is this okay? like I'm not sure what's going on with react internals, but setting the showQuicksaveButtons to true/false immediately reflects the change, with the buttons beings visible/not-visible, I just hope it's not calling this callback for the component over and over again? I was expecting that once I change the state, the buttons would disappear/reappear only on changing the screen, not this.

  window.modAPI.injectUI('crafting', (api) => {
    if (!getSettings().showQuicksaveButtons) return;
    return (
      <QuickSaveLoadButtons
        api={api}
        stackProps={{ left: '138px', bottom: '0px', spacing: '5px' }}
      />
    );
  });

When showQuicksaveButtons is false, I intend to default to window.addEventListener('keyup', ...) for keybinds

outer jay
#

The mod settings changing cause a page rerender

placid monolith
#

I see

#

nice

placid monolith
placid monolith
#

wait a minute? why? why require pillar creation when I have the techniques already?

This is a manual I already have btw, Manuals tab, not like some manual preview in sect manual pavilion

#

oh wait I'm dumb

#

the number of slots lol

#

wait lol I posted this in modding

#

well... it's best that way, few people saw this

placid monolith
#

"Straight" sexuality option doesn't disable the same gender choice in "Verdigris House" reminds me... I don't think game's preferences/settings are exposed to mods?

#

So a mod can't make use of the player's specified sexuality, in case they wanted to know it for some reason

outer jay
#

yeh atm no

#

REQUEST πŸ˜„

empty folio
#

Is there a trigger for when you press the button to enter combat or crafting that happens before the time passes, and before onPlayerEnterCombat?

outer jay
#

What do you want to do?

empty folio
#

Use the date information without relying on onPlayerEnterCombat because it happens too late in the stack of commands/calculations

outer jay
#

I think even that's too late

#

Because time advances when you click the explore button

#

Best to track it outside that entirely

empty folio
#

Yeah. I'm not sure what to trigger on to grab the date info though. It needs to persist through the time advance and then recalculate on moves or explores (which it does easily now), but I'm losing the date information for the action because it re-does the date Calc - after the time Calc and before combat

outer jay
#

Hmmm

empty folio
#

I can't just minus 1 it, because if it goes from 1099/30/4 to 1099/1/5 it's totally different numerology result

#

1099/12/31 - > 1100/01/01 would be a more apparent example
26 VS. 4

placid monolith
#

there should be a calendar update action, you could cache the date from there in some way I think

empty folio
#

I can probably just declare a new variable or array to save it in, then pull from until the action ends ThonkCursed

#

But the calendar update is the issue I'm trying to work around.

#

The way I have it now, by the time you enter combat, or travel, or whatnot, you have to grab the day before, or multiple days before in the case of 2 day crafts at the sect, the chaperone missions with the traders, multi-day crafts on your own, etc, etc

placid monolith
empty folio
#

I know. I've got to pc before. It's just an example. I expect you know a lot more examples too Hehe

#

"including, but not limited to" FunnyHaha

#

The chaperone missions are 13 days iirc

placid monolith
#

yeah the escort ones

outer jay
#

Okay idea: add a listener to the selected location dialog that caches the current day

#

Then use that

placid monolith
outer jay
#

I don't think so. Good suggestion though!

#

Reeeeequest

placid monolith
#

hmm... could the player character be referenced by "he/him", "she/her" based on the gender instead? and put an option for the usage of "they/them" in the settings somewhere

I feel like dialogs wouldn't need to be modified too much, or at least no need for duplicates? - "...dialog... la la la {playerPronoun1}... la la la..."???

playerPronoun1 or 2 for he/she/they and him/her/them...

#

or is it going to be more complex than I'm imagining?

#

playerPronoun can be abbreviated to pp for short smug

placid monolith
#

probably some other stuff too

outer jay
#

All the gender pairs would need to become trios

#

Probably not crazy amounts of work though

#

Want to request it?

placid monolith
# outer jay Want to request it?

yeah, I'll write it on a while, it'd be great if it's not too much work

personally they/them language feels very bland to me, when the referenced individual is a known entity and the gender is known

placid monolith
#

oh so just hmm "he/she/they" is probably what you meant by that, the is/are could also be abstracted away into a property that gives the appropriate one based on the current pronoun, so still not much work, just one more variable in dialogues

#

if they're game specific I'm going to add in a request to expose game icon components to mods

outer jay
#

Those are just muicons

#

ContentCopy
SaveAlt

placid monolith
outer jay
#

Huh

#

FileDownloadOutlined,
FileUploadOutlined,

#

Is what I use, but they don't appear in the icon browser

#

I am 2 major versions behind so maybe they removed it from the latest

placid monolith
#

btw, this is a bug right?
#general message

#

another thing, I'm still not able to use keybinds in mystic realm, Esc in battles etc

#

I thought it was fixed

#

...How can I replicate ModReduxAPI.hasSave with just RootState (getGameStateSnapshot)? How is the boolean value determined?

outer jay
#

Redux is only available when a save is loaded. On the main menu it's not mounted

placid monolith
#

in main menu and new game char creation screen

placid monolith
#

so globallly

outer jay
#

Try to read the ReactReduxContext

#

But you have to be inside the react context to do that

#

There's no global way afaik

#

Youd have to request that

empty folio
placid monolith
#

why does onReduxAction have payload now 😭

#

well still not bad, could be useful, but I still need RootState in onReduxActionPayload since I'll be modifying the payload while looking up something in the current state on how to modify the payload exactly

#

there's also this issue #1500017492117033000 message

outer jay
placid monolith
outer jay
#

oh wait

#

im a moron

#

ah theres other broken stuff

#

annoying

#

ill have to do some weirdness with 0.6.54-2 or something πŸ˜„

placid monolith
#

hmm... now let's see if mod keybind feature is working or not

#

registerKeybinding is still scuffed

export interface KeybindingDefinition {
    action: KeybindingAction;
    category: KeybindingCategory;
    displayName: string;
    description: string;
    defaultKey: string;
    allowRebind: boolean;
}
outer jay
#

?

#

in what wy

placid monolith
outer jay
#

ahh

#

hard cast it to string

#

it should work

#

ill update the type though

placid monolith
#

yeah that'd work

#

rebinding is not working

#

useKeybinding still uses the key that's specified in it

#

not the rebinded one

#
  api.useKeybinding(0, {
    F9: () => loadLastQuickSave(api),
  });
#
window.modAPI.actions.registerKeybinding({
  action: `${MOD_ID}.quickload` as KeybindingAction,
  category: 'ui',
  displayName: 'Quick Load',
  description: '',
  defaultKey: 'F9',
  allowRebind: true,
});
outer jay
#

lemme dig in

#

found it

outer jay
#

should fix:
keybindings type
keybindings not working
scroll in options
hasSave in the wrong place
no 'previous state' on payload reducer

placid monolith
#

hmm

placid monolith
#

rebinded keys with useKeybinding that is

#

and window.modAPI.utils.getHasSaveLoaded() returns true in main menu

#

so kinda useless lol

outer jay
#

Hih

#

Urgh

#

Well that's not ideal

#

I'll reopen those

placid monolith
#

Also, for some reason, useKeybinding(0, ...) doesn't work in mysticalRegion screen

#

works in combat

#

if I set priority to 100, it works

outer jay
#

Yeh you need priority 1 or more

placid monolith
#

oh

outer jay
#

Because the dialogue sets priority 1

placid monolith
#

oh example now uses priority 10, I swear it was 0 in there before

outer jay
#

Yeh

#

Try -1

#

I think that should be more reliable

#

But no idea

#

All the ones I've added are 1

#

On mystical region

#

Keybindings are a finiky thing because they have to correctly enable and disable based on dialogs and stuff

placid monolith
outer jay
#

Darn

placid monolith
#

-1 makes it not work in combat either

outer jay
#

Oh well πŸ˜‚

#

Will fix

placid monolith
#

wait a minute, are you telling me if the priority of my useKeybinding is higher than anything else on the screen, even if there's no keybinding conflict, those lower priorty keybinding simply won't work!!?

#

priorty 10 disabled b for auto battle etc

outer jay
#

Yes

#

So you generally use it for disabling lower stuff

#

And every dialog open will context the keybindings inside them with a higher priority

#

So you can't accidentally keypress something under what you are interacting with

#

Generally you want to use priority 0

placid monolith
#

at least getRegisteredKeybindValue works

#

so I'm going back to the simpler world of window.addEventListener

outer jay
#

Probably sensible

placid monolith
#

mod keybinds should probably namespaced by mod name, as in a heading

outer jay
#

Request

#

Or I will forget

placid monolith
#

is it supposed to have duplicate entries like this if the string is in multiple places?

placid monolith
#

you have keybinds in tooltips hardcoded? πŸ˜‚

outer jay
#

From before you could rebind

placid monolith
# outer jay Legacy

probably before there were translations too, because that made me remove t() from my string in Typography thinking the tool is supposed to auto pickup strings in tsx lol