Need help breaking down 'BardSongsScript'.

Post » Mon Nov 19, 2012 4:32 am

I'm finally to the point where I can add my own bard to my own tavern, in my own land. Now, this bard is 100% seperate from the rest. He plays entirely different songs. Completely seperated from the rest of the bard system.

While I was contemplating how to get him to randomly play songs from time to time, I searched for bard quests, and stumbled across the BardSongsScript. This no doubt is the center of the madness, controlling when bards play where, and how.

My problem is that the script is over 500 lines long, and contains a huge amount of random extra's for Skyrim's bards, the main quest, other quests involved. It's a massive mess, and I'm utterly lost. This is my first time in Skyrim dealing with a script this big, that uses this many new (To Skyrim) scripting elements.

I was wondering if someone here could help me break it down into a short concise script that can simply run my bard. I'm going to have songs, and instrumentals just like the normal bards. I need him to randomly play songs without the player prompting him, and I'd like it if there was some interaction among the other people in the Inn. (Like how people clap at the end)

I have some ideas on how to do some of these things, but I'm fairly certain they're way off... I'll slowly grind through this script as I have time, but any pointers on the situation would be awesome!

Thanks,
AJV
User avatar
Kate Norris
 
Posts: 3373
Joined: Mon Nov 27, 2006 6:12 pm

Post » Mon Nov 19, 2012 5:39 pm

Just for reference, here is the script. Warning though, comments contain main quest spoilers:
Spoiler
Scriptname BardSongsScript extends Quest Conditional ;----------------------------------------------------------------------------------------Scene Property BardSongsBallad01Scene autoScene Property BardSongsBallad01WithIntroScene autoScene Property BardSongsDrinkingSong01Scene autoScene Property BardSongsDrinkingSong01WithIntroScene autoScene Property BardSongsDrinkingSong03Scene autoScene Property BardSongsDrinkingSong03WithIntroScene autoScene Property BardSongsDrinkingSong02Scene autoScene Property BardSongsDrinkingSong02WithIntroScene autoScene Property BardSongsInstrumentalFlute01 autoScene Property BardSongsInstrumentalFlute02 autoScene Property BardSongsInstrumentalLute01 autoScene Property BardSongsInstrumentalLute02 autoScene Property BardSongsInstrumentalDrum01 autoScene Property BardSongsInstrumentalDrum02 autoScene Property BardSongsInstrumentalFluteonly01 autoScene Property BardSongsInstrumentalFluteonly02 autoScene Property BardSongsInstrumentalBard2Drum01 autoScene Property BardSongsInstrumentalBard2Drum02 autoScene Property BardSongsInstrumentalWedding01 autoScene Property BardSongsInstrumentalWedding02 auto;----------------------------------------------------------------------------------------ReferenceAlias Property BardSongs_Bard  Auto ReferenceAlias Property BardSongsInstrumental_Bard  Auto ReferenceAlias Property BardSongs_Bard2  Auto ReferenceAlias Property BardSongsInstrumental_Bard2  Auto VoiceType Property FemaleYoungEager Auto voiceType Property MaleYoungEager Auto Quest Property MQ306 AutoQuest Property MQ106 AutoQuest Property MQ203 AutoActorBase Property TalsgarTheWanderer AutoActor Property Sven AutoActor Property Lurbuk AutoPackage Property MorthalLurbukSleep1x5 AutoFaction Property CurrentFollowerFaction AutoKeyword Property LocTypeInn Auto;----------------------------------------------------------------------------------------Location Property HaafingarHoldLocation AutoLocation Property WinterholdHoldLocation AutoLocation Property EastmarchHoldLocation AutoLocation Property RiftHoldLocation AutoLocation Property PaleHoldLocation AutoLocation Property ReachHoldLocation AutoLocation Property FalkreathHoldLocation AutoLocation Property WhiterunHoldLocation AutoLocation Property HjaalmarchHoldLocation AutoKeyword Property CWOwner  Auto  MusicType Property MUSTavernSILENCE Auto;----------------------------------------------------------------------------------------String Bard2SavedInstrumentBool Bard2SavedPlayContinuousint Bard2LastSongPlayedString SavedInstrumentBool SavedPlayContinuousint SavedSongToPlayInt LastSongPlayedBool ProcessingDialogueRequestBool StopSong = FalseobjectReference BardHandoffString InstrumentHandoffBool PlayContinuousHandoff Int	SongToPlayHandoffBool ChangeSettingsHandoffFloat LocationOwner ConditionalInt Playing = 0 ConditionalInt InstrumentalSong = 1 ConditionalInt Bard2InstrumentalSong = 1 Conditional;----------------------------------------------------------------------------------------int Function GetRandomSong(objectReference PassedBard)		Int BardSongToPlay = LastSongPlayed	While BardSongToPlay == LastSongPlayed 				If MQ306.GetStage() > 0 													;If we're past Sovngard you can play 10: Tale of the Tongues			BardSongToPlay = Utility.RandomInt(2,10)		Else					BardSongToPlay = Utility.RandomInt(2,9)								;If not randomize the rest.		EndIf				If PassedBard.GetVoiceType() == FemaleYoungEager &&  BardSongToPlay == 2		;If the song picked is "Age Of..." for FemaleYoungEager (who can't sing it) set it to "Ragnar" 			BardSongToPlay = 1			EndIf		If PassedBard.GetVoiceType() == MaleYoungEager &&  BardSongToPlay == 3			;If the song picked is "The Dragonborn..." for MaleYoungEager  (who can't sing it) set it to "Ragnar" 			BardSongToPlay = 1		EndIf		Endwhile ; 	debug.Trace("Returning Random Song #"+BardSongToPlay)	Return (BardSongToPlay)EndFunction;----------------------------------------------------------------------------------------Function PlayChosenSong(Int ChosenSong)	Int Intro = Utility.RandomInt(0,1)	If ChosenSong < 13		LastSongPlayed = ChosenSong	Else		Bard2LastSongPlayed = ChosenSong	EndIf	If ChosenSong == 10; 		debug.Trace("Playing Bard song 10: Tale of the Tongues")		If Intro == 0; 				debug.Trace("Playing Bard song 10 without intro")			BardSongsBallad01Scene.Start()		Else; 				debug.Trace("Playing Bard song 1 with intro")			BardSongsBallad01WithIntroScene.Start()		EndIf	EndIf	If ChosenSong == 1; 		debug.Trace("Playing Bard song 1: Ragnar The Red")		If Intro == 0; 				debug.Trace("Playing Bard song 1: Ragnar The Red without intro")			BardSongsDrinkingSong02Scene.Start()		Else; 				debug.Trace("Playing Bard song 1: Ragnar The Red with intro")				BardSongsDrinkingSong02WithIntroScene.Start()		EndIf	EndIf	If ChosenSong == 2; 		debug.Trace("Playing Bard song 2: Age of...")		If Intro == 0; 				debug.Trace("Playing Bard song 2 without intro")			BardSongsDrinkingSong03Scene.Start()		Else; 				debug.Trace("Playing Bard song 2 with intro")			BardSongsDrinkingSong03WithIntroScene.Start()		EndIf	EndIf	If ChosenSong == 3; 		debug.Trace("Playing Bard song 3: The Dragonborn")		If Intro == 0; 				debug.Trace("Playing Bard song 3 without intro")			BardSongsDrinkingSong01Scene.Start()		Else; 				debug.Trace("Playing Bard song 3 with intro")			BardSongsDrinkingSong01WithIntroScene.Start()		EndIf	EndIf	If ChosenSong == 4; 			debug.Trace("Playing Bard song 4: Flute1")		InstrumentalSong = Utility.RandomInt(1,6)		BardSongsInstrumentalFlute01.Start()	EndIf	If ChosenSong == 5; 			debug.Trace("Playing Bard song 5: Flute2")		InstrumentalSong = Utility.RandomInt(1,6)		BardSongsInstrumentalFlute02.Start()	EndIf	If ChosenSong == 6; 			debug.Trace("Playing Bard song 6: Lute1")		InstrumentalSong = Utility.RandomInt(1,4)		BardSongsInstrumentalLute01.Start()	EndIf	If ChosenSong == 7; 			debug.Trace("Playing Bard song 7: Lute2")		InstrumentalSong = Utility.RandomInt(1,4)		BardSongsInstrumentalLute02.Start()	EndIf	If ChosenSong == 8; 			debug.Trace("Playing Bard song 8: Drum1")		InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalDrum01.Start()	EndIf	If ChosenSong == 9; 			debug.Trace("Playing Bard song 9: Drum2")		InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalDrum02.Start()	EndIf	If ChosenSong == 11; 			debug.Trace("Playing Bard song 11: FluteOnly1")		InstrumentalSong = 1		BardSongsInstrumentalFluteonly01.Start()	EndIf	If ChosenSong == 12; 			debug.Trace("Playing Bard song 12: FluteOnly2")		InstrumentalSong = 1		BardSongsInstrumentalFluteonly02.Start()	EndIf	If ChosenSong == 13; 			debug.Trace("Playing Bard song 13")		Bard2InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalBard2Drum01.Start()	EndIf	If ChosenSong == 14; 			debug.Trace("Playing Bard song 14")		Bard2InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalBard2Drum02.Start()	EndIf	If ChosenSong == 15; 			debug.Trace("Playing Bard song 15")		Bard2InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalWedding01.Start()	EndIf	If ChosenSong == 16; 			debug.Trace("Playing Bard song 16")		Bard2InstrumentalSong = Utility.RandomInt(1,3)		BardSongsInstrumentalWedding02.Start()	EndIfEndFunction;--------------------------------------------------------------------------------------Function PlaySongRequest(objectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, int SongToPlay = 0, Bool ChangeSettings = True)		BardHandoff= Bard		InstrumentHandoff = Instrument		PlayContinuousHandoff = PlayContinuous		SongToPlayHandoff = SongToPlay		ChangeSettingsHandoff = ChangeSettings		RegisterForSingleUpdate(1)EndFunction;--------------------------------------------------------------------------------------Event OnUpdate()	PlaySong(BardHandoff, InstrumentHandoff, PlayContinuousHandoff,SongToPlayHandoff, ChangeSettingsHandoff)EndEvent;---------------------------------------------------------------------------------------Function PlaySong(objectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, int SongToPlay = 0, Bool ChangeSettings = True); 	;Debug.tracestack()	While Bard.IsInDialogueWithPlayer()			if Changesettings == False && (Stopsong == True || SavedPlayContinuous == False)				Return			endif			Utility.Wait(1); 			Debug.Trace("Playsongs is waiting...")		EndWhile; 	debug.Trace("Function Called. Stopsong is " + Stopsong)	if Changesettings == False && (Stopsong == True || SavedPlayContinuous == False)		Playing = 0		Return	endif	If Bard == Lurbuk &&  Lurbuk.GetCurrentPackage() == MorthalLurbukSleep1x5		Playing = 0		Return     	Endif	if Changesettings == True			StopAllSongs()	endif	Playing = 1	If (Bard as Actor).IsInFaction(CurrentFollowerFaction); 		debug.Trace("Bard is a follower! Aborting song.")		Playing = 0		Return     	Else		BardSongs_Bard.forcerefto(Bard) 									;Force the passed in character into the aliases required to play		BardSongsInstrumental_Bard.forcerefto(Bard) 	Endif	RegisterLocationOwner(Bard)	If ChangeSettings == False 											;Allows the sytem to recall the function without changing the previous settings.; 		debug.Trace("Using Previous Settings")		Instrument = SavedInstrument		PlayContinuous = SavedPlayContinuous		SongToPlay = 0	Else																	;Saves the settings of the original call.; 		debug.Trace("Using New Settings")		SavedInstrument = Instrument		SavedPlayContinuous = PlayContinuous	endif	If (Bard as Actor).GetActorBase() == TalsgarTheWanderer		 SavedPlayContinuous = False	endif; 		debug.Trace("Instrument is " + Instrument); 		debug.Trace("SongToPlay is " + SongToPlay)	If Bard == Sven && MQ106.GetStage() >  20 && MQ106.Getstage() < 50		If LastSongPlayed == 6			SongToPlay = 7		Else			SongToPlay = 6		endIf	endif	If Bard == Sven && MQ203.isrunning()   						;GetStage() >=  10 && MQ203.Getstage() < 40		If LastSongPlayed == 6			SongToPlay = 7		Else			SongToPlay = 6		endIf	endif	If Instrument == "Instrumental"; 		debug.Trace("Requested Instrumental")							;Randomly choose instrument to play if Instrumental was chosen		SongToPlay = Utility.RandomInt(4,9) 	endif	If Instrument == "Flute"												;Play Flute song if Flute was chosen; 		debug.Trace("Requested flute")		If LastSongPlayed == 11			SongToPlay = 12		Else			SongToPlay = 11		endIf	endif	If Instrument == "Lute"												;Play Lute song if Lute was chosen		If LastSongPlayed == 6			SongToPlay = 7		Else			SongToPlay = 6		endIf	endif	If Instrument == "Drum"												;Play Drum song if Drum was chosen		If LastSongPlayed == 8			SongToPlay = 9		Else			SongToPlay = 8		endIf	endif; 	debug.Trace("SongToPlay is now " + SongToPlay)	if SongToPlay == 0												;if a particular song hasn't been requested, get a random song.; 		debug.Trace("Choosing Random Song")		SongToPlay = GetRandomSong(Bard)      				endif			; 	debug.Trace("Executing Play Chosen function Song " + SongToPlay)	If (Bard as Actor).IsInFaction(CurrentFollowerFaction); 		debug.Trace("Bard is a follower! Aborting song.")		Playing = 0		Return     	Endif	If !Bard.Is3dLoaded(); 		debug.Trace("Bard has no 3D! Aborting song.")		Playing = 0		Return     	Endif	PlayChosenSong(SongToPlay)		Utility.Wait(1)	StopSong = FalseEndFunction;--------------------------------------------------------------------------------------Function StopAllSongs(); 	Debug.Trace("StopAllSongs hapenning now.")		StopSong = True	BardSongsBallad01Scene.Stop()	BardSongsBallad01WithIntroScene.Stop()	BardSongsDrinkingSong01Scene.Stop()	BardSongsDrinkingSong01WithIntroScene.Stop()	BardSongsDrinkingSong02Scene.Stop()	BardSongsDrinkingSong02WithIntroScene.Stop()	BardSongsDrinkingSong03Scene.Stop()	BardSongsDrinkingSong03WithIntroScene.Stop()	BardSongsInstrumentalFlute01.Stop()	BardSongsInstrumentalFlute02.Stop()	BardSongsInstrumentalLute01.Stop()	BardSongsInstrumentalLute02.Stop()	BardSongsInstrumentalDrum01.Stop()	BardSongsInstrumentalDrum02.Stop()	BardSongsInstrumentalFluteOnly01.Stop()	BardSongsInstrumentalFluteOnly02.Stop()	Playing = 0EndFunction;--------------------------------------------------------------------------------------Function RegisterLocationOwner(objectreference BardToCheck)		Location CurrentLocation 	If BardToCheck.isInLocation(HaafingarHoldLocation)		 CurrentLocation = HaafingarHoldLocation 	ElseIf BardToCheck.isInLocation(WinterholdHoldLocation)		 CurrentLocation = WinterholdHoldLocation	ElseIf BardToCheck.isInLocation(EastmarchHoldLocation)		 CurrentLocation = EastmarchHoldLocation	ElseIf BardToCheck.isInLocation(RiftHoldLocation)		 CurrentLocation = RiftHoldLocation	ElseIf BardToCheck.isInLocation(PaleHoldLocation)		 CurrentLocation = PaleHoldLocation	ElseIf BardToCheck.isInLocation(ReachHoldLocation)		 CurrentLocation = ReachHoldLocation	ElseIf BardToCheck.isInLocation(FalkreathHoldLocation)		 CurrentLocation = FalkreathHoldLocation	ElseIf BardToCheck.isInLocation(WhiterunHoldLocation)		 CurrentLocation = WhiterunHoldLocation	ElseIf BardToCheck.isInLocation(HjaalmarchHoldLocation)		 CurrentLocation = HjaalmarchHoldLocation	Else		CurrentLocation = WhiterunHoldLocation 	Endif	LocationOwner = CurrentLocation.GetKeywordData(CWOwner)EndFunction;--------------------------------------------------------------------------------------Function Bard2PlaySong(objectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, int SongToPlay = 0, Bool ChangeSettings = True)		if Changesettings == False && (Stopsong == True || PlayContinuous == False)		Return	endif	BardSongs_Bard2.forcerefto(Bard) 									;Force the passed in character into the aliases required to play	BardSongsInstrumental_Bard2.forcerefto(Bard) 	RegisterLocationOwner(Bard)	If ChangeSettings == False 											;Allows the sytem to recall the function without changing the previous settings.; 		debug.Trace("Using Previous Settings")		Instrument = Bard2SavedInstrument		PlayContinuous = Bard2SavedPlayContinuous		SongToPlay = 0	Else																	;Saves the settings of the original call.; 		debug.Trace("Using New Settings")		Bard2SavedInstrument = Instrument		Bard2SavedPlayContinuous = PlayContinuous	endif	If Instrument == "Drum"												;Play Drum song if Drum was chosen; 		debug.Trace("Bard2 recognized Instrument is " + Instrument)		If Bard2LastSongPlayed == 13			SongToPlay = 14		Else			SongToPlay = 13		endIf	endif	If Instrument == "Flute"												;Play Flute song if Flute was chosen		If Bard2LastSongPlayed == 15			SongToPlay = 16		Else			SongToPlay = 15		endIf	endif; 	debug.Trace("Bard2 Instrument is " + Instrument); 	debug.Trace("Bard2 SongToPlay is " + SongToPlay)	If (Bard as Actor).IsInFaction(CurrentFollowerFaction) ; 		debug.Trace("Bard is a follower! Aborting song.")		Playing = 0		Return     	Endif		;If !Bard.Is3dLoaded(); 		;debug.Trace("Bard has no 3D! Aborting song.")		;Playing = 0		;Return     	;Endif	PlayChosenSong(SongToPlay)	EndFunction;---------------------------------------------------------------------------------------------Function StopInnMusic()		Game.GetPlayer().GetCurrentLocation().HasKeyword(LocTypeInn)		MUSTavernSilence.Add()EndFunction
First just a little disclaimer - I have access to the Papyrus source at the moment but not the Creation Kit so everything I say here I've gleaned from just looking at the script. Basically I can't check out how quests and references are set up in Skyrim.esm, so take everything I say about that with a pinch of salt.

So, the first thing to notice about this script is that it extends http://creationkit.com/Quest_Script. This is not a quest that you will attach to your bard. It seems, from the script's http://www.creationkit.com/ReferenceAlias_Script properties, that the bard being manipulated will be accessed via an alias.

Here's a list of all the functions and events in the script:
  • Int Function GetRandomSong(ObjectReference PassedBard)
  • Function PlayChosenSong(Int ChosenSong)
  • Function PlaySongRequest(ObjectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, Int SongToPlay = 0, Bool ChangeSettings = True)
  • Event OnUpdate()
  • Function PlaySong(ObjectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, Int SongToPlay = 0, Bool ChangeSettings = True)
  • Function StopAllSongs()
  • Function RegisterLocationOwner(ObjectReference BardToCheck)
  • Function Bard2PlaySong(ObjectReference Bard, String Instrument = "Any", Bool PlayContinuous = True, Int SongToPlay = 0, Bool ChangeSettings = True)
  • Function StopInnMusic()
Remember, only native events (like http://www.creationkit.com/OnUpdate_-_Form) can act as entry points for a script, but the only native event in this script requires registration. I expect there's a quest stage or something that registers this Quest for updates.

In the OnUpdate event, all it does is call the PlaySong function. It looks like this function runs various checks (like whether or not the bard is a follower) and aborts the song if any of them don't pass. After that, it sets up the bard by forcing one of the aliases to point to it, and calling the RegisterLocationOwner function on it. The rest of it is just picking the song to play (potentially using GetRandomSong, which does what it says on the tin), and once that's decided the PlayChosenSong function is called.

RegisterLocationOwner just checks if the bard is in any of the locations hard-coded into the script. This information isn't used in this script though, so I'm not sure what that's about. It's possibly used for conditionalising packages on the bard aliases or something.

The PlayChosenSong function calls on the appropriate [src="http://www.creationkit.com/Scene_Script"]Scene (the Scenes are included as properties, so hard coded) for the chosen song.

Some functions, like PlaySongRequest, Bard2PlaySong, and StopInnMusic, aren't called in this script. I expect they're probably called from various quest stages or other scripts, possibly running on the script's aliases.

I hope that helps :)

Cipscis
User avatar
Andrew Lang
 
Posts: 3489
Joined: Thu Oct 11, 2007 8:50 pm


Return to V - Skyrim