Difference between revisions of "User:Fg109"

From the CreationKit Wiki
Jump to navigation Jump to search
imported>Fg109
imported>Fg109
Line 1: Line 1:
I was trying to write a tutorial on papyrus basics on my user page, but I realize I absolutely suck at explaining things.  I'm just going to post (parts of) scripts that I made and liked.
I was trying to write a tutorial on papyrus basics on my user page, but I realize I absolutely suck at explaining things.  I'm just going to post (parts of) scripts that I made and liked.
== Saving Actor's Outfit ==
A function returning a 32 element array containing an actor's equipped (base) items.  Requires SKSE.
<source lang="papyrus">Form[] Function SaveOutfit(Actor akActor)
Form[] SavedOutfit = new Form[32]
int slot = 1
int i
int j
while (i < 32)
Form TempForm = akActor.GetWornForm(slot)
if (TempForm)
SavedOutfit[j] = TempForm
j += 1
endif
slot *= 2
i += 1
endwhile
Return SavedOutfit
EndFunction</source>
There will probably be empty elements, since the actor probably is not wearing an item in every single slot.  Automatically sorted so that empty elements are at the end of the array.


== Converting Local/Global Rotation ==
== Converting Local/Global Rotation ==

Revision as of 09:49, 1 June 2012

I was trying to write a tutorial on papyrus basics on my user page, but I realize I absolutely suck at explaining things. I'm just going to post (parts of) scripts that I made and liked.

Saving Actor's Outfit

A function returning a 32 element array containing an actor's equipped (base) items. Requires SKSE.

Form[] Function SaveOutfit(Actor akActor)
	Form[] SavedOutfit = new Form[32]
	int slot = 1
	int i
	int j
	while (i < 32)
		Form TempForm = akActor.GetWornForm(slot)
		if (TempForm)
			SavedOutfit[j] = TempForm
			j += 1
		endif
		slot *= 2
		i += 1
	endwhile
	Return SavedOutfit
EndFunction

There will probably be empty elements, since the actor probably is not wearing an item in every single slot. Automatically sorted so that empty elements are at the end of the array.

Converting Local/Global Rotation

I wrote a function for converting from local to global rotation. I find that I use it a lot.

Float[] Function ConvertRotation(Float AngleX, Float AngleY, Float AngleZ, Bool FromLocal = True)
    Float NewX
    Float NewY
    if (FromLocal)
        NewX = AngleX * Math.Cos(AngleZ) + AngleY * Math.Sin(AngleZ)
        NewY = AngleY * Math.Cos(AngleZ) - AngleX * Math.Sin(AngleZ)
    else
        NewX = AngleX * Math.Cos(AngleZ) - AngleY * Math.Sin(AngleZ)
        NewY = AngleY * Math.Cos(AngleZ) + AngleX * Math.Sin(AngleZ)
    endif
    Float[] Angles = new Float[3]
    Angles[0] = NewX
    Angles[1] = NewY
    Angles[2] = AngleZ
    Return Angles
EndFunction

Angle Z stays the same, because "Local" in this case means "What are the new X and Y angles if I turn (change the Z angle) to this heading?"

Multi Fire Spell

To create a multi-fire spell, you will need to create these things:

  1. An activator using the model of one of the magic projectiles
  2. Another activator that doesn't need any model (just duplicate DummyObject)
  3. An explosion that spawns the second activator
  4. A projectile that creates the explosion
  5. A spell that uses the projectile

The first activator should have a script with an OnTranslationAlmostComplete event that will place an explosion at itself (not the custom one you made) in order to inflict damage, then disable and delete itself.

The second activator should use this script:

Scriptname MissileTargetScript extends ObjectReference

Activator Property MissileObj Auto
ObjectReference[] Missiles
Int Count

Event OnInit()
	Actor Player = Game.GetPlayer()
	Missiles = New ObjectReference[128]
	Count = Utility.RandomInt(3, 13)
	Missiles[0] = Player.PlaceAtMe(MissileObj)
	Missiles[0].MoveTo(Player, 75 * Math.Sin(Player.GetAngleZ()), 75 * Math.Cos(Player.GetAngleZ()), \
		0.75 * Player.GetHeight())
	Float OffsetAngle = 360 / (Count - 1)
	int index = 1
	while (index < Count)
		Missiles[index] = Missiles[0].PlaceAtMe(MissileObj)
		Float DistanceXY = 64 * Math.Sin(OffsetAngle * (Index - 1))
		Float DistanceZ = 64 * Math.Cos(OffsetAngle * (Index - 1))
		Missiles[index].MoveTo(Missiles[0], DistanceXY * Math.Sin(Missiles[0].GetAngleZ() - 90), \
		DistanceXY * Math.Cos(Missiles[0].GetAngleZ() - 90), DistanceZ)
		Missiles[index].SetAngle(0, 0, Missiles[0].GetAngleZ() + Utility.RandomInt(-45, 45))
		index += 1
	endwhile
	Utility.Wait(0.25)
	index = 0
	while (index < Count)
		SmoothCurve(Missiles[index], Self, 1000)
		index += 1
	endwhile
	Disable()
	Delete()
EndEvent

Function SmoothCurve(ObjectReference A, ObjectReference B, Float Speed)
    Float AngleZ = A.GetHeadingAngle(B)
    if (AngleZ < -45)
        Float OffsetAngle = -45.0 - AngleZ
        AngleZ = -45.0
        A.SetAngle(0, 0, A.GetAngleZ() + OffsetAngle)
    elseif (AngleZ > 45)
        Float OffsetAngle = 45.0 - AngleZ
        AngleZ = 45.0
        A.SetAngle(0, 0, A.GetAngleZ() + OffsetAngle)
    endif
    Float DistanceXY = Math.sqrt((B.X - A.X) * (B.X - A.X) + (B.Y - A.Y) * (B.Y - A.Y))
    Float SplineMagnitude = DistanceXY / Math.Cos(AngleZ)
    Float AngleZEnd = A.GetAngleZ() + (A.GetHeadingAngle(B) * 2)
    A.SplineTranslateTo(B.X, B.Y, B.Z, 0, 0, AngleZEnd, Math.Abs(SplineMagnitude) * 0.75, Speed)
EndFunction

So what happens is you cast your custom spell. The custom spell creates a projectile. When the projectile hits something, it causes an explosion. The explosion would spawn an activator (the second one, our 'missile target'). The missile target would create 3 to 13 missiles (the first activators) and place them in a clock-like arrangement in front of the player. Then the missiles will fire themselves at the target (in a random curved trajectory) and explode when they reach it.

Basic Hunger Mod

Give actors an ability with this script:

Scriptname fg109TestMEScript extends ActiveMagicEffect

Faction Property HungerFaction Auto
Int Property UpdateInterval Auto
Formlist Property FoodsHighList Auto
Formlist Property FoodsMidList Auto
Formlist Property FoodsLowList Auto
Keyword Property VendorItemFood Auto
Actor Myself

Event OnEffectStart(Actor akTarget, Actor akCaster)
	Myself = akTarget
	;if NPC is not in the hunger faction, add him/her in
	if (Myself.GetFactionRank(HungerFaction) < 0)
		Myself.SetFactionRank(HungerFaction, 0)
	endif
	;increment "hunger variable" every UpdateInterval seconds
	RegisterForUpdate(UpdateInterval)
EndEvent

Event OnUpdate()
	if (Myself.GetFactionRank(HungerFaction) < 100)
		;increment the "hunger variable" by 1
		Myself.ModFactionRank(HungerFaction, 1)
	else
		;die of hunger
		Myself.Kill()
	endif
EndEvent

Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
	if (FoodsHighList.HasForm(akBaseObject))
		;we just ate something from FoodsHighList
		Myself.ModFactionRank(HungerFaction, -5)
	elseif (FoodsMidList.HasForm(akBaseObject))
		;we just ate something from FoodsMidList
		Myself.ModFactionRank(HungerFaction, -3)
	elseif (FoodsLowList.HasForm(akBaseObject))
		;we just ate something from the FoodsLowList
		Myself.ModFactionRank(HungerFaction, -1)
	elseif (akBaseObject.HasKeyword(VendorItemFood))
		;a food not in one of the lists (mod added?)
		if (akBaseObject.GetGoldValue() < 3)
			Myself.ModFactionRank(HungerFaction, -1)
		elseif (akBaseObject.GetGoldValue() < 5)
			Myself.ModFactionRank(HungerFaction, -3)
		else
			Myself.ModFactionRank(HungerFaction, -5)
		endif
	endif
	if (Myself.GetFactionRank(HungerFaction) < 0)
		;completely full
		Myself.SetFactionRank(HungerFaction, 0)
	endif
EndEvent