Anything not in italics was written by him, though likely slightly edited by me for better clarification and stuff like that.
- Particle shaders, responsible for all detection spells in game/CK, can only be applied to Actors.
- Effect shaders do not allow for simple exchange of meshes that have the Z-TestBuffer enabled for membrane shaders. Which basically means you can't use 'shine through' effect on membrane shaders, only particle shaders allow this.
- You can't simply apply image space modifiers and detect life shaders to actors/player to mimic detection events. Both elements are well coordinated in the detection MGEF's.
Ok, so now I'm going to show you how to circumvent those problems. I strongly recommend making the mod based on all DLC's in order to gain full access to all available files, though the whole thing is probably feasible with only using Skyrim.esm. First here's what you need in your Mod:
- One FormList built from scratch.
- One duplicated 'DetectLifeEnemyInteriorSelfFF' MGEF.
- One duplicated 'Detect Life' Spell.
- One duplicated 'DLC2DetectLifeBoxActor' Actor.
- One Quest built from scratch. This is an empty quest. Just the usual quest data like EditorID and such.
- One Effect Shader duplicated or built from scratch, whichever you prefer.
Make sure to prefix all of your instances. for example, if you were to build an arrow detection mod via hotkey, then name the files FAH_DetectArrowSpell (FAH = Find Arrow Hotkey). Save your mod with the corresponding prefix (as the name of the .esp). Now let's do the easy things first:
1. Go to your duplicated actor instance and change the height from 1.00 to 0.10 (smallest size available depending on the mesh). You do this in order to place the Detection Dummy close to the object you want to detect, but also making sure you can't see it.
2. Now open your FormList and put every single instance you want to detect later in-game into the FormList. In my case I've put all playable arrows into the FormList.
3. Now go to your MGEF, remove all conditions then add this condition:
Subject -> GetIsID -> YourDetectorDummy == 1.00 AND
...remove everything else you feel isn't needed inside the MGEF. Like for example sound, and other Visual Effects that aren't 'LifeDetectedFriend' and 'DetectLife01IMod'.
4. Now open your Spell and remove all effects adding only your custom made effect. Also remove all auto calculations, but leave 'Area Effect Ignores LOS' ticked.
5. Now it's a good time to save your mod again.
6. Now open your effect shader and turn off the particle shader. Then turn on the membrane shader. Remove the palette texture and copy this to your fill texture...
Effects\GhostShaderRedGrad.dds
...for color, I recommend using orange colors all the way. Everything else is open for you to experiment. For example, my membrane shader is light blue with a white glow.
Ok, so now this was the membrane shader that gets applied to the items you want to detect, in my case arrows, here's a picture on how it looks in game:
1. Set up the quest you made earlier for SkyUI MCM and SKSE Hotkey feature, aka Start Game Enabled/Run Once and a PlayerAlias with the SKI_PlayerLoadGameAlias script attached.
2. Attach a script to your quest similar to the following code (see the MCM Quickstart for a bit of information on some of those functions, and note that this is a very long script):
Scriptname FAH_FindArrowQuestScript extends SKI_ConfigBase
Actor Property PlayerREF Auto
ActorBase Property FAH_DetectorDummy Auto
FormList Property FAH_ArrowFormList Auto
EffectShader Property FAH_MembraneShader Auto
Spell Property FAH_DetectArrowSpell Auto
Int KeyFindArrow
Int KeyArrow
Event OnConfigInit()
RestoreValues()
EndEvent
Event OnGameReload()
Parent.OnGameReload()
RestoreValues()
EndEvent
Event OnPageReset(string Page)
If (Page == "")
Return
Else
UnloadCustomContent()
EndIf
If (Page == "Hotkey")
SetCursorFillMode(TOP_TO_BOTTOM)
SetCursorPosition(0)
AddHeaderOption("Find Arrow Hotkey")
KeyFindArrow = AddKeyMapOption("Find Arrow Hotkey", KeyArrow)
EndIf
EndEvent
Event OnOptionHighlight(int Option)
If (Option == KeyFindArrow)
SetInfoText("Set your find Arrow Hotkey!")
EndIf
EndEvent
Event OnOptionKeyMapChange(int a_option, int a_keyCode, string a_conflictControl, string a_conflictName)
If a_option == KeyFindArrow
bool Continue = true
If (a_conflictControl != "")
string msg
If (a_conflictName != "")
msg = "This key is already mapped to:\n'" + a_conflictControl + "'\n(" + a_conflictName + ")\n\nAre you sure you want to continue?"
Else
msg = "This key is already mapped to:\n'" + a_conflictControl + "'\n\nAre you sure you want to continue?"
EndIf
Continue = ShowMessage(msg, true, "Yes", "No")
EndIf
If (Continue)
KeyArrow = a_keyCode
SetKeymapOptionValue(a_option, a_keyCode)
RegisterForKey(KeyArrow)
EndIf
EndIf
EndEvent
Event OnKeyDown(Int aiKeyCode)
If aiKeyCode == KeyArrow && !Utility.IsInMenuMode()
UnregisterForKey(KeyArrow)
;Remove dummy detectors when key is pressed again Block
DetectorRef.Disable()
DetectorRef.Delete()
DetectorRef2.Disable()
DetectorRef2.Delete()
DetectorRef3.Disable()
DetectorRef3.Delete()
DetectorRef4.Disable()
DetectorRef4.Delete()
DetectorRef5.Disable()
DetectorRef5.Delete()
DetectorRef6.Disable()
DetectorRef6.Delete()
DetectorRef7.Disable()
DetectorRef7.Delete()
DetectorRef8.Disable()
DetectorRef8.Delete()
DetectorRef9.Disable()
DetectorRef9.Delete()
DetectorRef10.Disable()
DetectorRef10.Delete()
DetectorRef11.Disable()
DetectorRef11.Delete()
DetectorRef12.Disable()
DetectorRef12.Delete()
DetectorRef13.Disable()
DetectorRef13.Delete()
DetectorRef14.Disable()
DetectorRef14.Delete()
DetectorRef15.Disable()
DetectorRef15.Delete()
DetectorRef16.Disable()
DetectorRef16.Delete()
DetectorRef17.Disable()
DetectorRef17.Delete()
DetectorRef18.Disable()
DetectorRef18.Delete()
DetectorRef19.Disable()
DetectorRef19.Delete()
DetectorRef20.Disable()
DetectorRef20.Delete()
;Registering Arrows on the ground Block
ObjectReference ArrowFloor = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor2 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor3 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor4 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor5 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor6 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor7 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor8 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor9 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor10 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor11 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor12 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor13 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor14 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor15 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor16 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor17 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor18 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor19 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
ObjectReference ArrowFloor20 = Game.FindRandomReferenceOfAnyTypeInListFromRef(FAH_ArrowFormList, PlayerREF, 3000.0)
;Applie membrane shader to arrows found Block
FAH_MembraneShader.Play(ArrowFloor, 30.0)
FAH_MembraneShader.Play(ArrowFloor2, 30.0)
FAH_MembraneShader.Play(ArrowFloor3, 30.0)
FAH_MembraneShader.Play(ArrowFloor4, 30.0)
FAH_MembraneShader.Play(ArrowFloor5, 30.0)
FAH_MembraneShader.Play(ArrowFloor6, 30.0)
FAH_MembraneShader.Play(ArrowFloor7, 30.0)
FAH_MembraneShader.Play(ArrowFloor8, 30.0)
FAH_MembraneShader.Play(ArrowFloor9, 30.0)
FAH_MembraneShader.Play(ArrowFloor10, 30.0)
FAH_MembraneShader.Play(ArrowFloor11, 30.0)
FAH_MembraneShader.Play(ArrowFloor12, 30.0)
FAH_MembraneShader.Play(ArrowFloor13, 30.0)
FAH_MembraneShader.Play(ArrowFloor14, 30.0)
FAH_MembraneShader.Play(ArrowFloor15, 30.0)
FAH_MembraneShader.Play(ArrowFloor16, 30.0)
FAH_MembraneShader.Play(ArrowFloor17, 30.0)
FAH_MembraneShader.Play(ArrowFloor18, 30.0)
FAH_MembraneShader.Play(ArrowFloor19, 30.0)
FAH_MembraneShader.Play(ArrowFloor20, 30.0)
;Place dummy detector at arrows Block
ObjectReference DetectorRef = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef2 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef3 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef4 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef5 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef6 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef7 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef8 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef9 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef10 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef11 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef12 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef13 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef14 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef15 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef16 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef17 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef18 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef19 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
ObjectReference DetectorRef20 = ArrowFloor.PlaceActorAtMe(FAH_DetectorDummy)
;Cast detection spell on dummy detector Block
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef2)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef3)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef4)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef5)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef6)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef7)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef8)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef9)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef10)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef11)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef12)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef13)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef14)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef15)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef16)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef17)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef18)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef19)
FAH_DetectArrowSpell.Cast(PlayerREF, DetectorRef20)
Utility.Wait(5)
;Remove previously placed dummy detectors Block
DetectorRef.Disable()
DetectorRef.Delete()
DetectorRef2.Disable()
DetectorRef2.Delete()
DetectorRef3.Disable()
DetectorRef3.Delete()
DetectorRef4.Disable()
DetectorRef4.Delete()
DetectorRef5.Disable()
DetectorRef5.Delete()
DetectorRef6.Disable()
DetectorRef6.Delete()
DetectorRef7.Disable()
DetectorRef7.Delete()
DetectorRef8.Disable()
DetectorRef8.Delete()
DetectorRef9.Disable()
DetectorRef9.Delete()
DetectorRef10.Disable()
DetectorRef10.Delete()
DetectorRef11.Disable()
DetectorRef11.Delete()
DetectorRef12.Disable()
DetectorRef12.Delete()
DetectorRef13.Disable()
DetectorRef13.Delete()
DetectorRef14.Disable()
DetectorRef14.Delete()
DetectorRef15.Disable()
DetectorRef15.Delete()
DetectorRef16.Disable()
DetectorRef16.Delete()
DetectorRef17.Disable()
DetectorRef17.Delete()
DetectorRef18.Disable()
DetectorRef18.Delete()
DetectorRef19.Disable()
DetectorRef19.Delete()
DetectorRef20.Disable()
DetectorRef20.Delete()
RegisterForKey(KeyArrow)
EndIf
EndEvent
Function RestoreValues()
RegisterForKey(KeyArrow)
EndFunction
FindAnyReferenceOfAnyTypeInListFromRef
...function.
And that concludes this tutorial. Thanks again to Mofakin for posting it and letting me edit it and post it here. If you have any questions, post them below and I'll try to answer them as best I can.