Jump to content

Getting a created NPC to change to different outfits on each day.


Recommended Posts

I've made more progress with the new version of my follower mod.

 

I decided to make a follower for my follower. I've done this in one of my skyrim follower mods & it worked well.

She isn't a proper companion though, she can't interact with the player, trade items etc. I could set her up to be one but my actual companion was such a monumental undertaking I never want to repeat that.

This presents a certain challenge. I want this npc to wear multiple outfits, but change between them each day.

 

I know Deacon already does something like this when he enters new locations. I've had a look and I can't find anything that indicates how this is done.

 

Can this be done by AI packages? Or is it controlled by a quest?

 

Any advice would be appreciated.

Link to comment
Share on other sites

You would need a script to set the outfit.

 

If the actor is unique to you then attaching a script to the lvlActor form would be the most straightforward.

 

Could look something like this (written cold, my contain errors) :

 

 

 

Scriptname MyActorScript extends Actor

Outfit Property pMyOutfitA Auto Const Mandatory
Outfit Property pMyOutfitB Auto Const Mandatory
Outfit Property pMyOutfitC Auto Const Mandatory
GlobalVariable Property pGameDay Auto Const Mandatory

Float fLastDayChange
Outfit LastOutfit

Event OnInit()
   Self.SetOutfit(pMyOutfitA)
   LastOutfit = pMyOutfitA
   fLastDayChange = pGameDay.GetValue()
EndEvent

Event OnLocationChange(Location akOldLoc, Location akNewLoc) ; or any event that happens every day but not too often.
   If (pGameDay.GetValue() > fLastDayChange) 
	   If (LastOutfit == pMyOutfitA)
		   LastOutfit = pMyOutfitB
	   ElseIf (LastOutfit == pMyOutfitB)
		   LastOutfit = pMyOutfitC
	   ElseIf (LastOutfit == pMyOutfitC)
		   LastOutfit = pMyOutfitA
   	   Endif
       Self.SetOutfit(LastOutfit)
       fLastDayChange = pGameDay.GetValue()	
	EndIf
EndEvent 

 

 

Link to comment
Share on other sites

Interesting. That looks very complex.

 

Is it possible to have more than 3 Outfit Properties? Perhaps one for each day?

 

I'm assuming that the blue text represents properties I'll have to create. For the akOldLoc & akNewLoc entries, will I have to fill them with specific locations? Or is there some way to make them represent any location change?

 

Thanks for your assistance with this.

Link to comment
Share on other sites

Just make an array:

Outfit[] Property MyOutfits Auto Const Mandatory

 

You can populate it in CK and access each element by number from script:

MyOutfits[0], MyOutfits[1], ... MyOutfits[n]

 

The number can be a variable (such as n), so you could increment it by one each time and reset it to 0 after the last element (MyOutfits.Length - 1) has been reached.

 

 

akOldLoc / akNewLoc will be filled by the game when it fires the LocationChange event.

But if you'd rather have things on a timetable, I recommend the scheduler in F4MS.

Link to comment
Share on other sites

Just coming back to say you are both epic human beings & I appreciate you for helping me. The script is a success, the outfit changes are flawless.

 

I have an additional request for help.

 

I've noticed that, while you can set an npc to have a sleep outfit & make packages that trigger the use of that outfit, the new outfit change script seems to overrule that feature (or maybe sleep outfits don't work in FO4).

 

If I wanted to make my npc equip their sleep outfit when their doing their sleep packages, how would I go about doing this?

 

Thanks again.

Link to comment
Share on other sites

  • 2 years later...

I'm new to modding Fallout4. I'vs modded a lot for Morrowind, Oblivion and Fallout3 ( I think I released my TenpennyTowerMakeover, transforming all the goons there into prohibition era gangsters).Skyrim was a pain - I lost intrest as Ice ands Snow does nort appeal to me. Fallout4 is very difficult because the programming interface has to be set up by the user, and so much has changed. I tend to look for stuff I can copy. So far I cannot manage dialogues - dont understand the new scene based dialogue system. Anyway, I was always doing clothing changes, and your script seems ideal for my Doc Hoff changing his vintage clothing Mod outfit during the night, with changes :

Scriptname Fallout3DocHoffClothingScript extends Actor

Outfit Property Fallout3DocHoffDayBlackTieTailsOutfitNoHat Auto Const Mandatory
Outfit Property Fallout3DocHoffEveningWhiteTieTailsOutfitNoHat Auto Const Mandatory

Outfit Property Fallout3DocHoffDayBlackTieTailsOutfitNoHatSC Auto Const Mandatory
Outfit Property Fallout3DocHoffEveningWhiteTieTailsOutfitNoHatSC Auto Const Mandatory

GlobalVariable Property pGameHour Auto Const Mandatory
Outfit LastOutfit

int myTimerID = 10 ; Give our timer an ID we can remember
float myTimerDuration = 5.0 ; 5 seconds

Event OnInit()
       Self.SetOutfit(Fallout3DocHoffDayBlackTieTailsOutfitNoHat )
       LastOutfit = Fallout3DocHoffDayBlackTieTailsOutfitNoHat

      StartTimer(myTimerDuration , myTimerID )
EndEvent

Event OnTimer(int aiTimerID)        
      If aiTimerID == myTimerID ; The five second timer we started just expired
         CheckOutfit()
          StartTimer(myTimerDuration , myTimerID)
      EndIf
EndEvent

Function CheckOutfit()
       If (pGameHour.GetValue() < 6 ) || (pGameHour.GetValue() >= 18 )
           If (LastOutfit != Fallout3DocHoffEveningWhiteTieTailsOutfitNoHat )
               LastOutfit = Fallout3DocHoffEveningWhiteTieTailsOutfitNoHat
               Self.SetOutfit(LastOutfit)
         endif
    else
           If (LastOutfit != Fallout3DocHoffDayBlackTieTailsOutfitNoHat )
               LastOutfit = Fallout3DocHoffDayBlackTieTailsOutfitNoHat
               Self.SetOutfit(LastOutfit)
           endif
    endif
EndFunction

 

 

Link to comment
Share on other sites

Probably a touch overkill but I wanted to have a little dabble in your eveningwear idea.


 

Spoiler
Scriptname Fallout3DocHoffClothingScript extends Actor

Struct OutfitStruct
    Outfit theOutfit
    bool IsEveningWear = True
EndStruct

;A struct array of all the possible outfits with an ability to 'tag' them as evening wear. Could have new outfits added to it via other scripts
OutfitStruct[] Property actorOutfits Auto Const

Float Property FirstChange = 6.0 Auto Const
{The first time of day (in hours) that the actor will change}
Float Property SecondChange = 18.0 Auto Const
{The second time of day (in hours) that the actor will change}

int LastOutfit = -1

int myTimerID = 10 ; Give our timer an ID we can remember
float myTimerDuration = 3.0 ; 3 in-game hours, less intensive than every five seconds. The game time doesn't change that quickly. Could even set this to one hour.

Event OnLoad()
    ;Use OnLoad so that the event fires everytime the player loads the cell with Doc Hoff in it
    CheckOutfit(IsEvening())
    StartTimerGameTime(myTimerDuration, myTimerID )

EndEvent

Event OnUnload()
    CancelTimerGameTime(myTimerID)
EndEvent

Event OnTimerGameTime(int aiTimerID)
    If aiTimerID == myTimerID
        CheckOutfit(IsEvening())
        StartTimerGameTime(myTimerDuration , myTimerID)
    EndIf
EndEvent

Function CheckOutfit(bool inTimeCheck)
    ;start at the last outfit to cycle through them
    int index = LastOutfit
    While index < actorOutfits.Length
        ;check here to ensure that it loops round and doesn't try to call indexes outside of the arrays range
        If index >= actorOutfits.Length
            index = 0
        EndIf
        
        If actorOutfits[index].IsEveningWear == inTimeCheck && index != LastOutfit
            LastOutfit = index
            SetOutfit(actorOutfits[index].theOutfit)
            index += 999
        EndIf
        index += 1
    EndWhile
EndFunction

Float Function GetTimeOfDay()
    ;GetCurrentGameTime gives the current game time in terms of "game days passed". Subtracting the floor of this value gives the time of day as a decimal (i.e. the difference)
    Float fDayHoursDecimal = Utility.GetCurrentGameTime() - math.Floor(Utility.GetCurrentGameTime())
    Float fHourOfDay = math.Floor(fDayHoursDecimal * 24)
    return fHourOfDay
EndFunction

bool Function IsEvening()
    ;Just a handy function in case you want to expand the script or call it from elsewhere
    Float currentHour = GetTimeOfDay()
    return currentHour < FirstChange || currentHour >= SecondChange
EndFunction

 

 

Link to comment
Share on other sites

15 hours ago, Sars99 said:

Probably a touch overkill but I wanted to have a little dabble in your eveningwear idexxxx

  Hide contents
Scriptname Fallout3DocHoffClothingScript extends Actor

Struct OutfitStruct
    Outfit theOutfit
    bool IsEveningWear = True
EndStruct

;A struct array of all the possible outfits with an ability to 'tag' them as evening wear. Could have new outfits added to it via other scripts
OutfitStruct[] Property actorOutfits Auto Const

Float Property FirstChange = 6.0 Auto Const
{The first time of day (in hours) that the actor will change}
Float Property SecondChange = 18.0 Auto Const
{The second time of day (in hours) that the actor will change}

int LastOutfit = -1

int myTimerID = 10 ; Give our timer an ID we can remember
float myTimerDuration = 3.0 ; 3 in-game hours, less intensive than every five seconds. The game time doesn't change that quickly. Could even set this to one hour.

Event OnLoad()
    ;Use OnLoad so that the event fires everytime the player loads the cell with Doc Hoff in it
    CheckOutfit(IsEvening())
    StartTimerGameTime(myTimerDuration, myTimerID )

EndEvent

Event OnUnload()
    CancelTimerGameTime(myTimerID)
EndEvent

Event OnTimerGameTime(int aiTimerID)
    If aiTimerID == myTimerID
        CheckOutfit(IsEvening())
        StartTimerGameTime(myTimerDuration , myTimerID)
    EndIf
EndEvent

Function CheckOutfit(bool inTimeCheck)
    ;start at the last outfit to cycle through them
    int index = LastOutfit
    While index < actorOutfits.Length
        ;check here to ensure that it loops round and doesn't try to call indexes outside of the arrays range
        If index >= actorOutfits.Length
            index = 0
        EndIf
        
        If actorOutfits[index].IsEveningWear == inTimeCheck && index != LastOutfit
            LastOutfit = index
            SetOutfit(actorOutfits[index].theOutfit)
            index += 999
        EndIf
        index += 1
    EndWhile
EndFunction

Float Function GetTimeOfDay()
    ;GetCurrentGameTime gives the current game time in terms of "game days passed". Subtracting the floor of this value gives the time of day as a decimal (i.e. the difference)
    Float fDayHoursDecimal = Utility.GetCurrentGameTime() - math.Floor(Utility.GetCurrentGameTime())
    Float fHourOfDay = math.Floor(fDayHoursDecimal * 24)
    return fHourOfDay
EndFunction

bool Function IsEvening()
    ;Just a handy function in case you want to expand the script or call it from elsewhere
    Float currentHour = GetTimeOfDay()
    return currentHour < FirstChange || currentHour >= SecondChange
EndFunction

 

Your code is a bit beyond me - but I'm saving it for future use. So far what I have written is for STANDARD Formal wear rules - just change the formal wear to the correct version unless the player is wearing something else. I'm anticipating that there may be cells where STRICT formal wear Rules ( Day wear only, Evening wear only, or STRICT stadard rlues in use) may be in use - they override any else being worn. I've just put in dummy code as I've no idea where vthat might apply - probably the Sanctuary and in Doc Hoffs precence at the Red Racket Petrol Stop. It's unfortunate that it seems no longer possible to detect being in a Named Exterior Cell by using a dummy interior cell name. Have to use distance from standard markers. If want to control players wear in Doc Hoffs presence its a different problem - he's in a different plugin. Fortunately there is a way to pass messages between plugins.

 

Link to comment
Share on other sites

Anyone know how to access a reference in a script

i.e. via the name of a X Marker or a Map Marker ref, so that I can use it in the GetDistance function?????

 

   if ( PlayerREF.GetDistance ( PlayerHomeMarkerREF) < 5000 )

      ............
   endif

 

Edited by AndyTheSaurus
Link to comment
Share on other sites

  • Recently Browsing   0 members

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