Werewolf Meter Papyrus Script Overview
Article #6 in a 10-part series.
- 1 - Skyrim Special Edition Released
- 2 - Convert Old Skyrim Mods for SE
- 3 - How to Disable Random Dragons in Skyrim
- 4 - Convert Black Sacrament Armor to SE Step-by-Step
- 5 - How to Update Meshes for Skyrim SE
- 6 - this article
- 7 - Skyrim SE - XPMSSE: Modify Weapon Positions
- 8 - Show Your Tail With Campfire Cloak In Skyrim
- 9 - Skyrim Frostfall and Survival Armor Edit for Warmth
- 10 - Frostfall SE with SKSE64
updated 2020 January for Werewolf Time Meter version 2
This article introduces some Papyrus scripting techniques and reviews my scripts for “Werewolf Time Meter” mod for Skyrim Special Edition. In a nutshell, the “Werewolf Time Meter” borrows the blue magicka bar as a countdown meter during beast form transformation. If you have limited experience writing scripts or programs, please see introduction and tutorials on Papyrus Reference.
resources
- Werewolf Time Meter on nexusmods.com includes script sources in archive (BSA) or on GitHub
- Creation Kit Papyrus Reference on creationkit.com
- Setup for Script Work with Creation Kit and Notepad++
intro
Instead of focusing on learning Papyrus, I go over technique and the workings of the two scripts making up “Werewolf Time Meter.” See “Creation Kit Papyrus Reference” for brief examples and tutorials.
The mod includes three script files (actually four): a spell-effect script allows the player to enable and disable the meter and the other controls, a main controller to display the meter, and a player-alias script to handle events. In the plugin there exists a spell effect to disable (damage) magicka regeneration preventing the time meter bar growing until beast form ends. This means upon detecting the player’s character has become a beast, the spell effect must be added. Remove if exists when not in beast form.
The player-alias OnRaceChangeEvent alerts the main script to check if beast or not to start or stop updating the magicka bar. During transformation the main script polls infrequently to calculate time remaining and update the meter. Since checking the player’s condition is very fast, we could probably get away with more frequent updates but only needs to be fast enough to update bar. 3-7 seconds seems acceptable.
Since the player cannot normally use power spells in beast form, we could probably forget the case of enable/disable toggle during beast form. However, mods may exist allowing it so we should at least consider the possibility. We should also consider odd scenarios and try to make the script as robust as possible.
name convention for quicker mod recognition
A convention I use for naming objects in a mod is to prepend with the mod-name initials making it easier to tell what belongs to the mod. I use “DTWW” for properties. My script names also follow similar naming style.
- DTWerewolfWatchToggle script: called by player action to enable/disable DTWereWolfWatch
- DTWereWolfWatch script: handles updating and restoring the magicka bar
- DTPlayerAliasScript: handles events, OnPlayerGameLoad, OnRaceChange, and OnHit
CK - Papyrus basics
The Creation Kit (CK) Papyrus compiler turns a source (psc-file) into a game-ready script file (pex). These are located in your \Data\scripts\ and \Data\scripts\source\ folders. If you’re concerned about private information keep in mind that the compiled pex-file includes your PC’s name and your login name. You may use Notepad++ with syntax-coloring and to launch the compiler. See my previous post, “Setup for Script Work with Creation Kit and Notepad++” on how to get started. It’s also possible to decompile a pex-file into a source using “Champollion” by li1lnx.
- The semi-colon (;) character at the start marks a comment line.
- Boolean comparison denoted similar to other languages: == (is equal to), != (not equal to), <, >, <=, >=
- A GlobalVariable is a Float type, but may be cast to Bool or Int.
- Use Property to connect objects to the plugin or other scripts.
- An Event occurs on a game condition which may be quest initialization, update at a specified time, when magic effect happens, or button activation.
- You may use Debug.Notification to help validate conditions during play testing. I comment these out when finished testing.
scripts
program / script writing basics
Writing clean, easy to read scripts helps reduce bugs and allows for re-use.
- Try to break up large functions into smaller, bite-size morsels. Make reading easier.
- Do you need to calculate the same thing more than once? Put that into a function to return the result.
- A function should have a specific goal: display a message, add spell to player, reset our globals.
The following are examples of short, helpful functions found in my script. You may copy/paste/edit into your scripts to your heart’s desire.
There’s another way to find hour by forcing the time to an integer (dayNum) and subtracting from time as shown below:
Below is how to adjust the magicka bar (up or down) with a new value for the actor. There’s no need to check maximum since game allows over-adding to fill.
DTWerewolfWatchToggle
The toggle is called by the spell effect, DTWerewolfSpellEffect, thus it extends ActiveMagicEffect. The “watch” script extends a quest, and this script must access that other script to tell it to enable or disable. It’s done using the Register and UnRegister functions found in that script as noted below in the ToggleWWMeter() function. OnEffectStart event happens whenever the spell effect is activated. Even though here the spell is only attached to the player, it’s a good habit to check if the Actor is the player in case of mistakes or later we decide to expand the spell.
Call a function in another script by using the property reference such as, (DTWerewolfWatch_quest as DTWerewolfWatch).Register() where DTWerewolfWatch is the name of the quest in this cast. Note the parenthesis around the cast.
- DTWerewolfWatch_quest: connects to script below
Below is the entire script.
DTWWPlayerAliasScript
This script catches events to tell DTWerewolfWatch script if something should happen. Let’s look at the event for transforming to and from beast.
The OnRaceSwitchComplete happens when changing to/from werewolf beast or vampire lord, but it also may happen when player loads a save for another character or during transformed beast. Like the comment warns, we should keep track if creature or not if we plan to do something. Above shows optional UnequipAll to undress the character at end of transformation, so must keep track. Otherwise the function simply tells DTWerewolfWatch.ProcessCheckMeter that a race change happened to let it decide if needs to start or end the meter display.
DTWerewolfWatch
The complete source file is 300+ lines long. Please refer to the source file available on GitHub.
If enabled, this script polls every X seconds using OnUpdate event. If the player disables, check if anything needs to be restored and cancel the next OnUpdate.
Near the top, I list all the properties together of objects found in the plugin files. Remember all the properties starting with “DTWW_” have been added in the DTWereWolfTimeMeter.esp plugin, and the others are part of the default game. Save key information to global variables to be used later. Here it’s good to know what time the player shifted to beast form (DTWW_PlayerShiftedToWereWolfTime), last known end-transformation time (DTWW_PlayerLastKnownShiftBackTime), and of course, it this darn thing is even running (DTWW_Enabled). Message objects edited in the CK notify the player of what’s happening.
If you’d like to see how these properties appear in Creation Kit, open my ESP-file, DTWerewolfTimeMeter.esp, and filter for “DTW” objects. Also see the quest, DTWW_WerewolfWatch, under the “scripts” tab.
- DTWW_Enabled: 0, 1, 2 for disabled, enabled, enabled-with-unequip
- DTWW_WerwolfMeterSpell: silently added with effect to damage magicka regeneration at 1200%
- DTWW_PlayerLastKnownShiftBackTime: to check if bloodlust has been extended
- DTWW_PlayerShiftedToWerwolfTime: to calculate time remaining and percentage for bar
- DTWW_WolfMeterToggleSpell: if player has this toggle spell then has been initialized
- DTWW_DamageMagickaRate: the effect that stops magicka regen - check if player has it to add or remove the spell
The OnUpdate Event is only called on Register, when playerAlias calls, or during meter display every few seconds to keep it updated.
I like to make sure initialization happens when the player isn’t busy, such as waiting until after the game introduction. Check Game.IsFightingControlsEnabled() and if false then wait again to try later. Before running the main function, ProcessCheckMeter, I added a precautionary check in case the meter has been disabled somehow.
Instead of showing the entire ProcessCheckMeter function, I cover the decision-making. Note the missing segments marked by ; Do stuff here.
The key here is to find out if the player is in beast form or not by checking the PlayerWerewolfQuest to see if IsRunning and the stage status. Looking at this quest in the CK, note that state 100 is the end so we only need to worry if PlayerWerewoflQuest.GetStage() < 100, beacuse otherwise the player is about to transform back.
Key decisions:
- Is the player in beast form? If so, check to add spell, DTWW_WerwolfMeterSpell, if needed. Update meter.
- Has the player shifted back? Remove DTWW_WerwolfMeterSpell and restore magicka.
Other conditions of note include checking if the player has extended bloodlust by feeding, or if extended bloodlust by MTSE lunar transformation.
Compatibility issues:
“Moonlight Tales” by Brevi doesn’t use PlayerWerewolfShiftBackTime for all-night lunar transformation. Instead, this value is set to 999 days in the future and an event is set. We don’t have direct access to that information, so instead it’s calculated using the function seen in the examples above, GetLunarTransformEndTime.
The boolean, showTimeMeter variable checks in case the damage-magicka-regen still needs adding.
Above at the end, we must check if shift-time has been updated and if it’s the first we’ve noticed (if playerLastKnownShiftTime == 0). Add spell and begin the meter if needed. If for some reason the spell fails to add, we can try again as shown below. The trimmed section below calculate the meter percentage and decides and updates using the function above in the examples.
If player has transformed back and have yet to restore (playerLastKnownShiftTime != 0), need to stop the meter and restore magicka level.
At the end of beast form and shifted back, we must remove the damage-magicka-regen spell, restore the magicka bar, and reset our global variables. I check to make sure the spell is removed as precaution and return success/failure so caller may decided if need to retry.
That’s how my werewolf transformation-time meter works, and a bit about writing Papyrus scripts for TES V: Skyrim.
Questions? Contact me on Nexusmods or via gmail.
Article #6 in a 10-part series.
- 1 - Skyrim Special Edition Released
- 2 - Convert Old Skyrim Mods for SE
- 3 - How to Disable Random Dragons in Skyrim
- 4 - Convert Black Sacrament Armor to SE Step-by-Step
- 5 - How to Update Meshes for Skyrim SE
- 6 - this article
- 7 - Skyrim SE - XPMSSE: Modify Weapon Positions
- 8 - Show Your Tail With Campfire Cloak In Skyrim
- 9 - Skyrim Frostfall and Survival Armor Edit for Warmth
- 10 - Frostfall SE with SKSE64
Skyrim, Skyrim Special Edition, Creation Kit, and The Elder Scrolls are trademarks of Bethesda Softworks LLC. All other trademarks belong to their respective owners.