About This File
- Lightning fast
- More robust (because when a Papyrus script calls a native function, it is scheduled for execution in the Skyrim Game Main thread, i.e. there are no multithreading problems when multiple Papyrus scripts are adding and removing tattoos at the same time).
- Fully compatible with SlaveTats, so it can be installed/deinstalled at any time (uses the same JContainer structures and does exactly the same as SlaveTats)
- Uses CommonLibSSE-NG, so it should run on all major Skyrim versions + Gog (tested on 1.6.1170 and 1.5.97)
- Original Papyrus SlaveTats, if you want to use it's MCM
Alternatively, there now is a new CatMenu/ImGui gui (tested on Skyrim 1.6.1170 and 1.5.97). It has the following requirements:
- CatMenu https://www.nexusmods.com/skyrimspecialedition/mods/65958 (don't forget to copy 'imgui.dll' to the game folder, as described on the CatMenu Nexus page).
- And very recommended, if you ALT-TAB between Windows and Skyrim: Alt-Tab Stuck Key Fix NG https://www.nexusmods.com/skyrimspecialedition/mods/148466
Bathing In Skyrim Tweaked v3.4 (17-May-2023) from Monoman1:
Spank That Ass v4.8 BETA SE (27-Apr-2021) from Monoman1:
Changelog:
0.6.3:
It is possible now to prevent that node overrides are applied to actors with the help of locks. SlaveTatsNG will honor these locks, and do nothing in synchronize_tattoos if another mod has the actor lock. This mechanism is independent of SlaveTatsNG, and can be used without it to synchronize node override manipulations by multiple mods, see NiNodeOverrideLock.psc.
0.6.4:
Cleanup, forgot to implement the synchronize_tattoos function in the MCM test menu
0.6.5:
Added a C++ interface, which can be queried via the SKSE messaging functions (merge request from @cybercheese). So, now it's possible to use SlaveTats directly from other SKSE plugins without Papyrus. I created a tiny project, with which I tested the interface: https://github.com/nopse0/SlaveTatsNG-testing
Basically, the interface can be queried like this:
void messaging_hook([[maybe_unused]] SKSE::MessagingInterface::Message* a_message)
{
switch (a_message->type) {
case SKSE::MessagingInterface::kPostLoad:
{
const char* slavetatsPlugin = "SlaveTatsNG";
SKSE::GetMessagingInterface()->RegisterListener(slavetatsPlugin, [](SKSE::MessagingInterface::Message* a_msg) {
if (a_msg && a_msg->type == SlaveTatsNG::MessageType::Interface) {
const SlaveTatsNG::Addresses* iface = SlaveTatsNG::Addresses::from_void(a_msg->data);
logger::info("SlaveTatsNG Interface found: address = {}", (void*)iface);
logger::info("simple_add_tattoo: address = {}", (void*)iface->simple_add_tattoo);
}
});
}
}
}
The name of the texture used for clearing unused overlay slots can now be configured, per default SlaveTats's "blank.dds" is used.
This can be changed in SKSE/plugin/SlaveTatsNG/SlaveTatsNG.ini:
[Config]
### Texture name used for clearing unused overlay slots: ###
# SlaveTats empty texture (is used per default)
# blankTextureName="Actors\Character\slavetats\blank.dds"
# Empty texture from RaceMenu
# blankTextureName="actors\character\overlays\default.dds"
# Same without path, probably also works
# blankTextureName="default.dds"
After changing the empty texture name, the game must be saved and restarted to refresh the shaders (everything looks purple at first)
0.6.10:
Implemented the missing tattoo_magic functions ("DibellanDefender").
0.6.11:
Removed the "excluded_by" and "requires" checks in the SlaveTats MCM, because dynamically updating the MCM list boxes doesn't work. This does no harm, because applying tattoos which are excluded by another tattoo, or which require another tattoo which isn't present still fail, it's just that all tattoos in the MCM are shown.
0.7.0:
synchronize_tattoos was executed concurrently by the Papyrus threads instead of by the Skyrim main thread
0.7.1:
Auto 'Add/remove tattoos' when Skyrim is started
0.7.2:
0.7.1 didn't work, rebuilding the SlaveTats cache must be done in 'kPostLoadGame' (and, I guess, the SlaveTatsNG.dll plugin must be loaded after the JContainers64.dll plugin (otherwise JContainers isn't initialized when the cache is rebuild), but, luckily, this is automatically the case, because SKSE plugins are loaded in alphabetical order)
Added a function to get the time elapsed since the game was last saved. This can be used with "Simple Clock on-screen" https://www.nexusmods.com/skyrimspecialedition/mods/89360 to make a "Save game reminder" (always annoying if the game crashes after not having saved for an hour, or so).
Simply replace
Int[] time = PO3_SKSEFunctions.GetSystemTime()
with
Int[] time = SlaveTatsNG.get_last_save_time()
0.7.5:
RaceMenu addresses are now read from a Json file, instead of being hardcoded
0.8.0:
# Changes
## 0.8.0
* The boolean field ``gloss`` in tattoos isn't used anymore, it has been replaced by two new float fields, ``glossiness`` and ``specularstrength``.
* Three other new fields have been added to tattoos: ``specularstrength``, ``emissivemult`` and ``glowtexture``.
* Besides the old ``apply_overlay`` function in ``SlaveTats.psc``, a new function ``apply_overlay_ex`` has been added to ``SlaveTatsNG.psc``:
```
bool function apply_overlay_ex(Actor target, bool isFemale, string area, int slot, string path, int color, int glow, float glossiness = 0.0, string bump_path = "", float alpha = 1.0, float specular = 0.0, string glow_path = "", float emissive_mult = 1.0) global native
```
It contains the above mentioned ``gloss`` change and the three new fields for the NiOverride parameters ``SpecularStrength``, ``EmissiveMult`` and ``Texture[glow/detail]``.
The old Papyrus function in ``SlaveTats.psc`` with boolean ``gloss`` parameter still exists; if ``gloss = true``, it calls ``apply_overlay_ex`` with hardcoded ``glossiness = 5.0`` and ``specularstrength = 5.0`` parameters.
```
bool function apply_overlay(Actor target, bool isFemale, string area, int slot, string path, int color, int glow, bool gloss, string bump = "", float alpha = 1.0) global native
```
Note: ``apply_overlay/apply_overlay_ex`` only apply NiOverride overlays, they don't change the SlaveTats JContainer tattoos, so they shouldn't be called directly. Instead edit the SlaveTats tattoos with JContainer or SlaveTats functions, and then call ``synchronize_tattoos``.
* The tattoo version (``.SlaveTats.version``) of actors is changed from ``1.0`` to ``2.0``.
0.8.1:
Fixed copy&paste error.
Edited by nopse0
What's New in Version 0.8.1 (GUI 0.2.0)
Released
Re-uploaded GUI v0.1.1, needed in some mod lists