Jump to content
  • entries
    3
  • comments
    0
  • views
    983

Make children grow to teens in Skyrim


Speele

1,721 views

I have no idea if a mod is already doing the stuff, but I designed one from a talk with some friends.

 

The thing is: there are children in Skyrim. Good. How to make them grow to teens?
So the thing becomes: keep the original children, but find a way to change them in teens at some moment.
 

DISCLAIMER:

the provided code is functionnal

I tested with Camilia Valerius, who got a child, then a teen I named Cimalia Valerius

but the follwing code must be adapted to any need

 

1. TES5EDIT
I made a script for TES5Edit (you need MXPF). Its goal is to consolidate any interesting NPC as a teen version.
So, if one is unique, the related teen would not.

 

Teens are copies, not overrides, of their parent.
And their FormId is exactly the same as their parent, but in the load order of the resulting mod/patch.
The only limitation is FormId collision. However, I got none with Legendary Edition.

 

I stuck myself in the name "Teens.esp" to build the database of base actors.
First, load all the mods containing actors you think they should have a teen version.
Click on any of them and Apply Script > MakeTeens
Then, when this script asks for a file name, enter "Teens".


MakeTeens.pas

Spoiler

{
  Make Teens
}

unit MakeTeens;
uses 'lib\mxpf';

function Initialize: Integer;
var
  i, fid, cur: integer;
  rec: IInterface;
  s: String;

begin
  DefaultOptionsMXPF;
  InitializeMXPF;
  PatchFileByAuthor('TeenMaker');
  SetExclusions(mxHardcodedDatFiles);
  AddMasterIfMissing(mxPatchFile, 'Update.esm');

  cur := GetLoadOrder(mxPatchFile);
  cur := cur shl 24;

  LoadRecords('NPC_');

  for i := MaxRecordIndex downto 0 do begin
    rec := GetRecord(i);
    s := EditorID(LinksTo(ElementByPath(rec, 'RNAM')));
    if (s = 'ImperialRaceChild') or (s = 'RedguardRaceChild') or (S ='NordRaceChild') or (s = 'BretonRaceChild') or (s = 'BretonRaceChildVampire') or (s = 'DefaultRace') then
      RemoveRecord(i)
    else if (geev(rec, 'DATA/Flags/Child') = '1') or (geev(rec, 'ACBS/Flags/Invulnerable') = '1') or (geev(rec, 'ACBS/Flags/Respawn') = '1') then
      RemoveRecord(i)
    else if (geev(rec, 'FULL - Name') = '') or (geev(rec, 'FULL - Name') = 'Prisoner') then
      RemoveRecord(i)
    else
      CopyRecordToPatch(i)
  end;

  // we remove the flags, the packages, the factions, the inventory, the scripts
  // we change level to 1
  // we keep the outfit
  for i := 0 to MaxPatchRecordIndex do begin
    rec := GetPatchRecord(i);
    fid := GetLoadOrderFormID(rec);
    fid := (fid and $00FFFFFF) + cur;
    SetLoadOrderFormID(rec, fid);
    s := geev(rec, 'EDID - Editor ID');
    seev(rec, 'EDID - Editor ID', '_z_' + s);
    s := geev(rec, 'FULL - Name');
    seev(rec, 'FULL - Name', s + ' Teen');
    if (geev(rec, 'ACBS/Flags/Unique') = '1') then
      seev(rec, 'ACBS/Flags/Unique', '0');
    if (geev(rec, 'ACBS/Flags/Essential') = '1') then
      seev(rec, 'ACBS/Flags/Essential', '0');
    if (geev(rec, 'ACBS/Flags/Protected') = '1') then
      seev(rec, 'ACBS/Flags/Protected', '0');
    if (geev(rec, 'ACBS/Flags/PC Level Mult') = '1') then
      seev(rec, 'ACBS/Flags/PC Level Mult', '0');
    seev(rec, 'ACBS/Level', '1');
    if ElementExists(rec, 'VMAD - Virtual Machine Adapter')
      then RemoveElement(rec, 'VMAD - Virtual Machine Adapter');
    if ElementExists(rec, 'SHRT - Short Name')
      then RemoveElement(rec, 'SHRT - Short Name');
    if ElementExists(rec, 'Factions')
      then RemoveElement(rec, 'Factions');
    if ElementExists(rec, 'Items')
      then RemoveElement(rec, 'Items');
    if ElementExists(rec, 'Packages')
      then RemoveElement(rec, 'Packages');
  end;

  PrintMXPFReport;
  FinalizeMXPF;
end;
end.

 

 

Now we have a mod, named "Teens.esp", full of base actors, beginning with formID "_z_".

 

2. Creation Kit on Teens.esp
Now the boring part. Load "Teens.esp" in CK. Go to Actors.
The first ones are teens (they all begin with "_z_"). Select all the teens, and only them.
Press Ctrl+F4 to export all facegen data. This should eliminate the gray face bug - but it will take a while.
Close CK once done, or make an archive from all facegen (note that such archive is valid, if limited to LE DLCs).

 

> however, Cimalia Valerius had the gray face, despite the file present.

> it may have been because I was there along the whole process, I don't know

=> EDIT: this "bug" was quite interesting. It was coming from... Ordenator, which repacked the vanilla BSAs.

So to make this export of facegeometry and facegendata working as expected, do not optimize your vanilla bsas with Ordenator.

 

3. Scripting things.

You can do the big-big part or just focus on the grow-to-teen process.

 

The big-big part is:

- make the aliases arrays (or use an auto register), for example 64 children and 64 moms

  > a big mod should have 128 male children and 128 female ones, then 2*128 moms
- make all sets of hairs/eyes for children + base actors, anything you need for birth

  > Serana's boy and girl will require a bit of work...
- catch a birth signal by mod event (from a pregnancy mod) and spawn the child, setting all the head parts (similar as OnTeenAge, below)
- assign the child into an alias
- make sure you catch OnLoad in the child alias to refresh head parts when the child is loaded
- make a player alias to re-register your events (birth and becoming teen)
- create a package template with two sequential procedures: follow mom and sandbox

  > with conditions: inSameCell packageData->mom, don't forget to make the child run while following

- create as many packages as the number of children aliases
- create as many mom aliases as the number of children aliases
- for package000, assign it to child alias000 and make it targetting to mom alias000

With everything above, you have a complete children mod and it's not so hard to make.

 

Now to the grow-to-teen process.

The design is to place a child into an alias.
Once in the alias, make it updating the scale from 0.5 to 0.8 (the latter being the scale of Skyrim's children).
And once the scale is 0.8, transform the child into a teen.
Then, make the teen grow, from 0.8 to 1.0.

 

I set 50 days for each grow.

 

Now, to the code.

 

The Kid Alias (interessing part)
-------------

Spoiler

;--- ONUPDATEGAMETIME
Event OnUpdateGameTime()
  ; fBirthday is the decimal game day when born
  ; fSpeedUp is a way to speed the grow
  ; IsTeen is a boolean

  ; scale for child:
  ; 0.50 > 0.80, in 50 days
  ; 0.625 > 1.0, 0.375 of range
  ; scale for teen:
  ; 0.80 > 1.00, in 50 days (same for range)

  Float myGrow = Utility.GetCurrentGameTime() - fBirthDay + fSpeedUp ; expressed in days
  myGrow /= 50.0
  If(bIsTeen)
    If(myGrow >= 1.0)
      me.SetScale(1.0)
      Return ; adult size, no update needed anymore
    Else
      myGrow *= 0.2
      myGrow += 0.8
      me.SetScale(myGrow)
    EndIf
  Else
    If(myGrow >= 1.0)
      ; become teen, with a grow for 50 another days (or remain a child)
      me.SetScale(1.0)
      Int handle = ModEvent.Create("KidooTeenAge") ; <= that's it
      ModEvent.PushInt(handle, slot)
      ModEvent.Send(handle)
      Return
    Else
      myGrow *= 0.375
      myGrow += 0.625
      me.SetScale(myGrow)
    EndIf
  EndIf
  RegisterForSingleUpdateGameTime(10.0)
EndEvent

 

The code above works and has been tested.

If a child cannot grow to teen (in the next script) then he/she will be stuck into the alias, with max children size. It's okay.

 

The Mod Event
-------------

Spoiler

;--- ONTEENAGE
Event OnTeenAge(Int i)
  Log("receiving teen age signal for slot "+i)
  KidAlias refAlias = vChildren[i] As KidAlias ; vChildren is a referencealias[] where all child/teen aliases auto registered on init
  Actor refChild = refAlias.me ; property "Actor me" on alias

  ; - do we have a base actor?
  Int refID
  Actor myMother = refAlias.myMother ; property "Actor myMother" on alias
  Actor myFather = refAlias.myFather ; property "Actor myFather" on alias
  Int childSex = refChild.GetLeveledActorBase().GetSex()
  If(childSex == 1)
    refID = myMother.GetLeveledActorBase().GetFormID()
  Else
    refID = myFather.GetLeveledActorBase().GetFormID()
  EndIf

  ; - find a match in the database
  refID = Math.LogicalAnd(refID, 0x00FFFFFF)
  ActorBase refBase = Game.GetFormFromFile(refID, "Teens.esp") As ActorBase ; <= here
  If(!refBase) ; <= nothing was found, so the child will remain a child eternally
    Log("no teen base found")
    Return
  EndIf
  Log("teen base found: " + refBase.GetName())

  ; - store all data
  Int iHair = refAlias.iHair ; this is the index in the formlist of children hairs
  Int iEyes = refAlias.iEyes ; this is the index in the formlist of children eyes (for non human)
  Float fBirthDay = Utility.GetCurrentGameTime() ; reinit grow for 50 new days
  ColorForm refHairColor = refAlias.refHairColor ; the ColorForm used as a child

  ; - spawn the teen
  refBase.SetHairColor(refHairColor)
  Actor refTeen = refChild.PlaceActorAtMe(refBase)
  refTeen.SetDisplayName(refChild.GetDisplayName(), False) ; transfer the name

  ; - assign new hair, eyes with respect to those previously chosen for childhood
  ; the trick is: the formlist for children and those for teens have the same internal order
  ; for example orc ice yes is at index 4 for child, 4 for teen

  Race myRace = refTeen.GetRace()
  FormList hairList
  FormList eyesList

  If(childSex)
    If(myRace == ArgonianRace)
      hairList = _HairTeenArgonianFemale
      eyesList = _EyesTeenArgonian
    ElseIf(myRace == BretonRace || myRace == ImperialRace || myRace == NordRace || myRace == RedguardRace)
      hairList = _HairTeenHumanFemale
      eyesList = _EyesTeenHuman
      ; there s only one eyes for human children so we have to choose randonly here
      iEyes = Utility.RandomInt(0, eyesList.GetSize() - 2) ; - 2 because I left inside, at the last index, vampire eyes (not used)
    ElseIf(myRace == DarkElfRace || myRace == HighElfRace || myRace == WoodElfRace)
      If(myRace == DarkElfRace)
        hairList = _HairTeenDarkElfFemale
        eyesList = _EyesTeenDarkElf
      ElseIf(myRace == HighElfRace)
        eyesList = _EyesTeenHighElf
        hairList = _HairTeenElfFemale
      Else
        eyesList = _EyesTeenWoodElf
        hairList = _HairTeenElfFemale
      EndIf
    ElseIf(myRace == KhajiitRace)
      hairList = _HairTeenKhajiitFemale
      eyesList = _EyesTeenKhajiit
    Else
      hairList = _HairTeenOrcFemale
      eyesList = _EyesTeenOrc
    EndIf
  Else
    If(myRace == ArgonianRace)
      hairList = _HairTeenArgonianMale
      eyesList = _EyesTeenArgonian
    ElseIf(myRace == BretonRace || myRace == ImperialRace || myRace == NordRace || myRace == RedguardRace)
      hairList = _HairTeenHumanMale
      eyesList = _EyesTeenHuman
      iEyes = Utility.RandomInt(0, eyesList.GetSize() - 2)
    ElseIf(myRace == DarkElfRace || myRace == HighElfRace || myRace == WoodElfRace)
      If(myRace == DarkElfRace)
        hairList = _HairTeenDarkElfMale
        eyesList = _EyesTeenDarkElf
      ElseIf(myRace == HighElfRace)
        eyesList = _EyesTeenHighElf
        hairList = _HairTeenElfMale
      Else
        eyesList = _EyesTeenWoodElf
        hairList = _HairTeenElfMale
      EndIf
    ElseIf(myRace == KhajiitRace)
      hairList = _HairTeenKhajiitMale
      eyesList = _EyesTeenKhajiit
    Else
      hairList = _HairTeenOrcMale
      eyesList = _EyesTeenOrc
    EndIf
  EndI
  ; as you see above, there s a lot of formlists to make...

  ; - assign the new hair style and eyes
  HeadPart refHair = hairList.GetAt(iHair) As HeadPart
  HeadPart refEyes = eyesList.GetAt(iEyes) As HeadPart
  refTeen.ChangeHeadPart(refHair)
  refTeen.ChangeHeadPart(refEyes)
  refTeen.QueueNiNodeUpdate()

  ; - prepare
  refTeen.SetScale(0.8) ; the initial scale of a teen
  refTeen.AddToFaction(KidFaction) ; something to identify them quickly

  ; - delete now the child
  Log("deleting child form")
  refAlias.Cleanup() ; mostly clear()
  refChild.Delete()

  ; - assign the teen
  refAlias.ForceRefTo(refTeen)
  refAlias.Initialize(myMother, myFather, fBirthDay, refHairColor, hairList, eyesList, iHair, iEyes, i, bIAmTeen = True) ; i was the slot parameter of this event
  Debug.Notification(refTeen.GetDisplayName() + " has become a teen")
EndEvent

 


 

For existing children, you have to place them into an alias, with their mom and dad, so it may be a bit tricky to retrieve information.

But hey, after a while, Whiterun children will be all teens!

 

Now the little story: I made this log entry because one of my friends doubted it was possible to grow children to teens in Skyrim.

I'll be happy to show the result.

 

Feel free to plunder the code if you are interested.

0 Comments


Recommended Comments

There are no comments to display.

×
×
  • 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