#Help with modding

1 messages ยท Page 3 of 1

sonic stratus
#

it's because of me, btw ๐Ÿ˜‚

#

It didn't duplicate before, but I pestered Lye that I needed it xD

placid monolith
#

btw, should I namespace mods? as in the package name by my name

outer jay
#

It's just about giving enough context so the translation can do it

placid monolith
outer jay
#

The mod name?

#

Oh, I guess maybe?

#

Unless it's an identical name it won't matter

placid monolith
#

what if there's another mod with quicksaves package name?

#

what happens then?

outer jay
#

If it's via steam they will have the mod id

#

So it's fine

placid monolith
#

oh

#

well then it's fine

sonic stratus
outer jay
#

Then you will have clashes

placid monolith
#

I was waiting for a sale on steam (for releasing the mod) lol before buying it again there, but ig I'll just do it soon

outer jay
#

You already have it on itch?

placid monolith
outer jay
placid monolith
#

I bought it

outer jay
#

Oh! Well thank you ๐Ÿ˜„

#

I very much appreciate it!

placid monolith
# outer jay Oh! Well thank you ๐Ÿ˜„

consider allowing anonymized downlaods for the workshop, so itch users can download mods too
currently it's not a big deal as there's not many mods in the first place but yeah

#

terraria has this on, gog users etc can download mods from workshop

outer jay
#

I didn't know that was a thing

placid monolith
#

maybe it doesn't matter if not many people play the game on itch, or if you don't plan to distribute it on gog etc later

outer jay
#

Put a feature request in, I'll dig through the settings tomorrow

placid monolith
outer jay
#

Steam UI is... A thing

#

I don't think a designer has ever even been within a mile of ot

placid monolith
#

where do workshop mods get installed? mods/loaded I assume?

outer jay
#

Yes

#

Eventually

#

Steam puts them somewhere first then I extract them to mods/loaded

placid monolith
#

I see

placid monolith
#

Hmm you're allowing whatever tags on the workshop? Pretty sure you can specify tags that are valid

#

much more controlled than people putting whatever tags in maybe

outer jay
#

I didn't see any real reason to restrict it just yet

placid monolith
#

what's minimumPotential? Gets incremented by .25 each reforge

#

looks like it comes into play when upgrading?

#

minimumPotential (floored) becomes the current max potential on upgrade (hiddenPotential gets incremented by 1 or whatever it should be at according to minPotential's value)

#

shouldn't minimumPotential also take effect on reforge? and not just upgrade?

hollow light
#

minimumPotential is a system specifically linked to upgrading, though its legacy (kinda) now

#

previously when you upgraded, you would lose half of your 'active' stars, and minimum potential was implemented so that upgradeable items would always have a 'minimum' amount of total stars

#

all the items that would last throughout the entirety of the game at least, we wanted them to always have a baseline 'valid' amount of stars for usability, based on the realm

hollow light
placid monolith
#

lol

#

yeah upgrade was adding a star when minpotential is higher than current total potential tier (hiddenPotential + qualityTier)

hollow light
#

so in fact, it IS better to exhaust all the potential before upgrading ๐Ÿคฃ

#

If you could throw that into #1241787390687711313 I'd be ever grateful

placid monolith
#

in a bit

empty folio
#

copilot is dead, long live copilot ๐Ÿ˜›

empty folio
placid monolith
#

lyeeder, how'd I match the string returned from getRegisteredKeybindValue with a KeyboardEvent for a compound keybind?

For eg. can't really match Shift+= returned by getRegisteredKeybindValue easily since KeyboardEvent will have key as +, and code Equal is something but not helpful as there's no mapping of code->key...

#

Is Shift+= format something used by the game? or is it specific to getRegisteredKeybindValue? If it's specific to API, maybe something like code could be used for the returned string instead of like =, so something like Shift+Equal, something that I can actually match against a KeyboardEvent

jagged parcel
#

I absolutely could not. Heck back when the best we had was sonnet 4.1, I hated agentic coding. I would try it a little bit then go back to manual coding

#

PS - I'm curious why you didnt just use something like gemma 4 E4B, should have been both faster and better quality. Maybe you would have been able to fit qwen 3.5 9b instead too, or get decent speeds with gemma 4 26b-a4b + offloading (or Qwen3.6-35B-A3B if youre feeling ambitious)

outer jay
placid monolith
placid monolith
#

wait a minute... why do I have to register anything and modify code for translations? The game should be able to do everything since the filename is the language code

Next steps:
  1. Open .\translations\template.json
  2. Copy it to a new language file, e.g. translations/ru.json
  3. Fill in the translated values for each key
  4. Register the translations in your mod:
       import ruTranslations from './translations/ru.json';
       api.addTranslation('ru', ruTranslations);

outer jay
#

That's fair

#

It's sorta muddled the self-translations Vs providing translations for other people's stuff

#

Bug it

placid monolith
#

where would the 3rd party translations be placed in game folder if they're not being shipped with the mod?

outer jay
#

They'd take the template.json from your mod, translate it, then register using addtrasnaltion

#

That would be its own mod

placid monolith
outer jay
#

No there's an export in the debug menu

#

Should be the same as what's used for the main game

#

Assuming it works lol

placid monolith
#

oh there's a translation app

#

I forgot

outer jay
#

I might even auto-translate mods with larger playerbases myself

#

We will see

empty folio
outer jay
#

Your mod contribution can be the mod-making stack ๐Ÿ˜‚

hidden saddle
#

How's the learning curve with mod making? I don't have much time but I've had a mod I wanted to make in mind for months now.

sonic stratus
#

and we also have docs ofc

#

just read it and you will have 95% of the necessary knowledge

#

and if something is unclear, you can always ask here

empty folio
#

Sentinel successfully caught my crash script, and sonar has a working scan of the repo.
Need to integrate the linting next methinks... And fix directory and git tools in MCP

#

And the llm can use the Sentinel tool to read reports

outer jay
hidden saddle
outer jay
#

Oh that's all 100% doable

#

And the mod docs should cover doing all of those

#

Though I will say for items you can only add items kinds already in the game

#

There's currently no way to add new types

hidden saddle
#

Oh that might be the hard part ๐Ÿ˜…

outer jay
#

What sort of item?

hidden saddle
#

A teleportation item

sonic stratus
#

should be doable

outer jay
#

We already have transport seals

hidden saddle
#

Is durability a thing now?

outer jay
#

But they are linked to a location

hidden saddle
outer jay
hidden saddle
#

But I want it to have charges

#

So I want to see since I have not played the game in a while to see if an item has been added like that

sonic stratus
#

just add a flag with the number of charges

hidden saddle
#

Ok I will probably implement that way

jagged parcel
#

You can also try to ungabunga the mod out with ai and see if it works ๐Ÿ˜‚. You might get lucky

jagged parcel
#

If you can fit it the most capable small model for coding currently is Qwen 3.6 27b

jagged parcel
# hidden saddle Ok I will probably implement that way

If you decide to use ai we have a template made for agentic coding
https://github.com/lemon07r/AfnmAgentModTemplate
If you are a newbie starting out though I suggest using it more for questions rather than implementation and implementing things your self one small part at a time so you don't end up lost in a ton of generated code that you don't understand

GitHub

Template repo for Ascend From Nine Mountains mods with ModAPI-first scaffolding, runtime validation, and Workshop packaging - lemon07r/AfnmAgentModTemplate

placid monolith
#

lyeeder, where's 0.6.55? ๐Ÿ˜  ๐Ÿ˜‚

placid monolith
outer jay
#

Oh I forgot

#

Oops

#

I'll release it in a bit

placid monolith
# outer jay I'll release it in a bit

should probably automate it in a ci, so you'd just need to increment version number (+ maybe tag) for it to publish, and you can have pre commit checks to ensure you increment types version (and tag it) if game's version is incremented

#

not sure how that'd play with nightly builds etc though

outer jay
#

The npm deploy needs a trusted app or something and it refused to work in a GitHub action

placid monolith
#

huh weird

outer jay
#

But maybe I'm just not an expert with it ๐Ÿ˜‚

placid monolith
#

it only shows name and versions for active ones? that's weird... probably because it only does that for extracted ones?

outer jay
#

It should do once it's cached the details

#

After it's been loaded once

placid monolith
#

also my character became a female somehow

outer jay
#

Fffs

#

How is that happening wtf

#

Bug it

#

With anything you can think of

placid monolith
#

still bug it?

sonic stratus
#

yep

outer jay
#

Please yeh

sonic stratus
#

it's a partially known bug

#

it already happened to one person, but we still didn't understand the reason xD

outer jay
#

@placid monolith types are up

empty folio
placid monolith
#

lyeeder, issue
#1500733585890480229 message

jagged parcel
placid monolith
#

lyeeder, a lot more stuff than just qualityTier in an item is persistent (so in savefile), no? That could be mutated...
#1500355843781300294 message

outer jay
#

No?

#

Well sorta. The others are hidden potential and enchantment

#

But neither should conceptually be modified by reforge

placid monolith
placid monolith
#

doesn't matter if in-game reforge does it or not

outer jay
#

That is true. Request ๐Ÿ˜‚

placid monolith
#

another breaking change in next update yipee

#

it's great I've not published the mod where I'm using all this yet

outer jay
#

Should be able to add them to the end so it won't break things

#

Just add more options to configure if desired

placid monolith
#

since I don't think many mods are using it yet

#

or any

placid monolith
#

there isn't a game load hook huh? like

onGameLoad(interceptor: (state: RootSate) => RootState))
#

for mutating state on game load

placid monolith
#

๐Ÿ˜ญ

placid monolith
#

hmm looks like ModReduxAPI.useKeybinding is now fixed

#

and priority -1 works

placid monolith
#

I thought it's supposed to give me the max Qi the player can have, like here

outer jay
#

Ah no

#

That's a little more complex

#

Get realm QI is used for giving QI rewards

placid monolith
outer jay
#

You want getBreakthroughQi * the current realm +3

#

Yeh the doc is wrong

#

I'll expose getMaxQi too

placid monolith
#

Are there any mods using ModReduxAPI.useKeybinding?
Because imo if the api mapped action ids to callback instead, it'd be much easier to understand what's going on

  api.useKeybinding(-1, {
    [`${MOD_ID}.quickLoad`]: () => loadLastQuickSave(api),
  });

rather than mapping of some default key to callback, for which you'll have to go look which keybind it's associated with when you're reading through some source

#

I don't think any on workshop are using it, so if the idea seems fine the change could be done now without much issue

#

Oh yeah I forgot that useKeybinding existed before mod key rebinding... I remember that's why I mentioned about adding a new function that'd have action->callback mapping and .useKeybinding would still exist but not support rebinding

outer jay
#

UseKeybinding is the game one, but I guess so could support providing the action id instead and handle mapping that too

#

Request it

placid monolith
# outer jay UseKeybinding is the game one, but I guess so could support providing the action...

UseKeybinding is the game one
What does "game one" mean? You mean the game also uses a similar api internally for rebinded keys, with default key to callback mappings?

And, should I request to overhaul the .useKeybinding to now use action ids instead of key names, or request for a new api that does it instead? Was thinking since no one is really making use of current .useKeybinding with key name callback mapping, might as well replace it.

#

Btw, another benefit of using action ids instead is that a mod could also register a callback for game's own action (like alternateConfirm etc). Not sure why one would want to do that... but it'd be possible to do it

outer jay
#

As in useKeybind is literally the hook the game uses for all it's keybindings, just exposed to mods too

#

For the request, request it AS WELL. I'll look if the binding is an action first, then if not fall back to assuming it's a key

placid monolith
#

Interpreting the object key as actionId first and with keyName as fallback doesn't seem like a good idea since if a mod registers a keybind with an actionId something like F9, that'd break .useKeybinding for another mod trying to bind to the actual F9 key.

#

If someday I have an actual use case for wanting to bind to game's actions or some other mods' actions, I'll revisit it perhaps

outer jay
#

You'll be happy to know the new inject UI works fully (tested) and supports a ton more positions

#

And completely changed the api

placid monolith
placid monolith
#

is being able to cancel out of animation for "enchantment extraction"/reforging/upgrading intended?

outer jay
#

Cancel out?

placid monolith
#

this one definately seems like a bug, but it behaves better in reforging/upgrading, backing out completely cancels out the process and clicking the button doesn't restart the animation from before like it does in the screencast above

#

that's why I thought maybe it's intended, but given you're confused about what I said, probably not

outer jay
#

Yeh bug

outer jay
empty folio
#

Nice. I'll have to see how that works later.
Stayed up to 3 am again, so no project work today ๐Ÿ˜…๐Ÿค“

#

(I get up at 6 for work ๐Ÿซ )

outer jay
#

You'll have to wait for the next release on it

#

End of the week

empty folio
#

Works for me daogreeting
My new compute card doesn't show up till Thursday anyway
And I still need to evaluate models for roo code

placid monolith
#

could afnm-types be shipped alongside the game build?

#

somewhere in the game folder I mean

#

ig just have the afnm-types/dist/ folder in game folder?
that way someone could just use the local package on the filesystem instead?

#

the only reason I'm saying this is because of the beta branch on steam

empty folio
#

followed link from ./dist/[mod-name]/package.json json }, "devDependencies": { "afnm-types": "0.6.52-v2", ...}

empty folio
#

that's the dist folder you asked for

placid monolith
#

sigh

#

the only reason I'm saying this is because of the beta branch on steam

#

afnm-types for the beta build of the game

empty folio
#

then use 0.6.54-2 instead of 52- v2

placid monolith
#

...

#

afnm-types for beta builds don't exist on npm

placid monolith
empty folio
placid monolith
empty folio
#

i'll probaly track dependencies tomorrow then, and update again before the(my) next build.
i'm still troubleshooting tool-calls on the local LLM ๐Ÿ˜…

placid monolith
#

lyeeder, how does the returned unsubscribe callback for ModAPI.subscribe works?
https://discord.com/channels/1208332427618160660/1501421551944466494

Are you storing the callback passed to subscribe in some Set and then just have something like this?:

function subscribe(listener: () => void) {
  someSet.add(listener);
  return () => someSet.delete(listener);
} 
#

ok yeah

function ILo(e) {
    return NLo ? H9.set(e, NLo(e)) : H9.set(e, () => {}
    ),
    () => {
        H9.get(e)?.(),
        H9.delete(e)
    }
}
#

Hmm I was thinking I'd also like there to be a remove hook function somewhere because I prefer that to storing the unhook callbacks somewhere and call them all while iterating (grouped per optional mod feature), but it'd not work, can't just have one that'd work for all hooks (well you could but that'd be a lot more changes)

and the other way would be adding a lot more members (one for each hook function) under .hook which doesn't seem worth it?

onReduxAction(callback: ...) => () => void;
removeReduxAction(callback: ...): boolean; // whether the callback got removed
// or `offReduxAction`

// usage
const myCallback = (action, prevState, state, payload) => {};
const unhookMyCallback = onReduxAction(myCallback);

unhookMyCallback();
// or
removeReduxAction(myCallback);
#

yeah idk, just having an unsubscribe function being returned is fine ig

placid monolith
#

haha mods that put overflow themselves...

outer jay
#

Easier to just shove onto npm with my existing scripts

placid monolith
placid monolith
outer jay
#

I mean, you can request it..I don't know how to DO it but I can throw an agent at it ๐Ÿ˜‚

placid monolith
empty folio
hidden saddle
placid monolith
#

not sure what's wrong but there's no mod load error UI here...

placid monolith
# outer jay Bug it

I just spent a not so fun amount of time fixing a bug because of this (image) ๐Ÿ˜ญ

For some reason it made me think decorators are applied top-to-bottom, didn't see the damn () after the decorator identifier in the example

...So I had this all along because of that when I wanted the opposite instead

  @singleton
  @FeatureManager.register
  export class SomeFeature extends BaseConfigurableFeature<{
    enabled: boolean;
  }> {...}
outer jay
#

What madness are you building if you are using decorators ๐Ÿ˜‚

placid monolith
#

idk why am I doing what I'm doing

placid monolith
#

if you've got some time of course

outer jay
#

Oohhh I see what you are trying to do

placid monolith
#

don't pay attention to revertChangedItems stuff, that's very early stuff, from before action payload hooks were a thing

outer jay
#

Personally I'd just use an array of interfaces the manager runs over

placid monolith
#

๐Ÿ˜‚

outer jay
#

True ๐Ÿ˜‚

#

Tbh id even toss the classes entirely

placid monolith
#

like with base*feature

outer jay
#

You dont

#

You split the base functionality to the manager

placid monolith
#

oh

outer jay
#

And you enforce the callbacks

#

So it's datadriven

#

If you want to look at examples from afnm look at breakthroughs

#

That does this, defines the shape of the required callbacks that the manager system calls at the right times

placid monolith
outer jay
#

Yeh

#

Data/breakthrough

#

I think

placid monolith
#

I also don't like settings handling as well, currently I'd have to use useState() for each feature in the ModSettings component

outer jay
#

Or harmony

placid monolith
#

hmm ig I'll look how you use useState in the non minified code

outer jay
#

If you have a central manager you can use 1 shared map as the state

placid monolith
#

yeah I was thinking of having one central setting manger per mod, would be easy to just stringify it all and set it to some key in localStorage but it may be bad to serialize the whole thing every time a single option changes

outer jay
#

Eh it's fine

#

I do it every like second for the entire save fike

placid monolith
#

true ๐Ÿ˜‚ ig I worry too much prematurely

outer jay
#

Json conversion in typescript is one of the most optimised bits of it

#

Turns out websites do it a lot ๐Ÿ˜‚

placid monolith
#

injectUI update is very nice, can even find the element to inject into more granularly than even what css selector would allow

jagged parcel
#

Am I safe to update the mod template yet, or will there be a new modtypes tomorrow? ๐Ÿ˜‚

placid monolith
#

so in a day or two?

jagged parcel
#

I had a feeling it was soon

outer jay
#

Saturday mornin

placid monolith
#

wait a minute...

#

this is turning all files to crlf?

# Auto detect text files and perform LF normalization
* text=auto
#

I thought it was supposed to be the opposite

#
warning: in the working copy of 'packages/nozwock-tweaks/translations/template.json', LF will be replaced by CRLF the next time Git touches it
#

oh auto

#

damn

#

or rather eol is not mentioned

#

sigh... the normalization commit is not going to be pretty

#

this is what I get for using windows for a while

#

ah no, I think it might only be talking about the working copy, and not the files in repo

empty folio
jagged parcel
#

Nice haha

empty folio
#

I'm pricing out my next workstation... Wonder if I can get a loan ๐Ÿค”

placid monolith
#

I need to be able to stop combat screen mid battle at some point, or on using some consumable (pill/item), move to some other screen, and then resume the battle some time later with changed combat state based on some criteria (enemies' state like hp, buffs, etc)

how'd I do this?

#

don't think it can be done currently?

empty folio
outer jay
#

What are you trying to do?

placid monolith
outer jay
#

Yeh ATM combat is all controlled in react state

#

You'd have to do something crazy like mims fiber hackery

#

As none of it is exposed to mods

placid monolith
#

it's fine if I can just get a copy of combat state, cancel combat, show my screen (or game's screen), and then restart combat screen with the copy of the state I have

outer jay
#

Not currently possible

outer jay
#

You'd have to request it

placid monolith
#

so I can request for them too

outer jay
#

Only combat. It was split to optimise it

#

React is faster than redux state

placid monolith
#

another annoying thing is that I can't start a GameEvent chain if the player isn't already in my screen (since that api is only in ModReduxAPI), so can't from combat screen

outer jay
#

Combat takes precedence over events

#

But as for the starting the event, you can do it from a Inject button

placid monolith
#

should I make a new bug post?
#1499596249270063195 message

placid monolith
# outer jay You'd have to request it

I wrote it but I feel like it'd be messy, require too many changes and still kinda not work

Even if there was an api to store combat state and cancel the combat, which I could resume/restore later after running my events via fake injectUI... no idea how the GameEvent chain which the initial battle may be a part of will be preserved and won't be messed with...

#

all this for a stupid joke mod ๐Ÿ˜‚

placid monolith
placid monolith
#

I didn't check all the unhook callbacks, but at least for the one I checked rn it works, so that's great

#

and got around to making "features" just objects instead doing the whole classes mess

#

much better I think

Object.values(patches).forEach((patch) => {
  patchManager.tryEnable(patch);
});
if (value) {
  patchManager.enable(patches.preventItemConsumption);
} else {
  patchManager.disable(patches.preventItemConsumption);
}
outer jay
#

Very clean

placid monolith
#

how do I get display name for an item? displayName seems like what I'd want but it's undefined... so this instead?

const t = window.modAPI.utils.t;
const itemNames = Object.entries(window.modAPI.gameData.items).reduce(
  (acc, [name, item]) => {
    acc[name] = t(name);
    return acc;
  },
  {} as Record<string, string>,
);

I'm not sure if every item name (id) has a translated string or not

#

okay the t thing is not working for some item names like Blueprint: ...

#

maybe some others too

outer jay
#

Displayname is an override, so use e.displayName ?? e.name

placid monolith
#

ok yeah that works t(item.displayName ?? name)

placid monolith
#

JSON.stringify doesn't serialize Set...

#

sigh

placid monolith
#

...๐Ÿซ 

JSON.parse(item, (key, value) => {
  if (
    typeof value === 'object' &&
    Object.keys(value).length === 2 &&
    value.__type__ === 'Set' &&
    value.value !== undefined
  ) {
    return Array.isArray(value.value)
      ? new Set(value.value)
      : new Set();
  }
  return value;
}),
// ...
JSON.stringify(this._cachedConfig, (key, value) => {
  if (value instanceof Set) {
    return { __type__: 'Set', value: Array.from(value) };
  }
  return value;
}),
keen mural
#

How do I get a reference to the live instance of the class that contains all the data of the main chatracter, so that I can modify them live? I'm basically trying to create an editor mod that can mod the main character's (at least for now) data (stats and everything else that may make sense to be able to modify).

outer jay
#

thats the player from the redux state

#

if you are making a ui itll be available through a selector

keen mural
#

it's called "player" then?

outer jay
#

player.player

#

the player, in the player slice

placid monolith
#

it's only for reading (useSelector)

outer jay
#

yeh use the reduxapi.actions.updatePlayer to edit after

keen mural
#

ok, thanks. I'll try that

placid monolith
#

hmm redux seems to be using immer internally, so I'll use it too ๐Ÿ˜‚
why bother writing this spread operator mess

#

not fun as objects get more and more nested

keen mural
#

it seems to work well. I'll see what I can add over time.

outer jay
placid monolith
#

hmm isn't there a window.structuredClone already?

keen mural
#

regarding combat stats, how can they be accessed through the player class?

outer jay
#

What are you looking to do? As that changes things

keen mural
#

yes, they are derived, but they could be changed directly through the rawstats field of the pill mod I did the other day. Insn't there something similar to access those stats directly through the player reference? otherwise how can that pill change them?

outer jay
#

That's layered on

#

Pills are one of the sources that all get combined to make the combat state

#

Others are equipment, breakthroughs, backgrounds

keen mural
#

and through player those layers can't be accessed?

outer jay
#

no, those are other slices

#

again, what are you looking to do

#

just READ the stats?

keen mural
#

no, I'm still talking about the editor. I'm trying to add more stats that can be changed through the editor. the combat stats in this case. it can already change some of them (maxhp, for example, but still not most of them.)

outer jay
#

then maybe look at the:

onCreatePlayerCombatEntity

hook

#

it lets you intercept the combat entity any time its crated and change its values

keen mural
#

ok, I'll try that. Thanks!

keen mural
#

what is the function called when an entity, like the player, consumes a pill?

outer jay
#

On consume item I think

keen mural
# outer jay On consume item I think

Is that the function that handles the event of the pill consumption in general or is it actually the function that apply hte stat changes that would result from the consumption of the pill?

outer jay
#

No that's the in-combat one

#

Applying changes to co bat state

#

There isn't an exposed one for the inventory items, other than listening to the redux action directly

keen mural
#

maybe I didnt explain this correctly. Basically I need to command the player entity to consume a pill of my choosing. what function would I have to use to do that?

outer jay
#

A stat pill right?

#

You can just modify the player entity and the inventory directly

#

Add it to the player and remove from inventory

keen mural
#

Basically, what I'm doing is still related to the editor. The other way of editing combat stats didn't really end up being successfull (meaning I still don't know how to do it right), but since I saw that I can successfully edit those same stats with a modded pill, what I'm trying to do is to create a temporary hidden pill with the stats I set through the editor and then forcefeed that to the character I'm editing (currently only the player is supported). it's a roundabout way of editing combat stats.

outer jay
#

Ah that will sorta not work

#

The stat pills register the pill name and count, then look it up from the item registry to apply the stats

#

You cant have a temporary one

keen mural
#

allright, that's not really a problem. I can temporary change an existing pill and then restore it.

outer jay
#

No you misunderstand

#

It's going to need to look it up EVERY time combat runs or a tooltip is shown

#

Because combat stats are derived

#

What didn't work about the interceptor?

keen mural
#

so, it basically always counts how many pill of am certain type have been consumed and only then it temporarily updates stats accordingly?

keen mural
#

allright, what if I create an hidden item that remains and always have the same stats and simply give the ability to accumulate a certain amount of them through the editor, showing how that would change the relevant stats?

outer jay
#

Yeh that's work

#

But feels like a MASSIVE hack ๐Ÿ˜‚

keen mural
#

yeah, I know, but it's still not clear to me how to do it the other way you talked about. the 0one based on onCreatePlayerCombatEntity.

outer jay
#

To do it, register the item using add item, and modify the player entity to add to consumedStatPills

outer jay
#

Let's you change anything

keen mural
#

If I use the method with OnCreatePlayerCombatEntity, will I still be able to see the updated stats on the character window? Or is that called only at the beginning of combat?

outer jay
#

Yes, the output of that is what populated the stats window, tooltips, and anything else that uses combat stats

keen mural
#

could it be that, when I use OnCreatePlayerCombatEntity, I still have to take a reference to a snapshot? Maybe something like snapshot.player.playercombat or something like this? Because, otherwise, the changes I make to the fields don't actually apply.

outer jay
#

You need to return the new entity

keen mural
#

In theory I do that

outer jay
#

Got some code to share?

keen mural
#

First I'm gonna try a couple of other things and then, if I can't figure out what's the problem, I'm gonna unfortunately annoy you again by asking to check my code!๐Ÿ˜ฉ

outer jay
#

That's alright! Just note it will be in like 8 hours when I awake once more

keen mural
#

no problem, I'm not on a schedule for these changes.

placid monolith
# outer jay Very clean

it was... until I wanted Patch type to allow additional properties (for patch state and helpers) besides the ones mentioned in the interface ๐Ÿ˜ญ

// doesn't work, can't have addional properties in Patch
const patches = {...} satisfies Record<PropertyKey, Patch>;

// works T_T
const makePatch = <T extends Patch>(patch: T) => patch;
const patches = {
  patchName: makePatch({
    ...
    someOtherProperty: {},
  }),
};
#

There's this too but then all other properties will have type unknown which isn't great

Record<PropertyKey, Patch & Record<PropertyKey, unknown>>
placid monolith
#

I forgot a default case return payload in onReduxActionPayload

Was wondering why the game was breaking so bad when here I am dropping all the payloads ๐Ÿ˜‚ (or well replacing all payloads with undefined)

keen mural
#

How does cultivatorResistance work, when compared with fistResistance, blossomResistance, etc.? Does cultivatorResistance work for any kind of damage or only for "non-typed" damage?

outer jay
#

It's for all damage

#

It's applied to scale cultivator hp to numbers that look like the players but still have them match the 'effective hp' of monsters

placid monolith
#

I set qiDroplets to 0 in combat/initCombat
But it's being reset to 17 which is what I had before battle, where is this 17 coming from?

return produce(state, (state) => {
  if (state.combat.player) state.combat.player.qiDroplets = 0;
  state.player.player.qiDroplets = 0;
});
#

is it window.modAPI.combat.getCombatState()? but .combat is undefined on combat/initCombat so I can't exactly set combat state then

#

hmm ig I could use window.modAPI.hooks.onBeforeCombat instead for modifying player state before battle

placid monolith
#

huh new ui

sonic stratus
#

but mb better to move it to the left side

sonic stratus
placid monolith
sonic stratus
#

at work atm xD

outer jay
#

???

#

It appears in the middle and flies over

sonic stratus
placid monolith
outer jay
#

Yes

#

Have you got examples where it breaks down?

#

Even the most expensive example I had seemed to align right

placid monolith
#

no just weird it's placed in center covering portraits

outer jay
#

Yeh it's fine

#

Only appears on that one step anyway

sonic stratus
outer jay
#

It's less satisfying on the left

#

In the middle its more ... Oomph yaknow

placid monolith
#

also easy to notice if it's in center, at the cost of covering portraits

sonic stratus
placid monolith
# outer jay It's less satisfying on the left

what if there are many items given (even if not done in game, a mod could be doing it) in a dialogue? would it just extend horizontally filling the screen? maybe it should be wrapped at a certain width

outer jay
#

Yeh I think it does

#

Though TBF I only tested with 8 items max

#

But that looked fine

placid monolith
#

hmm is the mod uploader looking for a package.json for mod metadata and defaulting to something if it's not found?

outer jay
#

Probably yeh

#

Feel free to poke around the source of that if you like, it's open source

placid monolith
# outer jay Probably yeh

now that I think about it, the uploader can't exactly run the mod in order to get metadata via getMetadata

#

hmm, why did you do metadata via an exported function instead of package.json or something?

We'd also be able to see latest metadata (version) in the "Mod Manager" ui in that case instead of showing cached metadata

outer jay
#

Feel free to submit a pr! It's not exactly a robust design ๐Ÿ˜‚ I only threw it together because steam doesn't provide a built in way

placid monolith
#

steam does have something, you can slap in arbitrary metadata to a workshop item iirc, so json string or whatever

outer jay
#

Steam has a mod uploader?

placid monolith
placid monolith
#

you can attach arbitrary metadata to a workshop item during upload

outer jay
#

Oh yeh, the mod uploader is a wrapper for that

placid monolith
outer jay
#

???

placid monolith
# outer jay ???

confused about what exactly? for eg. you could query for all workshop items' attached metadata without having to download any mod, and use that info to build a UI showing all the mods and option to download/subscribe mods of choice

outer jay
#

How is that relevant to the mod uploader?

placid monolith
#

it isn't ๐Ÿ˜‚

#

since the mod is already downloaded

outer jay
#

Very lost ๐Ÿ˜‚

placid monolith
#

but it's not great as it doesn't do anything for local mods

outer jay
#

The assumption is the mod itself is more valid than the cached data

placid monolith
#

and the mod uploader needs to get that metadata from somewhere, making the whole thing kinda moot, since if we already have a system (like let's say a bundled package.json) where the uploader can get the metadata without having to run the mod, so can the game then

#

why am I even saying stuff that doesn't matter ๐Ÿ˜‚
tldr, the metadata system needs to be updated to fetch it from some bundled json file, whether it be package.json or something else, that'd fix the "issue" of using old cached metadata in the UI

#

something like modinfo.json

{
    "name": "Mod Display Name",
    "version": "1.0.0",
    "targetGameVersion": "0.6.58",
    "authors": "authorA, authorB, ..., & authorZ",
    "description": ""
}
#

would need to update targetGameVersion manually but I don't think it's a big deal

outer jay
#

Quite possibly. Feel free to make a pr? Or put in a request (but it'll be a while till I do it)

placid monolith
outer jay
#

But it should be automated as part of the build

placid monolith
#

oh I think you were talking about the mod bundle build itself

#

I thought it was about uploader for some reason

#

hmm webpack/build script can import afnm-types, and so version can be retrieved from GAME_VERSION

placid monolith
#

does the character creation dialog have an inject ui slot name?

#

hmm yeah nvm, new-game-character-creation

placid monolith
placid monolith
#

it never returns null

#

even in main menu it just returns base state

outer jay
#

ah

#

bug time!

placid monolith
#

now don't go making it return null in main menu ๐Ÿ˜‚

#

I actually need that, just remove null return type

outer jay
#

return null always

#

thats what you wanted

placid monolith
#

Where is the data set by api.actions.setModData stored? Somewhere in RootState?

outer jay
#

yes under mod

placid monolith
#

Am I missing something? Because I can't think of a good reason why these redux dispatch wrappers (setModData, updatePlayer, etc) need to be limited to ModReduxAPI?

outer jay
#

because otherwise they cant be save specific

placid monolith
outer jay
#

dispatch isnt available outside the redux tree

#

trying to access it would crash the game

placid monolith
outer jay
#

its managed by react

placid monolith
#

I think you mentioned this before, I just forgot ๐Ÿ˜‚

placid monolith
#

why's id required in a GameDialog?

outer jay
#

To add slots

#

For inject ui

placid monolith
#

is there a way I could get the character id from a loaded save, the {forename}_{surname}_{createdAt} or guids (save filenames in saves/)?

#

I need to know if a loaded save belongs to a specific character/playthrough

outer jay
#

Sure, request it!

#

But why not just bake that into mod data?

#

Or flags?

#

Given players can restore saves and that will change the ids

placid monolith
# outer jay But why not just bake that into mod data?

I wanted to allow enabling mod per character. With per save, if a previous save is loaded (quickload etc) after the mod was enabled in a recent save, the mod would need to be enabled again (and all config would be reset). Thought it'd be better to do it per character because of that

placid monolith
#

the guid for playthrough/char save in saves/ doesn't change

#

nor does createdAt in save metadata

outer jay
placid monolith
#

only for the save the mod was loaded in and future saves

#

ik this is somewhat of an edge case

outer jay
#

Yeh so if it isn't 1, assume it's off?

#

Oh wait

#

I see if someone is going back in time

#

Yeh that's pain lol

#

I guess you can just hook it off the created at and name manually?

#

That should be in the state

placid monolith
#

yeah, config would be lost and all that, I was thinking of storing config globally in localStorage but grouped by character ids

#

so different config for different character

placid monolith
#

how does the game know a savebackup I've loaded is a backup of a save (named by guid) in saves/?

#

oh right

#

so forgetful, I had just asked for it a while ago

#

If I could get the save metadata in onLoadGame or something, ig that'd work?

outer jay
#

Should do yeh

placid monolith
#

oh wow nvm

#

it's in rootstate already

#

in newGame

placid monolith
#

damn, wasted quite some time reading up on jj that I stumbled into a while ago

Kuba Martin

Jujutsu (jj), a new version control system written in Rust, has popped up on my radar a few times over the past year. Looked interesting based on a cursory look, but being actually pretty satisfied with Git, and not having major problems with it, I havenโ€™t checked it out.
That is, until last week, when I finally decided to give it a go! I dive...

#

fortunately or unfortunately, I'm not too annoyed with git rn to give it a try

outer jay
#

The ONLY issue with git is working with non-diffable assets. Everything else it's perfect for what it does

placid monolith
#

image assets? and by diff, do you just want git to show prev and current image side-by-side like how github does it?

outer jay
#

I mean if you have say an asset for Maya, only one person can work on it because you can't merge the changes. Got has no way for someone to say 'im working on this, don't touch it'

#

Perforce / SVN has the ability to 'lock' a file and it's marked as locked across all branches

#

So you know

placid monolith
#

it doesn't seem like too big of a deal if same asset is changed across different branches, will just have to decide which one ends up as the final asset

outer jay
#

It's critical for teams that work on that sort of stuff

#

That's why perforce is such a titan in the gaming industry

placid monolith
#

ig if the team is too big, yes, that makes sense
for small teams, that stuff could just be communicated

outer jay
#

Communication

#

The dream

placid monolith
#

how are you handling assets for the game? git lfs or something else?

hollow light
#

i can say with absolute certainty, if i leave a branch open too long im going to go through a dark souls level boss determining which bits of current and which bits of incoming need to be preserved or dropped

#

nightmare nightmare nightmare

outer jay
placid monolith
#

why's this an issue?

window.modAPI.hooks.onNewGame((intent) => {
  return produce(intent, (intent) => {
    this._tryLockStats(intent.player);
  });
});
// ...
_tryLockStats(player: PlayerEntity, state?: Readonly<RootState>): void {
  const config = saveModConfig.tryGetValue(state);
  if (!config || !config.modEnabled) return;
  for (const [stat, it] of Object.entries(config.lockedPhysicalStats)) {
    if (it.locked)
      player.physicalStats[stat as PhysicalStatistic] = it.value;
  }
},
#

immer should've made a copy of intent, mutating player should be perfectly fine??

#

I'm doing the same thing in other hooks, it's just a problem in onNewGame for some reason

outer jay
#

Are you sure you are doing a deep copy?

placid monolith
#

immer is supposed to do that no?

outer jay
#

I wouldn't trust it to no ๐Ÿ˜‚

#

Id always do it myself

#

Just to be sure

placid monolith
#

What I don't understand is that why is it not consistent with the issue at least, why only in onNewGame ๐Ÿ˜‚
others hook also give readonly frozen objects

outer jay
#

Most hooks are pre-deep cloned by me

placid monolith
#

So have I been really living in the illusion that immer does deep copy...

outer jay
#

Maybe? I've never looked deep into it. I just throw deepclone all over the shop and call it a day

#

Wasteful yes

#

But eh

#

It's fast enough lol

placid monolith
#

immer is being weird

window.modAPI.hooks.onNewGame((intent) => {
  intent = cloneDeep(intent);
  this._tryLockStats(intent.player);
  return intent;

  // This still has the same error about trying to mutate readonly props
  // :/
  return produce(cloneDeep(intent), (intent) => {
    this._tryLockStats(intent.player);
  });
});
#

only the former works

placid monolith
#

you don't clone the result of onNewGame callback before mutating it

#

but immer freezes modified objects in the callback, so it fails because you're trying to modify readonly props

#

You can reproduce the issue like this

window.modAPI.hooks.onNewGame((intent) => {
  Object.freeze(intent.player);
  return intent;
});
hidden jewel
#

What is the call for adding a given buff to a condensation art, like the Cycle of 9?

outer jay
#

You need to replace the whole art

hidden jewel
#

Ah, it isn't just a call function for 'add buff: Cycle of Nine' then?

#

Since we aren't getting the nonminified update until LF I'm having difficulty visualising it

outer jay
#

There is not a function no

hidden jewel
#

ah, damn

#

Trying to fix broken mods atm

#

The Incandescent Nexus mod got borked at both the qi condensation stage and I think at the core formation stage but I'm not sure about that one yet

#

And Eldynn hasn't posted since Christmas

outer jay
#

I think it should still work. Just be 'less good'

hidden jewel
#

The CF one runs off the page in a way that worries me but I have no ability to judge yet, esp. since each of those breakthroughs stack on top of one another.

#

I saw that you were willing to provide a snippet of the nonminified code for another specific section- could I get the same for the qi condensation methods & their buffs?

outer jay
#

Sure gimme a sec

hidden jewel
#

thanks I appreciate it

outer jay
#
export const cycleOfNineArt: CondensationArtItem = {
  kind: 'condensation_art',
  artName: 'Cycle Of Nine',
  maxDroplets: 30,
  statChange: {
    dantian: 1,
    muscles: 1,
    flesh: 1,
    eyes: 1,
  },
  charismaMult: 0.8,
  lifespanMult: 1,
  patternBg: pattern,
  patternOpacity: 0.2,
  combatBuffs: [
    {
      buff: {
        name: 'Cycle Of Nine',
        icon: icon,
        canStack: false,
        stats: undefined,
        tooltip:
          'Each time you consume a <name>Qi Droplet</name>, gain <num>1</num> stack of <name>Cycle Of Nine: Resonance</name>.',
        triggeredBuffEffects: [
          {
            trigger: 'consume.qiDroplets',
            effects: [
              {
                kind: 'buffSelf',
                buff: {
                  name: 'Cycle Of Nine: Resonance',
                  icon: icon,
                  canStack: true,
                  stats: {
                    power: {
                      value: 0.1,
                      stat: 'power',
                      scaling: 'stacks',
                    },
                  },
                  stacks: 1,
                },
                amount: {
                  value: 1,
                  stat: undefined,
                },
              },
            ],
          },
        ],
        stacks: 1,
      },
      buffStacks: {
        value: 1,
        stat: undefined,
      },
    },
  ],
  name: 'Cycle Of Nine Art',
  description:
    'A condensation art developed in the Nine Mountain Sect, that allows for the cycling of Qi in a fashion that promotes <name>Qi Droplet</name> formation and storage. Cultivators who break through using this art find their dantian greatly expanded, allowing them to utilize the droplets in devastating displays of destruction.',
  icon: icon,
  stacks: 1,
  rarity: 'resplendent',
  realm: 'qiCondensation',
};
#

and the other two buffs:

{
        name: 'Distilling Furnace',
        icon: icon,
        canStack: false,
        stats: {
          dropletBoost: {
            value: 50,
            stat: undefined,
          },
        },
        stacks: 1,
      }
{
        name: 'Eternal Immolation',
        icon: icon,
        canStack: false,
        stats: {
          excessDropletsCost: {
            value: 30,
            stat: undefined,
          },
        },
        stacks: 1,
      }
hidden jewel
#

I dont think the other two sent in their entirety

outer jay
#

yeh i just sent the buff

#

the rest is essentially the same

hidden jewel
#

Ahhh the rest can be called yeah I see it now

#

Thank you!

#

Now, time to see if I can reference a mod and make a proper patch or if I have to dirty edit

#

You think I'm above this

#

I know I'm a hack when it comes to code

#

My only claim is getting the job done(ish)

#

that ish carries so much heavy lifting

outer jay
#

if it works how you got there doesnt matter

hidden jewel
#

Yes but a patch would be much cleaner

#

and I think I should be able to go about it the same way I did my crystal pressure pill

#

I just don't know how to call a separate mod in as a dependency instead of the base game

outer jay
#

once a mod is loaded all its assets are in the same maps

#

so you need to ensure your mod loads AFTER the parent one

hidden jewel
#

ahhh so I just need to make the call and have my mod loaded after ye

outer jay
#

then you can grab stuff it makes by name

hidden jewel
#

that's much easier

#

I was worried it was going to be some arcane Skyrim nonsense

outer jay
#

as for doing that, i 'think' i made a load order dragging thing but im not 100%. i might need to add a 'depends on' field to allow ordering

hidden jewel
#

welp one way to find out

#

oooo VS got an update, now I get to see a cute little dotted loop after npm install

hidden jewel
outer jay
#

its in the latest types, why?

hidden jewel
#

I wanted to just go newArt.combatBuff the same way I would like physicalStats

outer jay
#

you should be able to yeh

hidden jewel
#

wait

#

would my baseline just be outdated, I need to grab a new copy of the example mod?

outer jay
#

you need the types for 0.6.59

hidden jewel
#

right still using old afnm example mod download

#

almost certainly does not call the newest types

#

how dare my old isolated files not update automatically

#

@outer jay the afnm example mod download is flagging antivirus

#

is there a file in there that's just making microsoft be petty?

outer jay
#

quite possibly

#

its full of files ๐Ÿ˜„

#

but you can just update the types

#

no need to pull everything if you dont want to

hidden jewel
outer jay
#

very unspecific

hidden jewel
#

more specific

outer jay
#

it removed the whole zip?

#

weird

hidden jewel
#

yes

#

goddamn I see the edits in real time

#

oh that worked!

#

Thank you!

placid monolith
#

could have something like that for afnm too

placid monolith
placid monolith
hidden jewel
#

aaaaand done

#

The dependency mod loader seemed to work perfect in testing @outer jay

#

So we have confirmation now that we can make dependent mods

outer jay
#

Mind making a featurerequest to add the baking in of dependencies

#

Or do you mean it already works

hidden jewel
#

Already works

#

confirmed on my end no sweat

#

lemme grab you a pic

#

I decided to send several pics

outer jay
#

But doesn't that require it to happen to load in the right order?

#

Or did it auto-sort

#

Or I guess rely on the user to sort them

hidden jewel
#

I can just say 'load this below the Incandescent mod' as I did in the upload

outer jay
#

It works for now

#

Maybe in the future I'll add the dependency thing to auto sort

#

One less thing to do! ๐Ÿ˜‚

hidden jewel
#

yeah you've already got a mod loader in there, that should be bottom of the list of priorities

#

if it works, new things and things that don't work always take priority

placid monolith
#

oh the order thing? that it works as expected?

placid monolith
hidden jewel
hidden jewel
#

Gonna be so mad at myself if my problem this entire time was a missing comma...

#

nope okay so I'm actively messing up then

#

Right, so I'm trying to call in the new prismatic Pearl Core Breakthrough and add the social stats of 2 artefacts & 2 talismans back in, but I'm having some difficulty having the call recognized

#

Here's what the original code is calling:

#

And this is the section in specific that I'm trying to pass along to it

#

Am I just hooking into the wrong area, or is there something more fundamental that I'm overlooking?

#

I tried hooking into 'prismaticPearlCoreBreakthrough' instead but that caused errors in loading the mod.

outer jay
#

so id console log inside your mod to see what it actually contains

#

e.g.

console.log(window.modAPI.gameData.items.filter(e => e.kind === "condensation_art"))

hidden jewel
outer jay
#

as in to look at what the data actually looks like

#

before editing

hidden jewel
#

How would that function if my mod is calling from a separate mod?

#

It doesn't have visibility to the other mod until gametime is running

outer jay
#

yes, so it will console log at runtime

#

and you can see it in the dev console

hidden jewel
#

ohhhh I didnt realize there was a dev console

#

I thought you meant in the VS Code console

#

(which had me confused bc I thought you could only run at compilation in ts)

outer jay
#

you havent been developing with devMode on?

#

damn hard mode

hidden jewel
#

I've been fighting hard

#

there's a reason I didn't update my mod for CF until I reached CF

#

how do I turn on devmode?

outer jay
hidden jewel
#

yeah that one's on me

#

I recognize you were just saying this as an example but for reference

outer jay
#

oh yeh its a map ๐Ÿ˜„

#

Object.values(window.modAPI.gameData.items).filter(e => e.kind === "condensation_art")

hidden jewel
#

Not sure if I'm hunting wrong

outer jay
#

kind is the item kind

#

e.g. clothing

#

you want name

#

also for this id remove the filer

hidden jewel
#

ahhh yeah so that's gonna be b b name

outer jay
#

just print ALL the coreFormation ones

hidden jewel
#

fair

#

okay so that's REALLY interesting

#

It looks like I'm passing it along correctly

#

So something must be overriding it

outer jay
#

ah 1 sec

hidden jewel
#

ah am I missing something that would be obvious in the nonMinified code?

outer jay
#

you need to call addBreakthrough again

#

so it overrides and regenerates

#

i think

hidden jewel
#

So something like this?

#

Though I think I need do do the whole 'find name' nonsense again

outer jay
#

no actions.addBreakthrough

#

oh wait

#

okay, so i made the core formation breakthroughs WAY more complex ๐Ÿ˜„

hidden jewel
#

Yes

#

Yes you did

outer jay
#

i probably broke modding them

hidden jewel
#

They have been...rough ๐Ÿ˜„

outer jay
#

because heres how it looks

export const energisedPearlCore: Breakthrough = {
  requirements: [
    (args) => ({
      done: (args.breakthrough.coreFormation?.compressions ?? 0) >= 9,
      preview: (
        <GameTooltip
          provider={() => (
            <GameTooltipBox>
              <TooltipLine>
                {parseTooltipLine(
                  t(`Compress your core <num>9</num> times at <name>Compression Altars</name>`),
                )}
              </TooltipLine>
            </GameTooltipBox>
          )}
        >
          <Box display="flex">
            <Typography fontSize="120%">
              {parseTooltipLine(t('<num>9</num> core compressions'))}
            </Typography>
          </Box>
        </GameTooltip>
      ),
    }),
  ],
  totalRequirements: 9,
  getNumDone: (args): number => {
    return Math.min(9, args.breakthrough.coreFormation?.compressions ?? 0);
  },
  name: 'Energised Pearl Core',
  description:
    'Heavily compress the qi within your core until the qi that leaks out is filled with a glittering energy that can empower all forms of arrays and talismans.',
  physicalStats: {},
  socialStats: {},
  dynamicStats: (args) => ({
    physicalStats: { meridians: 1, dantian: 1, eyes: 1, flesh: 1, muscles: 2 },
    socialStats: {
      lifespan: 100,
      charisma: getBreakthroughCharisma('coreFormation', 1),
      talismanslots: 1,
    },
    combatStats: getCoreFormationAltarStats(args.breakthrough).combatStats,
    craftingStats: getCoreFormationAltarStats(args.breakthrough).craftingStats,
  }),
};
#

that dynamic stats is the killer

#

youll have to put in a request for me to expose that

hidden jewel
#

blech

#

so we're on pause playing until that's fixed

#

roger that

#

in semirelated news, I cant see feature requests, only bug notifications

#

is it okay if I throw it in there?

hidden jewel
#

I'll save this as 0.0.5 and push it once I get confirmation we're fixed on that end, then

minor flame
#

Picked my mod back up a few days ago, did something get changed with the Technique Crystals? They do not want to work for me anymore and I want to know if that is a new code problem or a me problem

outer jay
#

in what way?

minor flame
#

I click it and it fads to black

outer jay
#

interesting. that means the game crashed.

minor flame
#

it worked before I took my brake form it

outer jay
#

can you run with devMode on and senjd whats in the log?

minor flame
#

how dos one run with dec Mode

#

that might help with moding ...

outer jay
#

#1419048022993666148 message

minor flame
#

TypeError: Cannot read properties of undefined (reading 'name')
at _rolldown_dynamic_import_helper.js:2187:19542
at Array.filter (<anonymous>)
at _rolldown_dynamic_import_helper.js:2187:19523
at kps (_rolldown_dynamic_import_helper.js:2187:19720)
at T (_rolldown_dynamic_import_helper.js:2190:3562)
at _rolldown_dynamic_import_helper.js:2190:4436
at go (index.js:513:47559)
at ic (index.js:513:70152)
at xc (index.js:513:80432)
at Ou (index.js:513:116012)

outer jay
#

well, thats not helpoful ๐Ÿ˜„

#

mind sharing your mod?

#

i can try to figure out why

minor flame
#

shure, just throw it in here?

outer jay
#

yeh or dm me

minor flame
outer jay
#

and how are you triggering the crash

minor flame
#

I can also send you the uncompiled one if you need it

#

just clicking the crystel

#

there is no dropdown, stright to crash

outer jay
#

'the' crystal?

#

which one?

minor flame
#

I was trying to get the (I) crystal to work again but all my modded ones do not work anymore

outer jay
#

found it

#

somehow the mod has added an undefined into the list

#

mind sending the sources?

#

or should i say, a technique thats NOT in the techniqueMap

minor flame
#

compressing, sending in a moment

outer jay
#

so next release will fix the ui crash

minor flame
#

welp, to big for discord how do I give you acces to a privat git repo?

#

or dos that just mean no one can edit it?

#

never used it much before

outer jay
#

sadly you cant invite collaborators without a github enterprise

#

you could upload it to google drive and give me a link?

minor flame
#

I think I set it to public now, should work

hollow light
#

you'll want to set your main to protected, so you have to approve pushes, good practice

outer jay
#

oh damn youve been busy!

hollow light
#

i dont think anyone would be malicious in here though

outer jay
#

if i had to guess, you have a typo somewhere in here:

#

to avoid that, id import the techniques directly

#

if it helps, heres how the game does it:

const produceCrystal = (realm: Realm, element: TechniqueElement): TechniqueCrystalItem => ({
  subKind: 'crystal',
  kind: 'technique',
  name: `Technique Crystal ${realmToTier[realm]} (${elementToName[element]})`,
  displayName: tr(`Technique Crystal ${realmToTier[realm]} (${elementToName[element]})`),
  description: tr(
    `The crystal of an unformed ${elementToName[element]} technique. Focus on it to unveil the technique locked within, or convert to Enhancement Dust.`,
  ),
  techniques: techniques
    .filter(
      (t) => t.realm === realm && t.type === element && !t.secondaryType && !t.disableCrystalDrop,
    )
    .map((e) => e.name),
  fallbackTechniques: techniques
    .filter(
      (t) =>
        t.realm &&
        realms.indexOf(t.realm) < realms.indexOf(realm) &&
        t.type === element &&
        !t.secondaryType &&
        !t.disableCrystalDrop,
    )
    .map((e) => e.name),
  icon: crystalImage[element],
  stacks: 1,
  rarity: 'mundane',
  realm: realm,
  valueTier: 0.75,
});

type CrystalMap = Omit<Record<TechniqueElement, TechniqueCrystalItem>, 'none'>;
export const crystalsIMap: CrystalMap = techniqueElements
  .filter((e) => e !== 'none')
  .reduce(function (map, element) {
    map[element] = produceCrystal('bodyForging', element);
    return map;
  }, {} as CrystalMap);
export const crystalsI = Object.values(crystalsIMap);
#

or a standalone one:

export const chromaticCrystalIV: TechniqueCrystalItem = {
  subKind: 'crystal',
  kind: 'technique',
  name: `Technique Crystal IV (Chromatic)`,
  description: `The crystal of an unformed technique of unknown type. Focus on it to unveil the technique locked within, or convert to Enhancement Dust.`,
  techniques: mysticalRegion4.map((e) => e.name),
  fallbackTechniques: [],
  icon: chromatic,
  stacks: 1,
  rarity: 'resplendent',
  realm: 'coreFormation',
  valueTier: 0.75,
};
minor flame
#

I tryed that the first time and found my brain to smooth

hollow light
#

so real

#

it took me ages to make sense of mapping

minor flame
#

but I did not change the name of most things and tripplechekt the 2 that I did

#

and crystal I dos not have a changed name in it

hollow light
#

are they all added to the master technique list?

outer jay
#

ill fire off another release and it should stop the crash

hollow light
#

if the techniques aren't compiled they don't 'exist'

minor flame
#

yes

#

all are working

#

well registered at lest, cant test some now as the crystesl stoped working

#

but the unchanged ones where working and again (I) has no changes

minor flame
#

Well sins I cant test at the moment, some questions. If I have the temper mechanic duck taped to the puppet system which I use for my summons, do the temper stacks get lost if the puppet gets destroyed? And is there a trigger for when a puppet gets destroyed which I can use to cerate another buff?

outer jay
#

yes to both

#

e.g.

triggeredBuffEffects: [
    {
      trigger: 'guardianBroken.Spiritbound Ward',
      effects: [
        {
          kind: 'buffTarget',
          buff: shatteredMembraneVI,
          amount: { value: 8, stat: undefined },
        },
        {
          kind: 'buffSelf',
          buff: temperedCarapaceVI,
          amount: { value: 8, stat: undefined },
        },
      ],
    },
  ],

#

you need ANOTHER buff to listen to the breaking event though

minor flame
#

So I can not have the puppet itself create the new buff?

outer jay
#

no

#

i man you cand request that hook to be added

#

a 'onDestroyed' field of guardian

#

sensible request tbh

minor flame
#

thx, and requested

minor flame
#

also another question, is there a option to create a new tab for moded techniques now or is that one still on the to do pile?

hollow light
#

you should already be able to do that

#

under a technique definition there is 'noneType'

#

tabs for neutral techniques are created using that

#

so if you assign your modded techniques the same type in that field, it should make a tab for them

minor flame
#

do they need to be in type: "none" or type: NoneType"? when hovering over type the only options are the 6 schools and none which dos not create a new tab

#

thay are alos only wisible in the all tab and not in any other tab

hollow light
#

type: 'none' and noneType: (WHATEVER STRING HERE)

minor flame
#

huh, let me try

#

prais be, I can organize my techniques now : D

#

once I get those crystels working again

outer jay
#

ive just updated the game

minor flame
#

huza, it works

hidden jewel
outer jay
#

you can now just use social stats like before and it will work

hidden jewel
#

Hell yes, time to push the update then

#

thanks boss!

hidden jewel
# outer jay yes

oh also as a heads up the update bot is a little confused as to what update it's pushing to. Sometimes it says .60 (which has already been released) and sometimes it says .61 (which I guess is just now released, unless this is .60a or the like)

placid monolith
#

lyeeder, I can't see my "hello.meta" save in UI :/ ๐Ÿ˜‚

placid monolith
hollow light
#

nope!

#

I was referring to Tjarkus, who made his own mod repo public

placid monolith
hollow light
#

Good point! I'm potently inept at it's usage and specifics, but I've got heart

hidden jewel
#

ignore me I realized I never NPM ran

hidden jewel
#

So I was attempting to modify a few shards to practice before adding them to lists to see the effects- I wanted to make the shards available for Pillar Creation more closely mimic the formation game, so that Formation better serves as a tutorial for what's to come next- only to run smack dab head first into a duplication issue

#

Somehow both of these (and their left versions) are present in my game, even though I only called them to modify their values

outer jay
#

can you share your code?

hidden jewel
#

Is this an issue of them being called another time and I should just skip the interim?

#

Yeah one sec

#

Snipped out unrelated code

outer jay
#

right so

hidden jewel
#

import { PillarShardItem } from 'afnm-types';

const baseFengeLeft = window.modAPI.gameData.items['Fenge Shard (Left)'] as PillarShardItem
const baseFengeRight = window.modAPI.gameData.items['Fenge Shard (Right)'] as PillarShardItem

const newFengeLeft = {...baseFengeLeft};
const newFengeRight = {...baseFengeRight};

newFengeLeft.output = {
mode: 'multiply',
left: 0.3,
top: 0.7,
right: 0,
bottom: 0
}
window.modAPI.gameData.items['Xun Shard (Left)'] = newFengeLeft;

newFengeRight.output = {
mode: 'multiply',
left: 0,
top: 0.7,
right: 0.3,
bottom: 0
}
window.modAPI.gameData.items['Xun Shard (Right)'] = newFengeRight;

#

thought this would be easier to read

placid monolith
#

is assigning Fenge shard to Xun Shard intended?

hidden jewel
#

AW SH

#

NOPE JUST SAW THAT

#

So that's definitely one mistake

outer jay
#

i that might be THE issue ๐Ÿ˜„

hidden jewel
#

I swear to God

#

I will say there were 1 or 2 more issues but if that's the problem for all of them whoooooo boy

#

rubber ducky debugging

#

I just need to go get the CodeQuacker from my storage

#

found 4 more issues arising from mixing up my damn shard names...

placid monolith
outer jay
#

or do this:

const baseFengeLeft = window.modAPI.gameData.items['Fenge Shard (Left)'] as PillarShardItem
const baseFengeRight = window.modAPI.gameData.items['Fenge Shard (Right)'] as PillarShardItem

const newFengeLeft = {...baseFengeLeft};
const newFengeRight = {...baseFengeRight};

newFengeLeft.output = {
  mode: 'multiply',
  left: 0.3,
  top: 0.7,
  right: 0,
  bottom: 0
}
window.modAPI.gameData.items[newFengeLeft.name] = newFengeLeft;
hidden jewel
#

I tried doing that but it got pissy at me

outer jay
#

avoid the issue

hidden jewel
#

(my response was to Ribbit)

placid monolith
hidden jewel
#

the pillar shards are way more pedantic about what they want to accept

outer jay
placid monolith
#

yeah, so just inline cast it

hidden jewel
#

because I did exactly that for my crystallized pressure pills mod

outer jay
#
(modAPI.gameData.items['Fenge Shard (Left)'] as PillarShardItem).output = {
  mode: 'multiply',
  left: 0.3,
  top: 0.7,
  right: 0,
  bottom: 0
};
#

but in general i dont like that

#

typecasting is hacky

placid monolith
#

kinda have to downcast it, I don't think there's any other way

outer jay
#
const baseFengeLeft = window.modAPI.gameData.items['Fenge Shard (Left)']
if (baseFengeLeft.kind !== "pillar_shard") {
throw new Error("Its the wrong type!")
}

const newFengeLeft = {...baseFengeLeft};

newFengeLeft.output = {
  mode: 'multiply',
  left: 0.3,
  top: 0.7,
  right: 0,
  bottom: 0
}
window.modAPI.gameData.items[newFengeLeft.name] = newFengeLeft;
placid monolith
#

oh hmm that too ig

outer jay
#

if you do the above it type narrows by the compiler

hidden jewel
#

Right so typos were in fact 90% of the issue

#

The last 2 are mainly to sate my own OCD

#

import { PillarShardItem } from 'afnm-types';

const baseRonghui = window.modAPI.gameData.items['Ronghui Shard'] as PillarShardItem

newRonghui.stability = 5,
window.modAPI.gameData.items['Ronghui Shard'] = newRonghui;

outer jay
hidden jewel
#

really? The other ones auto-corrected

outer jay
#

which ones?

hidden jewel
#

huh no it is in fact a tooltip issue

#

nvm on that one

#

that's an easy fix

#

code incoming shortly

outer jay
#

right yeh. REDUCES is generated. INCREASES is not

#

why i did it that way god knows

hidden jewel
#

...excuse the french out of me

#

import { PillarShardItem } from 'afnm-types';
const baseYinxie = window.modAPI.gameData.items['Yinxie Shard'] as PillarShardItem

#

const newYinxie = {...baseYinxie};

#

newYinxie.stability = 10,
window.modAPI.gameData.items['Yinxie Shard'] = newYinxie;

#

And then all stabilizers had their qither requirement bumped up by 1 to account for the difference but I just couldn't stand losing stab for that

hidden jewel
outer jay
#

hmm

#

no idea ๐Ÿ˜„

hidden jewel
#

NOPE NVM

#

FOUND THE ISSUE

#

SAME DAMN ISSUE

#

i HATE PINYIN

outer jay
#

i would suggest using my pattern

hidden jewel
#

on the one hand yes

#

on the other hand

#

that would not have saved me this time

placid monolith
# hidden jewel that would not have saved me this time

I'm assuming 'Yinxie Shard' name is incorrect so you get undefined? if you had used type narrowing like lyeeder did, it'd have saved you you'd be trying to modify some prop on undefined which'd have given an error anyway, so yeah no, no benifit to the pattern in that case

#

oh baseHebing, and Yinxie

#

yeah there's no solution to you modifying one thing while thinking it's something else :P

hidden jewel
#

Yeah, error exists between monitor and chair

hidden jewel
#

Is pillar grid tile limit a moddable number, or is that not exposed?

#

I'm getting annoyed at not being able to visualize pillars after a set size and want to be able to make it so you can add in infinite (well, many many) tiles to create a 'blueprint' but not have that blueprint be submittable for a final pillar unless it meets all requirements

#

Like, having 1000 tiles on the board so you can always see the qither beams and the space around any given shard, but if you're over the 101 tile maximum, have it go 'nope, sorry, you're over the limit pal. Fix your soul'

outer jay
hidden jewel
#

Ahhh, so no infinite blueprint at the moment then

#

Right, shelving that plan then

placid monolith
#

RootState doesn't accept 'permanent' literal :\

outer jay
#

Lol wat

#

Wait that's remaining months

#

You don't need that

placid monolith
#

where is 'permanent' set?

#

in save state

outer jay
#

On the charcater itself. Not in save

#

On the charcater definition

placid monolith
#

yeah I meant in character def (in save state) lol

outer jay
#

No not the save version

#

The actual character

placid monolith
#

I see, so gameData

#

what should I set in state.characters.followingRemainingMonths if the current character variant has duration: 'permanent'?

#

0 or something ig

outer jay
#

Just 1

placid monolith
#

0.6.60 doesn't exist lol

outer jay
#

Yeh

#

It has no types changes

placid monolith
#

it does

#

the permanent thing

outer jay
#

Hmmm

#

Well anyway, we are on 61 now

placid monolith
#

yeh it's fine ๐Ÿ˜‚

hidden jewel
#

Could I get the nonminified code for the Martyred Zeal? I'm curious about something in the coding

outer jay
#

Note you can just see the definitions by console logging the object

placid monolith
#

just log stuff in window.modAPI.gameData, or the whole object itself

outer jay
#

Now I'm also happy to share the raw code if there's something you aren't getting from thst

#

But in general, easier to just log

hidden jewel
placid monolith
#

ugh, I didn't expect "kill me" to kill the game instead, it just keeps going

#

๐Ÿ˜‚

api.actions.advanceDays(Number.MAX_SAFE_INTEGER)
#

huh... is it doing every month one-by-one and not just skipping to what the date would be when the days are added?

#

anyways, for what I wanted, this works better

const state = window.modAPI.getGameStateSnapshot()!;
const updatedPlayer = produce(state.player.player, (player) => {
  player.socialStats.age =
    window.modAPI.utils.getLifeSpan(player, state.breakthrough) + 1;
});
api.actions.updatePlayer(updatedPlayer);
api.actions.advanceDays(30);
minor flame
#

is there a way to make the guardianIntercept only intercept dmg to hp and not shield?

outer jay
#

Not at the moment no