#Help with modding
1 messages ยท Page 3 of 1
btw, should I namespace mods? as in the package name by my name
It's just about giving enough context so the translation can do it
Which package name?
mod's package name
what if these are local mods?
Then you will have clashes
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
You already have it on itch?
yeah why?
You've done a lot for the game. I'll send you a steam key
too late ๐
I bought it
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
I didn't know that was a thing
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
Put a feature request in, I'll dig through the settings tomorrow
steam probably has it hidden somewhere, I wouldn't know, never published anything on steam
Steam UI is... A thing
I don't think a designer has ever even been within a mile of ot
where do workshop mods get installed? mods/loaded I assume?
I see
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
I didn't see any real reason to restrict it just yet
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?
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
but! With all that explained, this is a bug and minimumPotential should be omitted when stars are added lol
lol
yeah upgrade was adding a star when minpotential is higher than current total potential tier (hiddenPotential + qualityTier)
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
in a bit
copilot is dead, long live copilot ๐
well.... it took about forever, but i think i'm happy with my stack. can someone take a peek and let me know if there's anything MORE i need to configure before going ham with the agent? TIA
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
You made this with a 7b model?... I'm super impressed lmao
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)
That's fair feedback. Request it to return the split codes too
ok so it's api specific then, I'll write it out
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);
That's fair
It's sorta muddled the self-translations Vs providing translations for other people's stuff
Bug it
providing translations for other people's stuff
how does that work?
where would the 3rd party translations be placed in game folder if they're not being shipped with the mod?
They'd take the template.json from your mod, translate it, then register using addtrasnaltion
That would be its own mod
oh lol, seems quite annyoing for some translator looking to do that, given mod metadata lives in .js now and not in plain package.json
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
I'm still at the proof of concept. I wanted faster generation. I'll probably swap for codestral22b (or related... Devestral?) when I finish setup and sanity checking.
I already spent 12 hours building the stack ๐
Your mod contribution can be the mod-making stack ๐
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.
it's quite simple if you have basic knowledge of js or ts and we have active people who are very knowledgeable in mods
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
I'll submit that too 
After I generalize some of the files that are running the "back-end"
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
What's the mod? I can say how hard it would be
Basically I need to add a couple events with an npc, dungeon keys, a dungeon, bosses, and special item that I don't know if I should give the details of here.
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
Oh that might be the hard part ๐
What sort of item?
A teleportation item
should be doable
We already have transport seals
Is durability a thing now?
But they are linked to a location
I know
No
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
just add a flag with the number of charges
Ok I will probably implement that way
You can also try to ungabunga the mod out with ai and see if it works ๐. You might get lucky
Haha try not to use anything too ancient. The newer devstral is great however, I'm a big fan.
If you can fit it the most capable small model for coding currently is Qwen 3.6 27b
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
lyeeder, where's 0.6.55? ๐ ๐
^^
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
I looked into this and it didn't work in ci
The npm deploy needs a trusted app or something and it refused to work in a GitHub action
huh weird
But maybe I'm just not an expert with it ๐
it only shows name and versions for active ones? that's weird... probably because it only does that for extracted ones?
also my character became a female somehow
it's only in this battle (save was made in-battle)
if I go start another battle it's fine
still bug it?
yep
Please yeh
it's a partially known bug
it already happened to one person, but we still didn't understand the reason xD
@placid monolith types are up
Thanks. I have about 60gb for models, so after sanity checking I could probably partially offload that model
Stack-setup docs have been submitted in draft form
https://github.com/tsinanju/auspicious-days-agent-fork
lyeeder, issue
#1500733585890480229 message
If you have to offload I suggest sticking to an Moe like Qwen 3.6 35b, it should be much faster. Gemma 4 26b is good too if it still isn't fast enough
lyeeder, a lot more stuff than just qualityTier in an item is persistent (so in savefile), no? That could be mutated...
#1500355843781300294 message
No?
Well sorta. The others are hidden potential and enchantment
But neither should conceptually be modified by reforge
yeh I don't remember more than that
well a mod could modify enchantment's rarity for eg
doesn't matter if in-game reforge does it or not
That is true. Request ๐
another breaking change in next update yipee
it's great I've not published the mod where I'm using all this yet
Should be able to add them to the end so it won't break things
Just add more options to configure if desired
no don't have to worry about making the signature weird because of that just yet
since I don't think many mods are using it yet
or any
there isn't a game load hook huh? like
onGameLoad(interceptor: (state: RootSate) => RootState))
for mutating state on game load
๐ญ
oh wait, this is about Qi required for breakthrough or something
I thought it's supposed to give me the max Qi the player can have, like here
why's the description this? it makes it look like it'll give the max Qi
You want getBreakthroughQi * the current realm +3
Yeh the doc is wrong
I'll expose getMaxQi too
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
UseKeybinding is the game one, but I guess so could support providing the action id instead and handle mapping that too
Request it
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
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
I changed my mind on it, if the internals use the api as it is in its current state then it's fine.
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
You'll be happy to know the new inject UI works fully (tested) and supports a ton more positions
And completely changed the api
finally the nth position thing ๐
is being able to cancel out of animation for "enchantment extraction"/reforging/upgrading intended?
Cancel out?
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
Yeh bug
Is that registerInjectHUD()
Just injectUI
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 ๐ซ )
Works for me 
My new compute card doesn't show up till Thursday anyway
And I still need to evaluate models for roo code
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
followed link from ./dist/[mod-name]/package.json json }, "devDependencies": { "afnm-types": "0.6.52-v2", ...}
what?
that's the dist folder you asked for
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
then use 0.6.54-2 instead of 52- v2
you published a package just for testing ๐
oops 
on a related note, do i need to update my package.json for the modding
yes, afnm-types would need to be bumped manually each version
can't target @latest because of how lyeeder versions the packages
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 ๐
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
haha mods that put overflow themselves...
It's SUCH a pain in the ass to publish locally ๐
Easier to just shove onto npm with my existing scripts
can't you just link to the built package, in dependencies? or tarballs with npm pack ig
on that note, what about this ^^
I mean, you can request it..I don't know how to DO it but I can throw an agent at it ๐
maybe a little surprising you never had to built local packages all these years ๐
gemma didn't suit the project, so i guess i'll try qwen and llama next.
i'll be getting a compute card tomorrow to help with vram 
Oh nice I did not know there was a template for that
not sure what's wrong but there's no mod load error UI here...
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;
}> {...}
What madness are you building if you are using decorators ๐
don't ask ๐ญ
idk why am I doing what I'm doing
I changed my mind since I know you must be very curious, so here, tell me how to make it less mad! ๐
https://github.com/nozwock/afnm-mods/blob/984ca5fedd15e521cec065ae4c758bfa6556e61a/packages/nozwock-tweaks/src/modContent/features.ts#L46-L116
if you've got some time of course
Oohhh I see what you are trying to do
don't pay attention to revertChangedItems stuff, that's very early stuff, from before action payload hooks were a thing
Personally I'd just use an array of interfaces the manager runs over
yeah, could set order of execution that way if needed too... the only problem is that I have to remember to add the constrcutor to the list
๐
how'd I inherit some base functionality then?
like with base*feature
oh
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
it's there in 6.22 one?
I also don't like settings handling as well, currently I'd have to use useState() for each feature in the ModSettings component
Or harmony
hmm ig I'll look how you use useState in the non minified code
If you have a central manager you can use 1 shared map as the state
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
true ๐ ig I worry too much prematurely
Json conversion in typescript is one of the most optimised bits of it
Turns out websites do it a lot ๐
injectUI update is very nice, can even find the element to inject into more granularly than even what css selector would allow
Let me know how it goes!
Am I safe to update the mod template yet, or will there be a new modtypes tomorrow? ๐
update? last lyeeder mentioned anything was that the update will be at the end of the week
so in a day or two?
I had a feeling it was soon
Saturday mornin
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
Tiny ๐
But it works. Just need to work on some backend issues ๐ซ
Bet it's dns 
Nice haha
I'm pricing out my next workstation... Wonder if I can get a loan ๐ค
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?
Which flag stops combat when health is low
It cant
What are you trying to do?
I'd tell you but then you'd be spoiled
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
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
Not currently possible
hmm
You'd have to request it
what other screens are like that? dual cultivation maybe? or is that one completely based on RootState?
so I can request for them too
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
Combat takes precedence over events
But as for the starting the event, you can do it from a Inject button
should I make a new bug post?
#1499596249270063195 message
Please yeh
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 ๐
I was hoping at least this could be fixed before the next release is published?
https://discord.com/channels/1208332427618160660/1502226684550709369
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);
}
Very clean
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
ok yeah that works t(item.displayName ?? name)
...๐ซ
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;
}),
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).
thats the player from the redux state
if you are making a ui itll be available through a selector
it's called "player" then?
it's only for reading (useSelector)
yeh use the reduxapi.actions.updatePlayer to edit after
ok, thanks. I'll try that
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
it seems to work well. I'll see what I can add over time.
I use clonedeep from lodash personally
oh I see, just clone and then mutate away
hmm isn't there a window.structuredClone already?
regarding combat stats, how can they be accessed through the player class?
Combat stats are derived
What are you looking to do? As that changes things
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?
That's layered on
Pills are one of the sources that all get combined to make the combat state
Others are equipment, breakthroughs, backgrounds
and through player those layers can't be accessed?
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.)
then maybe look at the:
onCreatePlayerCombatEntity
hook
it lets you intercept the combat entity any time its crated and change its values
ok, I'll try that. Thanks!
what is the function called when an entity, like the player, consumes a pill?
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?
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
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?
A stat pill right?
You can just modify the player entity and the inventory directly
Add it to the player and remove from inventory
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.
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
allright, that's not really a problem. I can temporary change an existing pill and then restore it.
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?
so, it basically always counts how many pill of am certain type have been consumed and only then it temporarily updates stats accordingly?
Correct
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?
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.
To do it, register the item using add item, and modify the player entity to add to consumedStatPills
This will give you the combat entity. Then modify it to do what you like and return the new one
Let's you change anything
yeah, regarding the item method, at this point I think should be clear enough. I think the problem I had was that I think I was removing the item, so I couldn't see the stat changes afterward. Regarding the onCreatePlayerCombatEntity, I guess I'll try agin with this one and leave the item method only as the last possible option.
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?
Yes, the output of that is what populated the stats window, tooltips, and anything else that uses combat stats
ok, thanks!
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.
You need to return the new entity
In theory I do that
Got some code to share?
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!๐ฉ
That's alright! Just note it will be in like 8 hours when I awake once more
no problem, I'm not on a schedule for these changes.
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>>
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)
How does cultivatorResistance work, when compared with fistResistance, blossomResistance, etc.? Does cultivatorResistance work for any kind of damage or only for "non-typed" damage?
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
Thanks for the answer!
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
huh new ui
oh, interesting
but mb better to move it to the left side
I think this is a common place for relationship increase notifications
yeh and have them be placed and scroll vertically if many items were given in a dialogue
can you create a feature request?
at work atm xD
!!!
flies over on next dialogue
Yes
Have you got examples where it breaks down?
Even the most expensive example I had seemed to align right
no just weird it's placed in center covering portraits
but wouldn't it be better for this to appear on the left?
also easy to notice if it's in center, at the cost of covering portraits
yea, it's good for resources and items, but when there's another small portrait of the character on top of sprite of this character, it's a bit weird imo
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
hmm is the mod uploader looking for a package.json for mod metadata and defaulting to something if it's not found?
Probably yeh
Feel free to poke around the source of that if you like, it's open source
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
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
steam does have something, you can slap in arbitrary metadata to a workshop item iirc, so json string or whatever
Steam has a mod uploader?
but you'd still need something for local mods anyways
no, I mean via the steam ugc/steamworks api
you can attach arbitrary metadata to a workshop item during upload
Oh yeh, the mod uploader is a wrapper for that
which can be queried without having to download the mod, but that's not relevant for this game
only needed if the game is going to have an in-game mod browser ig
???
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
How is that relevant to the mod uploader?
Very lost ๐
it's somewhat relevant as you could query the up-to-date metadata for the subscribed mod via its workshop id, without having to wait for the mod to run once to cache its metadata
but it's not great as it doesn't do anything for local mods
The assumption is the mod itself is more valid than the cached data
your mod uploader would have to ensure that
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
Quite possibly. Feel free to make a pr? Or put in a request (but it'll be a while till I do it)
I'll think about it some more and then do it
But it should be automated as part of the build
or if the bundled zip already contains it, skip its generation based on the fields filled in the uploader UI
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
does the character creation dialog have an inject ui slot name?
hmm yeah nvm, new-game-character-creation
great
now don't go making it return null in main menu ๐
I actually need that, just remove null return type
Where is the data set by api.actions.setModData stored? Somewhere in RootState?
yes under mod
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?
because otherwise they cant be save specific
I'm not sure I follow? Wouldn't these dispatch call just fail if save isn't loaded (well the RootState is always there...)? Or you mean that outside ModReduxAPI there's no .hasSave to check first?
dispatch isnt available outside the redux tree
trying to access it would crash the game
oh so it has to be from a component
its managed by react
I think you mentioned this before, I just forgot ๐
why's id required in a GameDialog?
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
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
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
why'd the id change?
the guid for playthrough/char save in saves/ doesn't change
nor does createdAt in save metadata
But just read the game flags to see if the mod is on/off and do the thing?
the game flag won't exist in a previous save though?
only for the save the mod was loaded in and future saves
ik this is somewhat of an edge case
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
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
hmm name is indeed in that state
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?
Should do yeh
damn, wasted quite some time reading up on jj that I stumbled into a while ago
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
The ONLY issue with git is working with non-diffable assets. Everything else it's perfect for what it does
image assets? and by diff, do you just want git to show prev and current image side-by-side like how github does it?
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
I suppose marking an asset file like that as locked could be useful, but not by too much it seems
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
It's critical for teams that work on that sort of stuff
That's why perforce is such a titan in the gaming industry
ig if the team is too big, yes, that makes sense
for small teams, that stuff could just be communicated
how are you handling assets for the game? git lfs or something else?
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
Just git ATM. There's nothing big enough to need lfs
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
Are you sure you are doing a deep copy?
immer is supposed to do that no?
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
Most hooks are pre-deep cloned by me
So have I been really living in the illusion that immer does deep copy...
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
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
the problem is on your side
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;
});
What is the call for adding a given buff to a condensation art, like the Cycle of 9?
You need to replace the whole art
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
There is not a function no
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
I think it should still work. Just be 'less good'
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?
Sure gimme a sec
thanks I appreciate it
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,
}
I dont think the other two sent in their entirety
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
if it works how you got there doesnt matter
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
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
ahhh so I just need to make the call and have my mod loaded after ye
then you can grab stuff it makes by name
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
welp one way to find out
oooo VS got an update, now I get to see a cute little dotted loop after npm install
Has combatBuffs not been added as a callable property yet?
its in the latest types, why?
I wanted to just go newArt.combatBuff the same way I would like physicalStats
you should be able to yeh
wait
would my baseline just be outdated, I need to grab a new copy of the example mod?
you need the types for 0.6.59
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?
quite possibly
its full of files ๐
but you can just update the types
no need to pull everything if you dont want to
very unspecific
rain world has requirements for that. requirements contains id of mods a mod depends on.
{
"id": "moreslugcats",
"name": "More Slugcats Expansion",
"version": "1.11.0",
"hide_version": true,
"authors": "",
"description": "",
"requirements": ["rwremix"],
"requirements_names": ["Rain World Remix"],
"checksum_override_version": true
}
could have something like that for afnm too
you have executables lying around in your example repo
Here are all the fields for reference in case you're thinking of updating mod metadata system soon since some are optional and the above didn't had them
https://rainworldmodding.miraheze.org/wiki/ModInfo.json
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
Mind making a featurerequest to add the baking in of dependencies
Or do you mean it already works
Already works
confirmed on my end no sweat
lemme grab you a pic
I decided to send several pics
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
It works for now
Maybe in the future I'll add the dependency thing to auto sort
One less thing to do! ๐
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
why did it needed to be confirmed?
oh the order thing? that it works as expected?
how'd that even work lol! ๐ you don't have any metadata for dependencies currently
because we weren't sure if incandescent would load the items in time to be called by my patch
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.
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"))
As in what is being pulled down to it or what is being passed back up after the code is run?
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
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)
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?
yeah that one's on me
I recognize you were just saying this as an example but for reference
oh yeh its a map ๐
Object.values(window.modAPI.gameData.items).filter(e => e.kind === "condensation_art")
kind is the item kind
e.g. clothing
you want name
also for this id remove the filer
ahhh yeah so that's gonna be b b name
just print ALL the coreFormation ones
fair
okay so that's REALLY interesting
It looks like I'm passing it along correctly
So something must be overriding it
ah 1 sec
ah am I missing something that would be obvious in the nonMinified code?
So something like this?
Though I think I need do do the whole 'find name' nonsense again
no actions.addBreakthrough
oh wait
okay, so i made the core formation breakthroughs WAY more complex ๐
i probably broke modding them
They have been...rough ๐
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
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?
and done! Thank you for the help.
I'll save this as 0.0.5 and push it once I get confirmation we're fixed on that end, then
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
in what way?
I click it and it fads to black
interesting. that means the game crashed.
it worked before I took my brake form it
can you run with devMode on and senjd whats in the log?
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)
shure, just throw it in here?
yeh or dm me
and how are you triggering the crash
I can also send you the uncompiled one if you need it
just clicking the crystel
there is no dropdown, stright to crash
I was trying to get the (I) crystal to work again but all my modded ones do not work anymore
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
compressing, sending in a moment
so next release will fix the ui crash
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
sadly you cant invite collaborators without a github enterprise
you could upload it to google drive and give me a link?
Contribute to Tjarkus/Nexus-Project development by creating an account on GitHub.
I think I set it to public now, should work
you'll want to set your main to protected, so you have to approve pushes, good practice
oh damn youve been busy!
i dont think anyone would be malicious in here though
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,
};
I tryed that the first time and found my brain to smooth
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
are they all added to the master technique list?
ill fire off another release and it should stop the crash
if the techniques aren't compiled they don't 'exist'
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
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?
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
So I can not have the puppet itself create the new buff?
no
i man you cand request that hook to be added
a 'onDestroyed' field of guardian
sensible request tbh
thx, and requested
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?
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
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
huh, let me try
prais be, I can organize my techniques now : D
once I get those crystels working again
ive just updated the game
huza, it works
Does that include updates to expose Core Formation social stats?
yes
you can now just use social stats like before and it will work
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)
lyeeder, I can't see my "hello.meta" save in UI :/ ๐
any user with access can push to main directly right now in afnm repo? ๐
what... what does it matter there when he's the only contributor?
Good point! I'm potently inept at it's usage and specifics, but I've got heart
ignore me I realized I never NPM ran
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
can you share your code?
Is this an issue of them being called another time and I should just skip the interim?
Yeah one sec
Snipped out unrelated code
right so
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 PillarShardItemconst 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
is assigning Fenge shard to Xun Shard intended?
i that might be THE issue ๐
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...
you can just mutate gamedata, there's no need to create shallow copies etc
modAPI.gameData.items['Fenge Shard (Left)'].output = {
mode: 'multiply',
left: 0.3,
top: 0.7,
right: 0,
bottom: 0
};
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;
I tried doing that but it got pissy at me
avoid the issue
(my response was to Ribbit)
what exactly
the pillar shards are way more pedantic about what they want to accept
the issue is its missing the type cast
yeah, so just inline cast it
because I did exactly that for my crystallized pressure pills mod
(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
you're typecasting in other snippets too ๐
kinda have to downcast it, I don't think there's any other way
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;
oh hmm that too ig
if you do the above it type narrows by the compiler
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;
you have tyo update the tooltip too
really? The other ones auto-corrected
which ones?
huh no it is in fact a tooltip issue
nvm on that one
that's an easy fix
code incoming shortly
...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
Oh no the issue is both of these exist simultaneously
i would suggest using my pattern
window.modAPI.gameData.items[newFengeLeft.name] = newFengeLeft;
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
Yeah, error exists between monitor and chair
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'
It's up to an extra +10 (ATM), and it's a flag so you could have a mod that sets it to max
RootState doesn't accept 'permanent' literal :\
yeah I meant in character def (in save state) lol
I see, so gameData
what should I set in state.characters.followingRemainingMonths if the current character variant has duration: 'permanent'?
0 or something ig
Just 1
0.6.60 doesn't exist lol
yeh it's fine ๐
Could I get the nonminified code for the Martyred Zeal? I'm curious about something in the coding
Note you can just see the definitions by console logging the object
just log stuff in window.modAPI.gameData, or the whole object itself
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
Did not know this, thank you!
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);
Yes it is simulating the world
is there a way to make the guardianIntercept only intercept dmg to hp and not shield?
Not at the moment no