Jump to content

Blockhead Help


Myst42

Recommended Posts

Posted

Hello again

 

A few weeks ago I was doing a medusa race

Got interrupted by new mass install and now I started working again

 

Thing is, It's probably on my best interest to use blockhead on some stuff I have

For example:

-Snake tails for medusa race

-Got my hands on khajiit paws and raptor claws I mixed with HGEC, Robert's Male v5 and ZKEC type bodies I'd like to eventually use on the future to make beast race models. Hooves are also in the collection

-Pic related cause that's what' khajiits should look like

 

2125204-1413119502.jpg

 

 

I'm trying to wrap my head around Blockhead to make it work:

It says I must place files in Meshes/Characters/BodyAssetOverrides/PerRace/M-F

Then rename files to (RaceName)_(BodyPart).nif

And that supposedly will make the game target new files in those folders under those names

 

Question:

Does it work on complete body part redirections? I.E target everything looking for "foot" and "lowerbody" to new file, or it works only for nude models?

In other words is it possible to use it so when playing Khajiit I get the paws mesh when nude and get the pawed boots when using boots?

 

Also, if possible, how?

If I rename files, there's no room for armor folder name, just race and body part

 

----------------------------------------------------------------------

 

Tried looking at that "setbody reloaded blockhead edition" mod

The old one used to work by a script and token replacement

 

Couldn't make sense of the new one as I can't find where is the part where it redirects models to "Bombshell" folder

-----------------------------------------------------------------------

 

Considering that maybe blockhead and setbody only work for nude models, I collected a mod which allows to redirect clothing models called SetBody Expanded, works by adding "factions" and you can have alter "meshes" folder named after said factions

 

How could I make an automated function for it when playing beast races?

----------------------------------------------------------------------

 

Lastly I tried taking a look at another mod "Tamago Setbody Reboot" which does everything I wish happen with races but with pregnant women

 

One would try to make the condition for mesh swap to be "IsRace" instead of "IsPregnant" right?

Just drawing lines here cause my work juice ran out and I couldn't make sense of them scripts either

 

-----------------------------------------------------------------------

 

Don't wanna give up yet

But I'm clueless

Can I do this?

How? Could you guys explain any of this stuff please?

What do I need to do, how do I do it and where do I learn to do it?

 

Posted

The Blockhead documentation could do with some more examples. It's easy to get wrong so nothing seems to be happening. It doesn't help that what examples there are are for vanilla meshes and textures which almost no-one uses!!!!

 

Basically, texture swaps always occur. So if you designated Imperials to always use a tattooed skin, you'll see those tattoos even with armour.

Meshes however are NOT used in place of armour. If you give all male Argonians erections, this will only be seen if they drop their trousers.

It also doesn't spell out that you need to refer to the base ref, so for the player 00000007 (player) NOT 00000014 (playerref)

 

Some examples to help (my machines paths, adjust for your own):-

Meshes

This overides the players lowerbody mesh

E:\Oblivion\Data\meshes\Characters\BodyAssetOverrides\PerNPC\oblivion.esm\00000007_lowerbody.nif

This for a particular PC

E:\Oblivion\Data\meshes\Characters\BodyAssetOverrides\PerNPC\sonia.esp\000008EE_upperbody.nif

Textures

This overides the players whole body skin

E:\Oblivion\Data\Textures\Characters\BodyAssetOverrides\PerNPC\Oblivion.esm\00000007_foot.dds

All female Imperials

E:\Oblivion\Data\Textures\Characters\BodyAssetOverrides\PerRace\F\Imperial_foot.dds

 

A Script Example

 

scn asxsfsetaroused
;UpperBody     – 2
;LowerBody     – 3
;Hand        - 4
;Foot        - 5
;Tail        - 15
ref actor
short level
short npcfemale
short u3d

begin function {actor, level, u3d}
    set npcfemale to actor.getissex female
    if level == 0
        actor.ResetBodyAssetOverride 2 2
        actor.ResetBodyAssetOverride 3 2
        printc "ASX: aroused off 0"
    elseif level == 1
        if npcfemale == 1
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedub1.nif" 2 2
        else
            actor.SetBodyAssetOverride "Characters\asx\m\asxaroused1.nif" 3 2
        endif
        printc "ASX: aroused on 1"
    elseif level == 2
        if npcfemale == 1
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedub1.nif" 2 2
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedlb2.nif" 3 2            
        else
            actor.SetBodyAssetOverride "Characters\asx\m\asxaroused2.nif" 3 2
        endif
        printc "ASX: aroused on 2"
    elseif level == 3
        if npcfemale == 1
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedub1.nif" 2 2
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedlb3.nif" 3 2
        else
            actor.SetBodyAssetOverride "Characters\asx\m\asxaroused3.nif" 3 2
        endif
        printc "ASX: aroused on 3"
    elseif level == 4
        if npcfemale == 1
            ; correct this
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedub1.nif" 2 2
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedlb3.nif" 3 2
        else
            actor.SetBodyAssetOverride "Characters\asx\m\asxaroused4.nif" 3 2
        endif
        printc "ASX: aroused on 4"
    elseif level == 5
        if npcfemale == 1
            ; correct this
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedub1.nif" 2 2
            actor.SetBodyAssetOverride "Characters\asx\f\asxArousedlb3.nif" 3 2
        else
            actor.SetBodyAssetOverride "Characters\asx\m\asxaroused4.nif" 3 2
            ;actor.SetBodyAssetOverride asxqcore.ml4 3 2
        endif
        printc "ASX: aroused on 5 (fix)"
    endif
    if u3d == 1
        actor.update3D
    endif
end

 

Posted

Right, I appreciate the attempt but please keep in mind:

-I am NOT a programmer nor do I work with any computer related stuff, that makes me completely unfamiliar with scripting

-I'm a NOOB trying to LEARN. Seeing scripts and not understanding them is exactly what brought me here

-It's a tough mission but I'm willing to learn. Remember: from the bottom

 

However I can TRY to understand that (Just tell me if I'm wrong):

-Script is an attempt so swap models based on "arousal" variable

-I recognize if (condition) elseif (other condition) else (condition not met) and endif (close sentence)

-For every arousal level, script checks if npc is male or female and then redirects to specific model

-When something == 0 it's false and when it's == 1 is true

 

What I dont get:

-Why beginfunction {actor, level, u3d}?

-Why set npcfemale to actor.getissex female?

-What the hell is u3d?

-Is printc a pop up message?

-How is is that level refers to arousal level and not any other kind of level... there must be a lot of "level" variables in game...

-How to work with ref Means reference right?

-What is short

-What in oblivion are those numbers at the end of nif files?

 

-----------------------------------------------------

 

Back to original question, how to use this knowledge to obtain my goal, to redirect all models for a race both in nudity and dressing?

No head, no particular NPC, just a whole race

Blockhead page says "tier 3" refers to racial overrides

 

--------------------------------------------------

 

Looking at "Tamago Setbody" tried to find corresponding mesh swap script among the many in there

Still no idea which one is it

But this is tsbrFnOnActorEquip

 

 

 

scn tsbrFnOnActorEquip

 
ref rActor
ref rItemBase
 
int bFoundPrg
int bFoundRand
int i
int iBa
int iPrg
int iDefenseType
 
long lSlotMask
 
ref rCurrItem
 
array_var arIter
 
string_var sv
string_var svKey
string_var svOrig
string_var svPathKey
string_var svPathNif
 
Begin Function {rActor rItemBase}
 
; Scribe " %r====================%rtsbrFnOnActorEquip:: Processing %n equipping %n" rActor rItemBase
;We are not interested in the actors that are not loaded.
;OnActorEquip event is also fired when loading actors, so let's not worry.
     if PlayerRef != rActor
         if PlayerRef.IsInInterior
             if 0 == rActor.GetInSameCell PlayerRef
;if 3 <= tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: %n is in the different cell from the player, halted." rActor 1
;endif
                sv_Destruct sv, svKey, svPathKey, svPathNif
                return
            endif
        else
            if PlayerRef.GetParentWorldSpace != rActor.GetParentWorldSpace
;if 3 <= tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: %n is in the different worldspace from the player, halted." rActor 1
;endif
               sv_Destruct sv, svKey, svPathKey, svPathNif
               return
           endif
        endif
    endif
;Let's not mess with other important mod items.
    Let i := GetSourceModIndex rItemBase
    if eval (ar_HasKey tsbrMain.arExclude i)
        sv_Destruct sv, svKey, svPathKey, svPathNif
        return
     endif
 
;We already have checked if the (registered) actor is an npc or a creature
;So additional checking shouldn't be needed
     Let svKey := GetRawFormIDString rActor
;We check if this event is set for the wrong actor.
     if 1 > rActor.GetItemCount a4tcWomb || rActor.GetIsSex Male
;if 3 <= tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: %n is not an appropriate subject, halted." rActor 1
;endif
        sv_Destruct sv, svKey, svPathKey, svPathNif
        return
    endif
    if eval !(ar_HasKey tsbrMain.arSpermOverrides svKey) ;this part functions only if this actor is not overridden by spermy.
Scribe "tsbrFnOnActorEquip:: %n not found in SpermOverride." rActor 1
        if 110 > rActor.GetItemCount a4tcWombState || 140 < rActor.GetItemCount a4tcWombState
Scribe "tsbrFnOnActorEquip:: and not pregnant either. return." 1
            sv_Destruct sv, svKey, svPathKey, svPathNif
            return
        endif
   endif
 
;We are not interested in weapons or anything like that.
   if 0 == IsArmor rItemBase && 0 == IsClothing rItemBase
;if 3 <= tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: %n's item %n is neither armor nor clothing, halted." rActor rItemBase 1
;endif
        sv_Destruct sv, svKey, svPathKey, svPathNif
        return
    endif
 
;Check if this item is compatible or what should we do with this.
;Get the mesh path of the item, and convert it to a compatible key
;Realism level 0 allows male actors getting pregnant, but we don't want to set them a pregnant belly anyway!
    Let iDefenseType := IsArmor rItemBase
    Let iDefenseType += GetArmorType rItemBase
    Let lSlotMask := GetBipedSlotMask rItemBase
    Let sv := GetBipedModelPath 1 rItemBase
    if 1 > sv_Length sv ;mesh path not found? then it may be a male-only item.
        Let sv := GetBipedModelPath 0 rItemBase
    endif
    if 1 > sv_Length sv ;still not found? bah, then this is a wrong item.
        sv_Destruct sv, svKey, svPathKey, svPathNif
        return
    endif
    Let svPathKey := Call tsbrFnGetPBPath sv 0 0 0
    Let svOrig := svPathKey + ".Nif"
;   Scribe " %rtsbrFnOnActorEquip:: %n sv = %z svPathKey = %z" rItemBase sv svPathKey
    Let bFoundPrg := Call tsbrFnCheckEquipment svPathKey lSlotMask iDefenseType
;if 2 <= tsbrMain.iDebug
;Scribe " %rtsbrFnOnActorEquip:: Found Prg meshes? = %g" bFoundPrg 1
;endif
    Let svKey := GetRawFormIDString rItemBase
    if 0 == bFoundPrg
        Let svPathKey := "" ;To check if we should apply the new mesh path or not.
    endif
 
;Else, we should see if we must pick a new random mesh for this item.
    if tsbrMain.bAllowRandomMesh && 0 == bFoundPrg
        if eval (ar_HasKey tsbrMain.arRandData[iDefenseType] lSlotMask)
            ForEach arIter <- tsbrMain.arRandData[iDefenseType][lSlotMask]
                Let rCurrItem := arIter["value"]["Object"]
                if rItemBase == rCurrItem
                    Let svPathKey := arIter["value"]["Key"]
                    Let bFoundRand := 1
;if 2 <= tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: Found a random mesh! = %z" svPathKey 1
;endif
                    break
                endif
            loop
            if eval !(ar_HasKey tsbrMain.arEquipPath[iDefenseType] lSlotMask)
;What? We had discovered this mesh before, but can't find it now? Then discover it again.
;This happens if the randomly assigned mesh path wasn't from the ini.
                Let bFoundRand := Call tsbrFnBuildEntry svPathKey lSlotMask iDefenseType
           elseif eval !(ar_HasKey tsbrMain.arEquipPath[iDefenseType][lSlotMask] svPathKey)
               Let bFoundRand := Call tsbrFnBuildEntry svPathKey lSlotMask iDefenseType
           endif
       endif
       if 0 == bFoundRand
;We either couldn't find the matching item at all, or the user has deleted the mesh.
;Whatever. Pick a random mesh path for this item.
           Let svPathKey := Call tsbrFnPickRandom rItemBase lSlotMask
        endif
   endif
 
   if 0 < sv_Length svPathKey
;if 2 <= tsbrMain.iDebug
;Scribe " %rtsbrFnOnActorEquip:: svPathKey is valid, processing = %z" svPathKey 1
;endif
;Now that we know we should swap the mesh path of this item, we need to know in which prg/ba state this actor is.
;Break Armor first, if any
        if IsModLoaded "BreakArmor.esp"
            Let iBa := Call tsbrFnGetBAIndex rActor rItemBase
;           if 0 == iBa
;               Let iBa := Call tsbrFnGetBAIndexAlt sv
;           endif
;Let's make sure that not having enough prg meshes causing out of index error.
            if eval (iBa > ar_Last tsbrMain.arEquipPath[iDefenseType][lSlotMask][svPathKey])
                Let iBa := ar_Last tsbrMain.arEquipPath[iDefenseType][lSlotMask][svPathKey]
            endif
        endif
;Womb State (Prg) next.
    Let i := ar_Size tsbrMain.arEquipPath[iDefenseType][lSlotMask][svPathKey][iBa]
    Let iPrg := Call tsbrFnGetWombStateIndex rActor i
;And get the new nif path with them.
        Let svPathNif := tsbrMain.arEquipPath[iDefenseType][lSlotMask][svPathKey][iBa][iPrg]
;       Scribe " %rtsbrFnOnActorEquip:: Final svPathNif = %z" svPathNif
;       if 0 == sv_Compare $sv svPathNif ;Commented out in v194, because this is causing incorrect mesh swap issue.
;;Too bad... this item's path doesn't need to be changed.
;if tsbrMain.iDebug
;Scribe "tsbrFnOnActorEquip:: Don't need to change path(%z), halted." sv 1
;endif
;           sv_Destruct sv, svKey, svPathKey, svPathNif
;           return
;       endif
;Change nif path here, and queue a new task in the swap queue array to revert the path back a few frames later
        SetFemaleBipedPath $svPathNif rItemBase
        if eval !(ar_HasKey tsbrActionQueueController.arSwapQueue svKey)
            Let tsbrActionQueueController.arSwapQueue[svKey] := ar_Construct StringMap
            Let tsbrActionQueueController.arSwapQueue[svKey]["Ref"] := rItemBase
            Let tsbrActionQueueController.arSwapQueue[svKey]["PathBack"] := svOrig
;           Let tsbrActionQueueController.arSwapQueue[svKey]["PathNew"] := svPathNif
            Let tsbrActionQueueController.arSwapQueue[svKey]["Counter"] := tsbrMain.iBADelayFrame
        else
;Overwrite the new path entry with the new one, hope this won't give too much trouble
;           Let tsbrActionQueueController.arSwapQueue[svKey]["PathNew"] := svPathNif
            Let tsbrActionQueueController.arSwapQueue[svKey]["Counter"] += tsbrMain.iBADelayFrame
        endif
        if 0 == GetQuestRunning tsbrActionQueueController
            StartQuest tsbrActionQueueController
            Let tsbrActionQueueController.iDelayFrame := 1
        endif
    endif
; Scribe "--------------------%r "
 
sv_Destruct sv, svKey, svPathKey, svPathNif
 
End

 

 

 

And it doesn't make half the sense the other one does

Posted

OK, I'll do my best.

-Script is an attempt so swap models based on "arousal" variable

-I recognize if (condition) elseif (other condition) else (condition not met) and endif (close sentence)

-For every arousal level, script checks if npc is male or female and then redirects to specific model

-When something == 0 it's false and when it's == 1 is true

 

All spot on! Scripts are less mysterious to you than some (grin). The places to learn more are:

http://cs.elderscrolls.com/index.php?title=Portal:Scripting

http://obse.silverlock.org/obse_command_doc.html

Be wanred, scripts are a lot of reading, learning and experimentation.

 

-Why beginfunction {actor, level, u3d}?

A function is a script then can be called from other scripts.

http://obse.silverlock.org/obse_command_doc.html#User_Defined_Functions

 

-Why set npcfemale to actor.getissex female?

I could have passed the sex of the actor but having already passed the ref, it makes sense to find the sex for certain. We do this because we want textures or meshes to be appropriate for the actors sex.

 

-What the hell is u3d?

The option to update the 3D of the actor, if doing so at this stage is desired. http://cs.elderscrolls.com/index.php?title=Update3D

A lot of people think this is buggy when used on the player, but it seems to work fine IF you remember it updates the current 1st/3rd person view. So if the player is in 1st person and you want to update the 3rd person (the usual thing you want to do), it will not work. You have to switch to a 3rd person view first, then call update3d.

 

-Is printc a pop up message?

No. A diagnostic message to the console.

 

-How is is that level refers to arousal level and not any other kind of level... there must be a lot of "level" variables in game...

Arousal level is part of the ASX mod Nessa and I are working on.

(http://www.loverslab.com/topic/13194-asxwipthe-sisterhood-of-sin/?)

 

-How to work with ref Means reference right?

Spot on!

 

-What is short

A number: http://cs.elderscrolls.com/index.php?title=Short_Integer

 

-What in oblivion are those numbers at the end of nif files?

Block head parameters. The first is the body part being set. The second 2 means 'a mesh'. A 1 would have meant 'a texture'.

 

Hope that helps a bit. Scripting is a big subject! I program for a living and many Oblivion mods reveal to me that the author found scripting really hard too!

Posted

Thank you!

I guess there's no place for TLDR on this stuff...  :lol:

 

Well I got my reading to do...

 

In the meantime I'd like to keep speculating on the final vision of the project

How would you guys do an effective mesh swap for beast races?

Should I focus on Blockhead?

Or perhaps Tamago Setbody is a better option as it also engages the problem of armor and clothing?

Is Blockhead any useful for this anyway? Or perhaps as it functions only for nude models I should be returning to scripts?

Posted

Enthusiasm, aren't you!

 

Firstly let's clarify your objectives. You want to achieve two different goals, swap nude bodies and swap armors. They are different.

Some below may not make sense to you right now, well just don't panic and read on.

 

For nude bodies, blockhead should do the job. Satyrist made a beast body add-on for setbody reloaded, you can use that one to automatically assign beast bodies to beast races. At the moment setbody has a nasty bug with that add-on pack, but the fixed version will be released very soon.

http://www.loverslab.com/topic/36199-setbody-beast-body-menu-add-on/

 

If you go for scripting it yourself, using blockhead is as simple as typing this:

;Blockhead Body Parts convention
;2	upperbody
;3	lowerbody
;4	hand
;5	foot
;15	tail
	rActor.SetBodyAssetOverride $sFootPath 5 2
	rActor.SetBodyAssetOverride $sHandPath 4 2
	rActor.SetBodyAssetOverride $sUpperbodyPath 2 2
	rActor.SetBodyAssetOverride $sLowerbodyPath 3 2
This is the part that you were seeking in setbody reloaded, this is all. Isn't it simple! What isn't simple is other stuff, building data arrays, constructing menu structure with indefinite number of items, updating actors, and so forth. These "other" works consume over 90% of setbody scripts.

 

Speaking of updating actors, I don't use update3D because of two reasons. First, it resets whatever animation that is currently playing. Second, when called on the player, it sometimes makes the game report player's state as playing animation, causing you to be stuck with the current weapon (including bare hands), you can't equip anything else just like when you are attacking. However, using update3D has one certain advantage - you can finish the job in the same frame (npcs can not be updated within one frame without update3D).

 

 

For swapping armors, the example plugin you've picked(tamago setbody) isn't bad.

EXCEPT, it is way too complicated for a starter. Actually it isn't that horrible, just you are confused by all the fancy expressions, idioms, abbreviations.

 

Generally speaking, making sense of scripts means you anyway will have to learn how to code scripts yourself. And the fastest way to learn scripting is to grab an example plugin, see what's going on and write one by your own, imitating the workflow of your chosen example.

 

Now that you said you can make sense of basic scripts, you can try a bit further. The best scripting guide for obse/nvse scripting is by one of our mods Doctasax and they can be found here:

http://www.loverslab.com/topic/26749-tutorial-nvse4-part-1-syntax-and-expressions/

http://www.loverslab.com/topic/26802-tutorial-nvse4-part-2-user-defined-functions-udfs/

http://www.loverslab.com/topic/26963-tutorial-nvse4-part-3-string-variables/

http://www.loverslab.com/topic/27076-tutorial-nvse4-part-4-array-variables/

http://www.loverslab.com/topic/39417-tutorial-nvse4-part-5-event-handlers-user-defined-events-udes/

 

One important trick in unassemblying any kind of script-based mod is to find the right entry point. It's in many cases a quest script and tend to be named as "init" or "main" or something like that. If the mod has multiple quests, the entry point quest is most likely set as "start-game enabled".

Basically every script runs top to bottom, above to below, but keep in mind that it does not mean the actual workflow starts from the top. And in oblivion every variable is initially numeric zero, so if you encounter a new variable used that has never been assigned of any value, assume it to be a zero.

 

So.. let me recommend a slightly better example plugin.

https://www.loverslab.com/topic/37578-player-clothing-replacer/

This one. It's a very very simple plugin that is solely dedicated to swapping player's equipments, and only the player's. Its scripts are very short too, so a bit easier to understand, and yet it features some example uses of array, string and event handler.

The bad side is that I didn't bother documenting it at all. My bad practice. Speaking of commenting, Break Armor is very kindly documented; it explains how and why do something, almost line by line. Although it works a bit differently than tamago setbody or player clothing replacer, and although it's quite complex by its own, it should give you a good idea of the detailed workflow of a mesh-swap framework.

Tamago setbody is kind of even more complicated than Break Armor. But the basic idea is exactly same as player clothing replacer which is very simple. So the complexity of tamago setbody shouldn't be a problem once you get the hang of it.

 

Feel free to throw a question when you get stumped. I'll try to explain it in more detail.

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...