Jump to content

[WIP] Bodyoptions - Wear every armor, no matter which Body you have


DividedByZero

Recommended Posts

Requirements:

SKSE

 

Don't you think it's annoying, too? Having a CBBE Body, but finding an UNP based Armor that looks amazing, however you can't wear it without changing your entire base Body (and all other CBBE Mods) or else you have ugly textures? The only way being to wait for a CBBE Version or make one yourself (which is kind of impossible when you are inexperienced with 3D Tools).

 

Well my (very first) mod fixes that. Wear a UNP Armor and your Body will "magically" transform into an UNP one. Unequip the Armor und year normal body will be restored.

 

An example: Here you can see my Lunari girl, she is the CBBE Version of that mod (custom Mesh though).

post-23176-0-49266300-1389647058_thumb.jpg

 

She wants to wear the Witch Elf Armour. Well that Witch Elf Armour is a UNP Armor so it will usually look like this.

post-23176-0-51622000-1389648230_thumb.jpg

 

However to "fix" this issue, all we have to do is to open the "Witch Elf Armour.esp" in the CK and attach a simple script to the cuirass... nothing more nothing less. The script itself recognizes wether or not Bodyoptions.esp is active or not, so setting it as a master isn't required. Additionally only the "defining" Armor needs that script... Hands and Feet usually don't need an entirely new Skin as they work together rather well, even on different Bodies. So the Body Armor should usually be the only Armor to recieve the script.

post-23176-0-42097600-1389648337_thumb.png

(In Later Versions the Scripts for other body types would be called BodyCBBE, BodyADEC and BodyCHSBHC)

 

Now back in the game, whenever we equip the Armor, the Body textures will change to UNP ones.

post-23176-0-56508800-1389648502_thumb.jpg

 

How to make custom Races compatible:

Well, making Armors compatible is easy, however Races are an entirely different beast. It's not exactly hard to make them compatible, but it is extremly repetitve and tedious to do so.

 

We practicly make a copy of everything in your Race (female version) that has somehow to do with your Skin. This includes:

  • The Skin Armor
  • The corresponding ArmorAddons
  • A copy of FormID Lists that include Texture Sets (such as SkinRacenameFemaleBody, SkinRacenameFemaleHands etc.)
  • The Headpart that includes the Head mesh (e.g. FemaleHeadRacename)
  • All TextureSets that have the paths to your (female) races textures (e.g. SkinHeadRacename, SkinBodyRacename, SkinHandRacename and sometimes SkinFeetRacename

This is best done in TesVEdit, as you can easily both modify the EditorID of all these entries (select them all, copy them as new record into the same esp and add something like UNP to the EditorID suffix, to make them easily distinguishable). However VERY important here is, that both the new Headpart AND Armor Skin have an Offset in their FormID. I chose the Offset high enough to NOT interfere with other FormIDs (unless your Race mod is gargantuan). A new Headpart is used, since not every UNP texture set lines up with a head texture from the CBBE set. In this case the Offset is 0x00100000, that means if the "original" Skin/HeadPart has a FormID of e.g. [9C011B8C] (with 9C being the load order of our Plugin), then the FormID of the UNP Version has to be [9C111B8C]. As the script uses the Offset to find the new Skin that way (however that way no further FormID Lists or other script aren't needed).

 

The offsets are the following (already planned for future versions):

[00100000] - UNP Body Set

[00200000] - CBBE Body Set

[00300000] - ADEC Body Set

[00400000] - CHSBHC Body Set

 

Additionally the Full Name (not EditorID) of the HeadPart has to contain the Word "Head" or "head", as the script uses this Substring to find the corresponding HeadPart Slot (these can be random and aren't the same in every race).

 

After doing this you can use the CK to attach UNP Base Body meshes to our "new" ArmorAddons (UNP Hand Meshes to the Hand ArmorAddons etc.) as well as attaching the "new" TextureSets and Texture Swap Set FormID Lists to these Addons. (Same goes for the HeadParts)

 

The Armor Skin will get these new ArmorAddons and additionally a Keyword from the Bodyoptions.esp (so that one as master is needed). This Keyword is called "UNPBody" with the FormID of [xx002945]. This Keyword helps the script in identfiying what sort of Skin you are actually wearing right now (and maybe it will help later for other purposes).

 

After that you will to change the TextureSets in your FormID Lists and HeadParts as well.

 

Last you simply have to change all the paths in your copied Texture Lists, so that they show to your UNP textures.

 

Last you can simply save your race mod and try it out yourself.

 

 

 

This is now the earliest release. IMO the Scripts are still sloppy (as I'm still inexperienced in Papyrus) and could be done better and I bet that a lot of bugs are still in them. That's why I would like a lot of feedback for bugfixing. I will first hunt down all Bugs I come accross before I start implementing other support for other Skins, as I prefer a stable mod over a big one.

 

Also since you have to do so much yourself makes it more of a "Framework" than an actual Mod ad that point.

 

Also you have to excuse me if development will be slow, as university exams are closing in. Additionally a timezone difference of 7 hours will make my responce time longer as well.

 

Update 14.01.2014:

I completly rebuilt my Script Architecture, I moved from Keywords to using Factions (so Keywords were removed and aren't needed anymore). There are twelve Factions:

Default, Temporary and Permanent, for each of the 4 Body Types. (Though I don't have scripts yet to make properly use of the Default and Permanent Body, the Temporary Body works as intended)

 

DefaultBodyUNP

DefaultBodyCBBE

DefaultBodyADEC

DefaultBodyCHSBHC

These Factions mark the "default" Body Type of an Actor, basically what it means is that if you already have an UNP Body as your Base Mesh/Texture, than you will ad your Actor and everyone else, I need a future Script for that, maybe via MCM) and basically tell all your UNP Armors with the attached script to do nothing instead.

 

PermBodyUNP

PermBodyCBBE

PermBodyADEC

PermBodyCHSBHC

They don't have a use yet, but I want to use them to apply a new Base Skin to an Actor, similar to the SetBody mod in Oblivion

 

TempBodyUNP

TempBodyCBBE

TempBodyADEC

TempBodyCHSBHC

These now work to show how many pieces of what Body Type you have currently equipped (faction Rank = number of Armors) the Faction with the highest count will be displayed. Additionally it causes, that if you switch from one UNP Armor to the next, that the new Skin will be Skipped, making everything faster.

 

Tomorrow I will start working on support for all the other Body types.

 

 

Downloads:

MEGA: Bodyoptions v0.1 - first release

MEGA: Bodyoptions v0.2   14.01.2014 - redone Script architecture for better Performance and easier Upgrading

MEGA: UNP Meshes & Textures based on CBBE-CHSBHC-UNP-ADEC-Human Argonian Khajiit Texture-4096 by AnTiWoMaAgNoT to showcase the file structure (for playable Vanilla races) and make you be able to start off with textures and meshes.

MEGA: Lunari UNP Meshes and Textures Meshes, Textures and a modified LunariRace.esp for the Lunari Race to showcase how it works with custom Races

Witch Elf Armour.esp Witch Elf Armour with integrated script, original is required

 

To do:

-UNP Support

-Bug hunting

-CBBE Support

-ADEC Support

-CHSBHC Support

 

-Figuring out how to make a ReProccer to make everything less tedious

-Make a SetBody spell

 

Script Source Code (for Review) Version 14.01.2014:

BodyUNP.psc

 

 

Scriptname BodyUNP extends ObjectReference
import Game
import FormIDSupport
import BodyFactionController

Event OnEquipped(Actor akActor)
	if(GetModByName("Bodyoptions.esp") != 255); is Mod present?
		Faction DefaultUNPBody = GetFormFromFile(0x00003977, "Bodyoptions.esp") as Faction
		if(!akActor.IsInFaction(DefaultUNPBody))
			Faction TempUNPFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
			BodyFactionController.TestBodyFactions(akActor)
			akActor.ModFactionRank(TempUNPFaction, 1)
			BodyFactionController.ApplyCurrentTempSkin(akActor)
		endif
	endif
EndEvent

Event OnUnequipped(Actor akActor)	
	if(GetModByName("Bodyoptions.esp") != 255); is Mod present?
		Faction DefaultUNPBody = GetFormFromFile(0x00003977, "Bodyoptions.esp") as Faction
		if(!akActor.IsInFaction(DefaultUNPBody))
			Faction TempUNPFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
			BodyFactionController.TestBodyFactions(akActor)
			akActor.ModFactionRank(TempUNPFaction, -1)
			if(akActor.getFactionRank(TempUNPFaction) < 1) ;If there are still UNP Armors, keep the current temporary Skin
				BodyFactionController.ApplyCurrentPermSkin(akActor, 1) ;BodyType = 1 (UNP)
			endif
		endif
	endif
EndEvent

 

 

 

FormIDSupport.psc

 

 

Scriptname FormIDSupport extends Game
Import Math
Import StringUtil

;Returns the Filename of the current FormID
String function GetModByForm(int FormID) global
int modID = RightShift(FormID, 24) ;Reduces FormID to Mod ID. e.g. 0x9c11138c becomes 0x0000009c
return Game.GetModName(modID)
endfunction

;Returns a Form by adding an offset to a FormID
Form function GetFormByOffset(int FormID, int Offset) global
;normalize FormID e.g. 0x9c11138c becomes 0x0011138c
int normForm = RightShift(LeftShift(FormID, 8),8)
Form newForm = Game.GetFormFromFile(normForm+Offset, GetModByForm(FormID))
return newForm
endfunction

;returns the Slot Number of an ActorBase that contains his/her Head, -1 when there is no HeadSlot
int function getHeadSlot(ActorBase akActorBase) global
	int i = 0
	int slot = 0
	while(i < akActorBase.GetNumHeadParts())
		String HeadPartName = akActorBase.GetNthHeadPart(i).GetName()
		if(Find(HeadPartName,"Head") != -1 || Find(HeadPartName,"head") != -1) ;HeadParts containing the Name String "Head" or "head" are chosen
			slot = i
			return slot
		endif
		i += 1
	endwhile
	return -1
endfunction

 

 

 

BodyFactionController.psc

 

 

Scriptname BodyFactionController
import FormIDSupport
import Game
import Form

;Tests wether or not the current Actor is part of the Body Factions and adds them when necessary
function TestBodyFactions(Actor akActor) global
	Faction TempUNPFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCBBEFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempADECFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCHSBHCFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction PermUNPFaction = GetFormFromFile(0x00003411, "Bodyoptions.esp") as Faction
	Faction PermCBBEFaction = GetFormFromFile(0x0000340f, "Bodyoptions.esp") as Faction
	Faction PermADECFaction = GetFormFromFile(0x0000340e, "Bodyoptions.esp") as Faction
	Faction PermCHSBHCFaction = GetFormFromFile(0x00003410, "Bodyoptions.esp") as Faction
	if(!akActor.IsInFaction(TempUNPFaction))
		akActor.AddToFaction(TempUNPFaction)
	endif
	if(!akActor.IsInFaction(TempCBBEFaction))
		akActor.AddToFaction(TempCBBEFaction)
	endif
	if(!akActor.IsInFaction(TempADECFaction))
		akActor.AddToFaction(TempADECFaction)
	endif
	if(!akActor.IsInFaction(TempCHSBHCFaction))
		akActor.AddToFaction(TempCHSBHCFaction)
	endif
	if(!akActor.IsInFaction(PermUNPFaction))
		akActor.AddToFaction(PermUNPFaction)
	endif
	if(!akActor.IsInFaction(PermCBBEFaction))
		akActor.AddToFaction(PermCBBEFaction)
	endif
	if(!akActor.IsInFaction(PermADECFaction))
		akActor.AddToFaction(PermADECFaction)
	endif
	if(!akActor.IsInFaction(PermCHSBHCFaction))
		akActor.AddToFaction(PermCHSBHCFaction)
	endif
endfunction

;Returns the Faction with the highest Rank (most equipment pieces) as the primary one... this is the one that will be displayed
Faction function GetPrimarySkinFaction(Actor akActor) global
	Faction TempUNPFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCBBEFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempADECFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCHSBHCFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction highestFaction = TempUNPFaction
	if(akActor.getFactionRank(highestFaction) < akActor.getFactionRank(TempCBBEFaction))
		highestFaction = TempCBBEFaction
	endif
	if(akActor.getFactionRank(highestFaction) < akActor.getFactionRank(TempCBBEFaction))
		highestFaction = TempCBBEFaction
	endif
	if(akActor.getFactionRank(highestFaction) < akActor.getFactionRank(TempADECFaction))
		highestFaction = TempADECFaction
	endif
	if(akActor.getFactionRank(highestFaction) < akActor.getFactionRank(TempCHSBHCFaction))
		highestFaction = TempCHSBHCFaction
	endif
	if(akActor.getFactionRank(highestFaction) > 0)
		return highestFaction
	else
		return None
	endif
endfunction

;Apply the actors Current temporary Skin
function ApplyCurrentTempSkin(Actor akActor) global
	int headSlot = FormIDSupport.getHeadSlot(akActor.getActorBase())
	Faction TempUNPFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCBBEFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempADECFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction TempCHSBHCFaction = GetFormFromFile(0x0000340a, "Bodyoptions.esp") as Faction
	Faction currentTempBody = GetPrimarySkinFaction(akActor)
	if(currentTempBody == TempUNPFaction)
		changeSkin(akActor, GetUNPSkin(akActor), GetUNPHead(akActor, headSlot), headSlot)
	elseif(currentTempBody == TempCBBEFaction)
	;
	elseif(currentTempBody == TempADECFaction)
	;
	elseif(currentTempBody == TempCHSBHCFaction)
	;
	endif
endfunction

;sets the default Body of an Actor, meaning the base Skin of the Race itself (1 = UNP, 2 = CBBE, 3 = ADEC, 4 = CHSBHC)
function SetDefaultBodyType(Actor akActor, int BodyType) global
	Faction DefaultUNPFaction = GetFormFromFile(0x00003977, "Bodyoptions.esp") as Faction
	Faction DefaultCBBEFaction = GetFormFromFile(0x00003975, "Bodyoptions.esp") as Faction
	Faction DefaultADECFaction = GetFormFromFile(0x00003974, "Bodyoptions.esp") as Faction
	Faction DefaultCHSBHCFaction = GetFormFromFile(0x00003976, "Bodyoptions.esp") as Faction
	if(akActor.IsInFaction(DefaultUNPFaction))
		akActor.RemoveFromFaction(DefaultUNPFaction)
	elseif(akActor.IsInFaction(DefaultCBBEFaction))
		akActor.RemoveFromFaction(DefaultCBBEFaction)
	elseif(akActor.IsInFaction(DefaultADECFaction))
		akActor.RemoveFromFaction(DefaultADECFaction)
	elseif(akActor.IsInFaction(DefaultCHSBHCFaction))
		akActor.RemoveFromFaction(DefaultCHSBHCFaction)
	endif
	if(BodyType == 1)
		akActor.AddToFaction(DefaultUNPFaction)
	elseif(BodyType == 2)
		akActor.AddToFaction(DefaultCBBEFaction)
	elseif(BodyType == 3)
		akActor.AddToFaction(DefaultADECFaction)
	elseif(BodyType == 4)
		akActor.AddToFaction(DefaultCHSBHCFaction)
	endif
endfunction

;gets the default Body of an Actor, meaning the base Skin of the Race itself (1 = UNP, 2 = CBBE, 3 = ADEC, 4 = CHSBHC)
int function getDefaultBodyType(Actor akActor) global
Faction DefaultUNPFaction = GetFormFromFile(0x00003977, "Bodyoptions.esp") as Faction
	Faction DefaultCBBEFaction = GetFormFromFile(0x00003975, "Bodyoptions.esp") as Faction
	Faction DefaultADECFaction = GetFormFromFile(0x00003974, "Bodyoptions.esp") as Faction
	Faction DefaultCHSBHCFaction = GetFormFromFile(0x00003976, "Bodyoptions.esp") as Faction
	if(akActor.IsInFaction(DefaultUNPFaction))
		return 1
	elseif(akActor.IsInFaction(DefaultCBBEFaction))
		return 2
	elseif(akActor.IsInFaction(DefaultADECFaction))
		return 3
	elseif(akActor.IsInFaction(DefaultCHSBHCFaction))
		return 4
	else
		return 0
	endif
endfunction

;Apply the actors Current permanent Skin or restores Default skin with the help of the last BodyType
function ApplyCurrentPermSkin(Actor akActor, int BodyType) global
	int headSlot = FormIDSupport.getHeadSlot(akActor.getActorBase())
	Faction PermUNPFaction = GetFormFromFile(0x00003411, "Bodyoptions.esp") as Faction
	Faction PermCBBEFaction = GetFormFromFile(0x0000340f, "Bodyoptions.esp") as Faction
	Faction PermADECFaction = GetFormFromFile(0x0000340e, "Bodyoptions.esp") as Faction
	Faction PermCHSBHCFaction = GetFormFromFile(0x00003410, "Bodyoptions.esp") as Faction
	if(akActor.getFactionRank(PermUNPFaction) > 0)
		changeSkin(akActor, GetUNPSkin(akActor), GetUNPHead(akActor, headSlot), headSlot)
	elseif(akActor.getFactionRank(PermCBBEFaction) > 0)
	;
	elseif(akActor.getFactionRank(PermADECFaction) > 0)
	;
	elseif(akActor.getFactionRank(PermCHSBHCFaction) > 0)
	;
	else
		changeSkin(akActor, None, GetBaseHead(akActor,headSlot,BodyType*(0x00100000)), headSlot) ;use Body Type number to find correct customRace Offset to reverse back
	endif
endfunction

;Changes a players Skin to the desired one
function changeSkin(Actor akActor, Armor akArmor, HeadPart akHead, int headSlot) global
	akActor.getActorBase().setSkin(akArmor)
	akActor.getActorBase().setNthHeadPart(akHead, headSlot)
	if(!akActor.IsOnMount())
	akActor.QueueNiNodeUpdate()
	endif
endfunction

;Get the Base Head for the player, the Offset is meant as a countermeasure for custom races (0x00100000 for UNP, 0x00200000 for CBBE, , 0x00300000 for ADEC, , 0x00400000 for CHSBHC)
HeadPart function GetBaseHead(Actor akActor, int headSlot, int Offset) global
	if(GetModByName("Bodyoptions.esp") != 255); is Mod present?
		FormList RaceList = GetFormFromFile(0x00002944, "Bodyoptions.esp") as FormList
		Race actorrace = akActor.GetRace()
		if(akActor.getActorBase().getSex() == 1) ;Actor female?
			if(RaceList.HasForm(actorrace));Vanilla Race
				if(actorrace == Race.getRace("OrcRace") || actorrace == Race.getRace("OrcRaceVampire") ) ;OrcRace+Vampire
				return GetForm(0x0005161b) as HeadPart
				elseif(actorrace == Race.getRace("WoodElfRace") || actorrace == Race.getRace("WoodElfRaceVampire") ) ;WoodElfRace+Vampire
				return GetForm(0x0005161f) as HeadPart	
				elseif(actorrace == Race.getRace("RedguardRace") || actorrace == Race.getRace("RedguardRaceVampire") ) ;RedguardRace+Vampire
				return GetForm(0x00051622) as HeadPart	
				elseif(actorrace == Race.getRace("NordRaceVampire") || actorrace == Race.getRace("NordRaceVampire") ) ;NordRace+Vampire
				return GetForm(0x00051623) as HeadPart	
				elseif(actorrace == Race.getRace("ImperialRace") || actorrace == Race.getRace("ImperialRaceVampire") ) ;ImperialRace+Vampire
				return GetForm(0x0005161d) as HeadPart	
				elseif(actorrace == Race.getRace("HighElfRace") || actorrace == Race.getRace("HighElfRaceVampire") ) ;HighElfRace+Vampire
				return GetForm(0x0005161e) as HeadPart	
				elseif(actorrace == Race.getRace("DarkElfRace") || actorrace == Race.getRace("DarkElfRaceVampire") ) ;DarkElfRace+Vampire
				return GetForm(0x0005161c) as HeadPart	
				elseif(actorrace == Race.getRace("BretonRace") || actorrace == Race.getRace("BretonRaceVampire") ) ;BretonRace+Vampire
				return GetForm(0x00051621) as HeadPart	
				elseif(actorrace == Race.getRace("KhajiitRace") || actorrace == Race.getRace("KhajiitRaceVampire") ) ;KhajiitRace+Vampire
				return GetForm(0x00051612) as HeadPart
				elseif(actorrace == Race.getRace("ArgonianRace") || actorrace == Race.getRace("ArgonianRaceVampire") ) ;ArgonianRace+Vampire
				return GetForm(0x00051613) as HeadPart
				endif
			else; custom Race
				return GetFormByOffset(akActor.getActorBase().getNthHeadPart(headSlot).getFormID() , -Offset) as HeadPart
			endif
		endif	
	endif
endfunction

;Get UNP Skin for the Actor
Armor function GetUNPSkin(Actor akActor) global
	if(GetModByName("Bodyoptions.esp") != 255); is Mod present?
		FormList RaceList = GetFormFromFile(0x00002944, "Bodyoptions.esp") as FormList
		Race actorrace = akActor.GetRace()
		if(akActor.getActorBase().getSkin() == None)
		akActor.getActorBase().setSkin(actorrace.getSkin())
		endif
		if(akActor.getActorBase().getSex() == 1) ;Actor female?
			if(RaceList.HasForm(actorrace));Vanilla Race
				if(actorrace == Race.getRace("OrcRace") || actorrace == Race.getRace("OrcRaceVampire") ) ;OrcRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("WoodElfRace") || actorrace == Race.getRace("WoodElfRaceVampire") ) ;WoodElfRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("RedguardRace") || actorrace == Race.getRace("RedguardRaceVampire") ) ;RedguardRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("NordRace") || actorrace == Race.getRace("NordRaceVampire") ) ;NordRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("ImperialRace") || actorrace == Race.getRace("ImperialRaceVampire") ) ;ImperialRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor	
				elseif(actorrace == Race.getRace("HighElfRace") || actorrace == Race.getRace("HighElfRaceVampire") ) ;HighElfRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("DarkElfRace") || actorrace == Race.getRace("DarkElfRaceVampire") ) ;DarkElfRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("BretonRace") || actorrace == Race.getRace("BretonRaceVampire") ) ;BretonRace+Vampire
				return GetFormFromFile(0x00001db9, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("KhajiitRace") || actorrace == Race.getRace("KhajiitRaceVampire") ) ;KhajiitRace+Vampire
				return GetFormFromFile(0x00001e58, "Bodyoptions.esp") as Armor
				elseif(actorrace == Race.getRace("ArgonianRace") || actorrace == Race.getRace("ArgonianRaceVampire") ) ;ArgonianRace+Vampire
				return GetFormFromFile(0x00001e58, "Bodyoptions.esp") as Armor
				endif
			else ;custom Race
				return GetFormByOffset(akActor.getRace().getSkin().getFormID(), 0x00100000) as Armor
			endif
		endif	
	endif
endfunction

HeadPart function GetUNPHead(Actor akActor, int headSlot) global
	if(GetModByName("Bodyoptions.esp") != 255); is Mod present?
		FormList RaceList = GetFormFromFile(0x00002944, "Bodyoptions.esp") as FormList
		Race actorrace = akActor.GetRace()
		if(akActor.getActorBase().getSex() == 1) ;Actor female?
			if(RaceList.HasForm(actorrace));Vanilla Race
				if(actorrace == Race.getRace("OrcRace") || actorrace == Race.getRace("OrcRaceVampire") ) ;OrcRace+Vampire
				return GetFormFromFile(0x00001e73, "Bodyoptions.esp") as HeadPart
				elseif(actorrace == Race.getRace("WoodElfRace") || actorrace == Race.getRace("WoodElfRaceVampire") ) ;WoodElfRace+Vampire
				return GetFormFromFile(0x00001e75, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("RedguardRace") || actorrace == Race.getRace("RedguardRaceVampire") ) ;RedguardRace+Vampire
				return GetFormFromFile(0x00001e74, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("NordRaceVampire") || actorrace == Race.getRace("NordRaceVampire") ) ;NordRace+Vampire
				return GetFormFromFile(0x00001e72, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("ImperialRace") || actorrace == Race.getRace("ImperialRaceVampire") ) ;ImperialRace+Vampire
				return GetFormFromFile(0x00001e70, "Bodyoptions.esp") as HeadPart
				elseif(actorrace == Race.getRace("HighElfRace") || actorrace == Race.getRace("HighElfRaceVampire") ) ;HighElfRace+Vampire
				return GetFormFromFile(0x00001e6f, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("DarkElfRace") || actorrace == Race.getRace("DarkElfRaceVampire") ) ;DarkElfRace+Vampire
				return GetFormFromFile(0x00001e6e, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("BretonRace") || actorrace == Race.getRace("BretonRaceVampire") ) ;BretonRace+Vampire
				return GetFormFromFile(0x00001e6d, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("KhajiitRace") || actorrace == Race.getRace("KhajiitRaceVampire") ) ;KhajiitRace+Vampire
				return GetFormFromFile(0x00001e71, "Bodyoptions.esp") as HeadPart	
				elseif(actorrace == Race.getRace("ArgonianRace") || actorrace == Race.getRace("ArgonianRaceVampire") ) ;ArgonianRace+Vampire
				return GetFormFromFile(0x00001e6c, "Bodyoptions.esp") as HeadPart
				endif
			else; custom Race
				return GetFormByOffset(akActor.getActorBase().getNthHeadPart(headSlot).getFormID() , 0x00100000) as HeadPart
			endif
		endif	
	endif
endfunction

 

 

Link to comment

To be honest, I just edit the armor's mesh in Nifskope to change the texture links on the body to point to a set of that body mod's textures. It's pretty easy...

 

jH4pt8C.png

 

Just make some folders like...

textures\actors\character\female\unp\

textures\actors\character\female\7b\

textures\actors\character\female\adec\

 

Then put those textures in those folders, then any time you have an armor mod with those bodies you just click the skin texture in the view then expand it down to the BSShaderTextureSet and just change all the links to add unp\ or adec\, or whatever.

 

If you're gonna have to edit stuff anyways, this way you don't have to mess with scripting.

Link to comment

This seems useful, and it would be nice that people started making outfits with this by default.

 

in any case, what I do is to use this mod that somebody pointed me a couple days ago. It's really cool, and after some setup you don't really need to worry about scripting or anything like that. All you need is to install the mod and whenever you equip an outfit whose body doesn't match, pop the "change body" spell for dozens of options.

 

Of course it would be nice to have outfits that don't require even this, but I do like the idea of being able to switch body types. Maybe your mod could handle that by using "bodysuits" in the shape of the other bodies.

Link to comment

To be honest, I just edit the armor's mesh in Nifskope to change the texture links on the body to point to a set of that body mod's textures. It's pretty easy...

-snip-

 

Just make some folders like...

textures\actors\character\female\unp\

textures\actors\character\female\7b\

textures\actors\character\female\adec\

 

Then put those textures in those folders, then any time you have an armor mod with those bodies you just click the skin texture in the view then expand it down to the BSShaderTextureSet and just change all the links to add unp\ or adec\, or whatever.

 

If you're gonna have to edit stuff anyways, this way you don't have to mess with scripting.

 

This actually doesn't work (for me at least), because the TextureSets are applied to the Skin part of the .nif, overwriting every texture it may have (how else are different textures for the same body possible). You could of course change the Attrivute of that part as well (making it effectively clothes), however that could:

  1. mess up your Tinting
  2. Disable different Textures for Different Races

For 2. You would have to create a seperate Version with that Texture and then make Race specific ArmorAddons.

And even if skin change/tinting alone worked that way... this becomes even more Tireseome when workinf with LOTS of Armors, because you basically have to create 2 Versions for EVERY Armor (the _0 and _1.nif) and that for EVERY seperate body texture you may have (so for vanilla races you need 6 Armors: 2 original, 2 Khajiit and 2 Argonian)... my way would be much much easier to implement for Armors.

 

Believe me: I have that idea ever since the concept between CBBE, UNP (and later ADEC) surfaced and I tried your alternative many times already... this is simply the best way I could come up with to handle that problem.

Link to comment

Nice, When i read the title I thought with this mod you can wear any armor you like and your body will not change with the one armor has in it and will remain the same...lol

But the textures thing is also very helpful if you are using either cbbe or unp or whatever body and want to wear other body mod's armor..

Link to comment

Update 14.01.2014:

I completly rebuilt my Script Architecture, I moved from Keywords to using Factions (so Keywords were removed and aren't needed anymore). There are twelve Factions:

Default, Temporary and Permanent, for each of the 4 Body Types. (Though I don't have scripts yet to make properly use of the Default and Permanent Body, the Temporary Body works as intended)

 

DefaultBodyUNP

DefaultBodyCBBE

DefaultBodyADEC

DefaultBodyCHSBHC

These Factions mark the "default" Body Type of an Actor, basically what it means is that if you already have an UNP Body as your Base Mesh/Texture, than you will ad your Actor and everyone else, I need a future Script for that, maybe via MCM) and basically tell all your UNP Armors with the attached script to do nothing instead.

 

PermBodyUNP

PermBodyCBBE

PermBodyADEC

PermBodyCHSBHC

They don't have a use yet, but I want to use them to apply a new Base Skin to an Actor, similar to the SetBody mod in Oblivion

 

TempBodyUNP

TempBodyCBBE

TempBodyADEC

TempBodyCHSBHC

These now work to show how many pieces of what Body Type you have currently equipped (faction Rank = number of Armors) the Faction with the highest count will be displayed. Additionally it causes, that if you switch from one UNP Armor to the next, that the new Skin will be Skipped, making everything faster.

 

Tomorrow I will start working on support for all the other Body types.

Link to comment

TempBodyUNP

TempBodyCBBE

TempBodyADEC

TempBodyCHSBHC

These now work to show how many pieces of what Body Type you have currently equipped (faction Rank = number of Armors) the Faction with the highest count will be displayed. Additionally it causes, that if you switch from one UNP Armor to the next, that the new Skin will be Skipped, making everything faster.

 

Not sure about it, but wouldn't this actually be wrong? Usually what rules what body you're using is the body piece. If you had a body piece for CBBE for example, and three more for UNP because they don't clip too much, wouldn't that make the body look bad?

 

Just a noob question.

Link to comment

 

TempBodyUNP

TempBodyCBBE

TempBodyADEC

TempBodyCHSBHC

These now work to show how many pieces of what Body Type you have currently equipped (faction Rank = number of Armors) the Faction with the highest count will be displayed. Additionally it causes, that if you switch from one UNP Armor to the next, that the new Skin will be Skipped, making everything faster.

 

Not sure about it, but wouldn't this actually be wrong? Usually what rules what body you're using is the body piece. If you had a body piece for CBBE for example, and three more for UNP because they don't clip too much, wouldn't that make the body look bad?

 

Just a noob question.

 

 

My recommendation is actually to ONLY have the chestpiece have the script, and that is the most important one. Feet and Hand textures are usually compatible between CBBE, UNP etc. as they are mostly based upon the same Mesh (the standard hand/feet nif) and therefore have the same UV Map.

 

The reason why I did it was because of how the script fired when switching from one UNP Armor directly to another. Basically what would happen is that instead of FIRST using OnUnequipped() of the old Armor and then using OnEquipped() on the new it would do it the other way around and cause issues (basically it would revert to the default body).

 

With the Temp Factions I can basically control the number of pieces you are currently wearing, as the "Rank" of the Faction (as stated)... It's basically a simple "hack" against that issue, hell I even managed to make it more efficient basically every time the UNP OnEquipped() is called the Rank of your TempUNP Faction raises by one (unless of course you declared the UNP Body already as either your Default Body or Permanent Skin). Same goes for OnUnequipped, it simply lowers the rank by 1.

 

That way, I make use of the bug for switching from one UNP Body to another as the rank doesn't go from 1 to 0 to 1 again (meaning: equip UNP Skin, unequip it and then equip it again), but rather from 1 to 2 to 1 (meaning: never unequip UNP Body)

 

I rather wanted o work with factions than global values, as Factions are Actor specific and easier to implement, while they can also easily serve as a nice way to add permanent Scripting attributes to an Actor.

 

Link to comment

Ok, I understand. In any case, I see kinda tedious to have to modify every single body armor you add to the game. I think that a mod that allowed you to switch bodies would be more convenient.

 

In fact, it could be made so that you could have this body-changing mod to be able to create a list of armors ingame. There's this other mod called "Body Change" that if I remember correctly has this feature (unfortunately is kinda buggy and doesn't support half the races). Basically you can add outfits to the list and select which body to use, and the mod remembers it automatically. That mod had only 10 slots, but I'm pretty sure it could be done more efficiently.

Link to comment

Ok, I understand. In any case, I see kinda tedious to have to modify every single body armor you add to the game. I think that a mod that allowed you to switch bodies would be more convenient.

 

In fact, it could be made so that you could have this body-changing mod to be able to create a list of armors ingame. There's this other mod called "Body Change" that if I remember correctly has this feature (unfortunately is kinda buggy and doesn't support half the races). Basically you can add outfits to the list and select which body to use, and the mod remembers it automatically. That mod had only 10 slots, but I'm pretty sure it could be done more efficiently.

 

For modifiying your standard Body I did the Permanent Skin faction, they will later be your Skin OVER The Default one... basically: Default Skin (on fitting Outfits)> Permanent Skin > Temporary Skin.

 

The Rank for the Perm Body is basically the index for a FormList ID, that contains a certain Body Shape (so basically UNPPermFaction Rank 1 means the UNP Base Body as Skin, Rank 2 stands for UNPB, Rank 3 for Sevenbase etc.)

 

Additionally, just a few hours ago this little godsent released. It HEAVILY decreases my workload for fitting ALL Bodies for ALL Skin types for the vanilla races (I will update tutorial later, on how you can update your races for other skins in a few TES5Edit Scripts).

Link to comment

But still, isn't a pain in the ass having to do all that manual work? Instead of making a mod that makes you able to wear an armor no matter your body type (being the mod the one that does the work) you're splitting the work between the mod and the armors themselves. I got one of those ChaPi armo mods and only in that one I already have a crapton of them. Add it up to TERA armor packs and any other armor mashup, and in the end you're just saving up some time from just popping BodySlide 2 and adapting the armor to your body (since with that tool and further updates this is going to be easier to do).

 

Wouldn't it be easier to create a mod that managed armor lists ingame, that you just had to choose which body use whenever you tried it the first time and forget about it ever again?

Link to comment

But still, isn't a pain in the ass having to do all that manual work? Instead of making a mod that makes you able to wear an armor no matter your body type (being the mod the one that does the work) you're splitting the work between the mod and the armors themselves. I got one of those ChaPi armo mods and only in that one I already have a crapton of them. Add it up to TERA armor packs and any other armor mashup, and in the end you're just saving up some time from just popping BodySlide 2 and adapting the armor to your body (since with that tool and further updates this is going to be easier to do).

 

Wouldn't it be easier to create a mod that managed armor lists ingame, that you just had to choose which body use whenever you tried it the first time and forget about it ever again?

 

Basically you mean saying to the Mod "see this esp?, well this one got the UNP Armor in it!". That would be a plan for future versions, but for now I need to get the normal Skin change going.

 

Once I figure out MCM I could do that... a window that would have all your esps and a nice Button on were you could choose the Type of Body that normally goes for them. Or I would write a Reproccer that does the same, just with the scripts.

 

Until then I will figure out how we can attach the script with the automation tool for TES5Edit I just posted, with that attaching the Scripts should be much easier as well, just Filter your Armor for, let's say cuirasses, and then use quick change to Attach an UNP (or whatever) Body mod and alll ermors would have it now.

 

Next Variant would be to do a FormID List for each Body, were you put ALL your Armors inside and then let the game look to what ID List the armor any actor just put on belongs to. However here I need to write a function to Inject a FormID List of the Base Mod with another FormID List from, lets say the TERA Mod, when the game loads. So the modder still needs to insert a FormID List into his mod (though you would only have to drag & drop your Elements into it) and somehow implement the "injection" script. Or you modify the base List of the Bodyoptions.esp in your mod and then merge all modified versions together with the Bashed Patch (best Variant I think).

 

I think I will first implement a function that custom races without defined Skins use the Base Body Variants (meaning the Body and Nord Textures from the Vanilla races) after that I will look for a way to make the game listen to every Armor change in Game and to apply Skins based on their FORMID List record.

Link to comment

How about editing the ArmorAddon to point towards a different skin texture?

 

Tried it, it is VERY difficult, because the Skin Armor of Vanilla races (and possibly custom ones) points towards SEVERAL different Versions of the same Addon for different Races (as e.g. Beast races use different Hand meshes) so you would first have to take out the correct Addon for your Race (order is pretty Random), then access it's TextureSet (again: sometimes several of those as e.g. the base Body Addons have acces different TextureSets for different Races). Than create a temporary local copy of that TextureSet (AFAIK creating entirely new entries is not possible with scripts) because else EVERY actor using that texture sets Skin would change.

 

It's sadly not as direct as: ArmorAddon Mesh path ... and texture path...

 

BTW. I just changed a bit about the scripts: now the game should watch automatically whenever an Actor changes his Armor and look up if that armor is part of a Skin FormID List, if it is it will change the Actor towards that specific Skin. If the Skin doesn't exist for a custoim Race it will switch to the Default UNP/CBBE/ADEC/CHSBHC Skin of the Nord Race, but not the HeadPart (to not fuck up it's mesh if that Race uses a different one or a different .tri), so everyone should be able to use the basic functions.

 

You simply have to load Bodyoptions pretty much last, add your Armor Mod as a master to bodyoptions.esp and insert your (preferably) chestpieces to the correct FormID Lists (UNPArmors, CBBEArmors etc.) so you don't have to attach Scripts to anything anymore, the game does it by itself.

 

Edit: found a way to make applying new headtextures easier, without changing the head part (turns out there is an overwriting Head Texture that overwrites the normal one, similar how ActorBase Skin overwrites the race Skin. So that needs some time until the next update

Link to comment

As a seasoned modder I would like to express my gratitude and support for the OP's endeavor :).

Someone mentioned that this can be done in a much simpler way by simply editing the texture paths in NifSkope for the body being part of the skin-misaligned armor/clothing model.
Unfortunately, I tried this, investigated the matter further and in many cases it does not work, because CK texture path overwrites .nif files' texture paths.

Link to comment

Soooo little progress Update (no Upload yet sry) with some good and bad news:

 

Good news:

I managed to make a spell that automatically attaches itslf to the player that speads another spell to all actors in a cell whenever a new one is loaded. This new spell causes to trigger the Skin change whenever an Actor changes a piece of equipment, that way attaching the script to Armors isn't necessary anymore. Instead what you do now is to open a second esp (Bodyoptions Patch) add your Armor mod as a master and simply drag and drop all your armors, that should trigger the skin change, into the appropiate Bodytype FormID List (UNPArmor, CBBEArmors etc.) as every Armor change will cause the game to look up, wether the equipped/unequipped Armor is part of one of these Lists and will then trigger the body changes. This should reduce the work when making Armor compilations compatible. (And should also make creating a ReProccer for that feature easier).

The same thing with FormID Lists works for the Bodies and HeadParts, making the "Offset rule" easier: in the Bodyoptions patch add your Racemod as a master and add the correspondonding UNP/CBBE... HeadParts and Bodies to it's corresponding FormID List (UNPHeads, UNPBodies), however there is also a List fo the Default Body (so it can revert back). The rule here is simple: when it finds your default Body "Armor" and/or in the Default corresponding List, it will use the index of that List and then go to the UNP/CBBE... List and use that index to grab the Body/HeadPart out of it (so you HAVE to make sure everything is sorted correctly). The FormID Offset Option still exist for those who e.g. create new races and want to make them compatible to this mod from the get go. (Since it is only a modification of Addresses with copied FormIDs that go to different Paths, Bodyoptions as master wouldn't be required for new races as well).

 

Bad news:

I tried to go from HeadPart change (for correct Head Textures) to simply change the Head Skin Texture Set of a single head (basically: these Sets are complexions such as frekles or wrinkles), to simply skip the part of "creating HeadParts"... however a ran into unsolvable Problems there: Some Actors without complexion have this field empty... now you could say: "grab the TextureSet from the Headpart and apply it as default!", BUT: there is no HeadPart.GetTextureSet() (or similar) command, making that option impossible for custom races (for Vanilla I would at least know what the base TextureSet is), however even with Vanilla races after pplying a "base" HeadTexture to them I ran into this little Problem: the Tint is wrong! Because appearently the Tint o the HeadSkin is seperate from the rest of the Body, however I can't change it via script as there are no function to get an Actors Skin tint.

Second I tried to directly manipulate NiNodes (basically the mesh i the memory) by changing it's textures (which would make things MUCH easier, as I would simply have to change folders in the meshes Textures ingame, no TextureSets required for anything). However I can't get a Texture Set of a Node (only Set it, and i need a getter to properly modify the Texture paths), additionally there is no function within TextureSets to Get or Set the individual texturepaths.

So HeadParts it is. What's worse is that you may have to create a HeadPart for EVERY complexion your race has, depending on how the Tint changes, when changing a HeadTexture on an Actor that already has one.

 

In the end it's all more work for ME, because I WILL make a ReProccer in time. (Proper scripts are more important first) Effectively reducing your work to "find the proper BodyType for your Armor(mod)". And it would update all those FormID Lists, TextureSets, Bodies and HeadParts by itself in the BodyoptionsPatch.esp .

Link to comment

I dont know how hard it would be to mod, but it seems like it would be easier on the user end to have an mcm menu and it list the clothes u are wearing atm and u pick which body type it is and it saves for when u re equip it next time.  No need for all this auto detection stuff when the user can just pick the body type one time for each outfit in game and be done with it.

 

http://www.nexusmods.com/skyrim/mods/47791/? ive not tried it yet but this mod allows changing of pc and npc body and textures in game, maybe it would be easier to create an addon for this.  However, after reading the description for this, it seems like it would be a bit annoying having the body change dialog with every npc without a way to toggle it.  Tho its got a public license and can be modified and redistributed.

Link to comment

I dont know how hard it would be to mod, but it seems like it would be easier on the user end to have an mcm menu and it list the clothes u are wearing atm and u pick which body type it is and it saves for when u re equip it next time.  No need for all this auto detection stuff when the user can just pick the body type one time for each outfit in game and be done with it.

 

http://www.nexusmods.com/skyrim/mods/47791/? ive not tried it yet but this mod allows changing of pc and npc body and textures in game, maybe it would be easier to create an addon for this.  However, after reading the description for this, it seems like it would be a bit annoying having the body change dialog with every npc without a way to toggle it.  Tho its got a public license and can be modified and redistributed.

Just took a look at the mod, it basically works the same way my mod does with a few exceptions: it's not automated and not race specific (kind of bad for beast races or races with other special textures in general). Additionally you have to do that for EVERY NPC manually... kind of shitty if you have a mixed bag of body types accross your vanilla armors/clothes or added custom armors to leveled Lists (so NPCs wear them automatically). Another thing: it doesn't get new head Textures, meaning that the border between head and body texture can have ugly seams and color mismatches (e.g. the UNP body is slightly darker than the cbbe one).

 

However the MCM Variant is a good idea... it would basically dynamically add your Armor to the auto recognition List (not hard to do)... but McM will be one of the Last things I implement.

Link to comment

Yours sounds like it will be better when finished.  I was hoping for the mcm thing cuz i want to avoid editing esps.  I didnt know it but evidently theres more to saving an esp than just clicking save.  I saved angrims apprentice and edited nothing but the face tint to get rid of mismatched neck seem and it totally borked some of its functionality.  something about having to convert master esps to esms b4 saving.  and probably other stuff.

Link to comment

Yours sounds like it will be better when finished.  I was hoping for the mcm thing cuz i want to avoid editing esps.  I didnt know it but evidently theres more to saving an esp than just clicking save.  I saved angrims apprentice and edited nothing but the face tint to get rid of mismatched neck seem and it totally borked some of its functionality.  something about having to convert master esps to esms b4 saving.  and probably other stuff.

 

Yeah, I actually prefer quick edits over TES5Edit as well, as you screw less stuff up, it also makes adding masters easier. But for that editing of the esps I want to resort to Reproccers later... these things are basically little java application that basically build esps on their own depending on settings you have. So it's basically like McM... just outside of Skyrim. Especially since everything you do in McM is bound to your save... kind of shitty if you have to set up dozens, maybe hundreds, of armors every time you start a new game, unless it writes into an ini or something, however writing and reading inis would make the scripts even slower, and I would like to make them as efficient as possible.

Link to comment
  • 1 year later...

Archived

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

  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use