lasere200 Posted November 8, 2017 Share Posted November 8, 2017 (edited) Hi, I've come across some roadblocks with my mod and I am looking to solve them but I just can't on my own. Help would be greatly appreciated. 1. I currently handle player detection by keywording all NPCs in the game, finding them via FindAllReferencesWithKeyword with a 4096 range and using IsDetectedBy on each of them. Obviously this leads to a lot of conflicts. Is there a way to get if the player is detected or not (for purposes of stealing) without modifying NPC records and if possible without F4SE? ScriptName ALEnhDetectedEffectScript extends Activemagiceffect ;-- Properties -------------------------------------- Actor Property Player Auto float Property ALEnhRange Auto GlobalVariable Property ALEnhDetected Auto Keyword Property ALEnhDetectedKeyword Auto mandatory Perk Property ALEnhDetectedPerk Auto ;-- Variables --------------------------------------- ;-- Functions --------------------------------------- Event OnEffectStart(Actor akTarget, Actor akCaster) While (Player.HasPerk(ALEnhDetectedPerk)) ObjectReference[] Actors = Player.FindAllReferencesWithKeyword(ALEnhDetectedKeyword as Form, ALEnhRange) If (Actors.length != 0 || Actors != None) int x = 0 int d = 0 While (x < Actors.length) Actor kActor = Actors[x] as Actor If (Self.CheckIfaActorCanBeProcessed(Actors[x])) If (kActor != None) If (kActor.IsDead() == False) If (Player.IsDetectedBy(kActor) == True) d = 1 EndIf EndIf EndIf EndIf x += 1 EndWhile ALEnhDetected.SetValue(d as float) Else ALEnhDetected.SetValue(0 as float) EndIf EndWhile EndEvent bool Function CheckIfaActorCanBeProcessed(ObjectReference akItem) return akItem.Is3DLoaded() && !akItem.IsDisabled() && !akItem.IsDeleted() && !akItem.IsDestroyed() && !akItem.IsActivationBlocked() EndFunction 2. I am using this same method to to find containers around the Player. I have keyworded all the containers in the game and I am using FindAllReferencesWithKeyword. Is there a way to do this without without modifying records? Somehow use their type? 3. After I get the container this is what I use to loot it. I am looking to modify the function below to remove a certain keyword from the items I am picking up (which as far as I can tell means removing the keyword from the base object and adding it back after having looted). Also if there is some OnItemAdded on the Player solution to this I'd love to know about it, I don't know where to start. Basically it would need to check on every item added if it has a certain keyword and delete it (from the the added form not the base object) Function LootContainerItems(ObjectReference akContainer, Keyword akKeyword) akContainer.RemoveItem(akKeyword as Form, akContainer.GetItemCount(akKeyword as Form), True, Player as ObjectReference) EndFunctionThank you. Edit: What would solve 1 and 2 would be something like FindAllReferences. I wouldn't mind filtering all the references via scripting because it wouldn't require to modify npc and container records anymore.That's the dream. Edited November 8, 2017 by lasere200 Link to comment Share on other sites More sharing options...
steve40 Posted November 8, 2017 Share Posted November 8, 2017 (edited) It looks like you are making a perk to detect unlooted NPCs and containers? Well, I suppose instead of adding your keyword via CK, make a formlist of all containers/npcs that you want to add the keyword to, then run a script when the game loads to add the keyword to the objects in the formlist that don't have the keyword. That will solve the mod conflict issue. But, I don't really see why you need to use keywords in the first place. You could try using FindAllReferencesOfType(Container, ALEnhRange), which should return anything that extends the container script, including actors, I think.You could then use: "if (myItem is Actor)" to filter npcs if necessary. You could do an item count and assume that non-empty containers haven't been looted instead of using a keyword to track them. Edited November 8, 2017 by steve40 Link to comment Share on other sites More sharing options...
lasere200 Posted November 9, 2017 Author Share Posted November 9, 2017 FindAllReferencesOfType only accepts base objects or form lists as arguments, not actual "types", or at least that's what I gather from it's Creation Kit page. How would I go about adding keywords via script as you said? Is it possible to do it through Quest Aliases? I've seen you can assign keywords to them. All I am interested in is keywording actors and containers - and I saw that I can choose to search in the loaded area for actors only and even with GetIsObjectType set to "Container" as a type. Here is my mod. It works and it terms of gameplay there are very few quirks but the compatibility is very very low since I am modifying 5000 records just to add a single keyword.https://bethesda.net/en/mods/fallout4/mod-detail/1922946Here is the F3NV version which was a lot smoother and is what I am aiming for:https://www.nexusmods.com/newvegas/mods/42631/? Link to comment Share on other sites More sharing options...
lasere200 Posted November 9, 2017 Author Share Posted November 9, 2017 (edited) This is my main script and along with the detection script from above, my entire mod. I use two keywords one for looting, one for detection.The looting keyword is on all the items I want to loot, all containers and NPCs while the detection keyword is on all the NPCs.The only in game issue that I haven't been able to fix is removing the keyword from the items I loot from containers. Because of that when I drop them I automatically pick them back up once. Since they are being looted from the open world the second time the keyword actually gets removed. Being able to keyword cotnainers and NPC some other way could make a big differece. ScriptName ALEnhEffectScript extends Activemagiceffect ;-- PROPERTIES ---------------------------------- Actor Property Player Auto float Property ALEnhRange Auto Form Property AmmoFusionCore Auto Form Property PowerGenerator01 Auto Form Property WaterPurified Auto FormList Property ALEnhActivatorList Auto FormList Property ALEnhBottleList Auto Keyword Property ALEnhKeyword Auto mandatory Keyword Property BobbleheadKeyword Auto mandatory Keyword Property PerkMagKeyword Auto mandatory Perk Property ALEnhPerk Auto ;-- VARIABLES ----------------------------------- GlobalVariable Property ALEnhDetected Auto GlobalVariable Property ALEnhLockpicking Auto GlobalVariable Property ALEnhStealing Auto ;-- EVENTS -------------------------------------- ;---- Start ------------------------------------- Event OnEffectStart(Actor akTarget, Actor akCaster) While (Player.HasPerk(ALEnhPerk)) ObjectReference[] Loot = Player.FindAllReferencesWithKeyword(ALEnhKeyword as Form, ALEnhRange) If (Loot.length != 0 || Loot != None) int x = 0 While (x < Loot.length) If (Self.CheckIfReferenceCanBeProcessed(Loot[x])) ;------ Bodies and Corpses ---------------------- Actor kActor = Loot[x] as Actor If (kActor != None) If (kActor.IsDead() == True) If (!Loot[x].IsActivationBlocked()) LootContainerItems(Loot[x], ALEnhKeyword) EndIf EndIf EndIf ;------ Activators ------------------------------ ElseIf (ALEnhActivatorList.HasForm(Loot[x].GetBaseObject()) || Loot[x].HasKeyword(BobbleheadKeyword) || Loot[x].HasKeyword(PerkMagKeyword)) If (Loot[x].Is3DLoaded()) If (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) Loot[x].Activate(Player as ObjectReference, False) EndIf EndIf Else Loot[x].Activate(Player as ObjectReference, False) EndIf EndIf ;------------------------------------------------ ElseIf (!Loot[x].IsActivationBlocked() && Loot[x].Is3DLoaded()) ;------ Locked Containers ----------------------- ObjectReference kContainer = Loot[x].GetContainer() If (kContainer != None) If (KContainer.IsLocked() == True) If (ALEnhLockpicking.GetValue() == 1 as float) If (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) Loot[x].Activate(Player as ObjectReference, False) Utility.Wait(2 as float) EndIf EndIf Else Loot[x].Activate(Player as ObjectReference, False) Utility.Wait(2 as float) EndIf EndIf EndIf ;------ Unlocked Containers --------------------- Elseif (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) LootContainerItems(Loot[x], ALEnhKeyword) EndIf EndIf Else LootContainerItems(Loot[x], ALEnhKeyword) EndIf ;------ Empty Bottles --------------------------- ElseIf (ALEnhBottleList.HasForm(Loot[x].GetBaseObject())) If (Player.GetItemCount(WaterPurified) + Player.GetItemCount(ALEnhBottleList as Form) < 10) If (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf EndIf Else LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf EndIf ;------ Fusion Cores ---------------------------- ElseIf (Loot[x].GetBaseObject() == AmmoFusionCore) ObjectReference PowerGenerator = Game.FindClosestReferenceOfTypeFromRef(PowerGenerator01, Loot[x], 128 as float) If (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) If (PowerGenerator != None) Loot[x].RemoveKeyword(ALEnhKeyword) Loot[x].Activate(Player as ObjectReference, False) Else LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf ElseIf (PowerGenerator != None) Loot[x].RemoveKeyword(ALEnhKeyword) Loot[x].Activate(Player as ObjectReference, False) Else LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf EndIf ;------ Open World Items ------------------------ ElseIf (Player.WouldBeStealing(Loot[x])) If (ALEnhStealing.GetValueInt() == 1) If (ALEnhDetected.GetValueInt() == 0) LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf EndIf Else LootOpenWorldItem(Loot[x], ALEnhKeyword) EndIf ;---- End --------------------------------------- EndIf x += 1 EndWhile EndIf EndWhile EndEvent ;-- FUNCTIONS ----------------------------------- bool Function CheckIfReferenceCanBeProcessed(ObjectReference akItemReference) return !akItemReference.IsDisabled() && !akItemReference.IsDeleted() && !akItemReference.IsDestroyed() EndFunction Function LootContainerItems(ObjectReference akContainer, Keyword akKeyword) akContainer.RemoveKeyword(akKeyword) akContainer.RemoveItem(akKeyword as Form, akContainer.GetItemCount(akKeyword as Form), True, Player as ObjectReference) EndFunction Function LootOpenWorldItem(ObjectReference akItemReference, Keyword akKeyword) akItemReference.RemoveKeyword(akKeyword) Player.AddItem(akItemReference as Form, 1, True) EndFunction Edited November 9, 2017 by lasere200 Link to comment Share on other sites More sharing options...
ThoraldGM Posted November 16, 2017 Share Posted November 16, 2017 Is it possible to use the ApplyingEffect part of a cloak effect to get all containers in radius of player? In conditions there is [GetIsObjectType Container == 1], ** but I don't know if that just returns chests etc or the fact that everything Object Oriented is technically a container. [**Edit: Just saw OP mentioned this in post #3. Nothing to see here, sorry.] If it does restrict "container" to storage containers, then you could have the cloak effect place the keyword, and remove the keyword when activated/looted by player. But then you might also have a problem losing keywords with container respawn. Idk if that would work. Just thinking out loud. Link to comment Share on other sites More sharing options...
lasere200 Posted November 21, 2017 Author Share Posted November 21, 2017 (edited) So I made it work using your suggestion but it has some big shortcomings right now but it's still a big step in the right direction. Made a perk that adds an ability with a cloak/continuous/self magic effect to the player. The cloak applying effect is a spell (script/concentration/contact) that looks like this: Scriptname ALEnhKeywordEffectScript extends activemagiceffect Actor Property Player Auto Keyword Property ALEnhKeyword Auto mandatory Perk Property ALEnhCloakPerk Auto mandatory Event OnEffectStart(Actor akTarget, Actor akCaster) While (Player.HasPerk(ALEnhCloakPerk)) debug.trace("hep") akTarget.AddKeyword(ALEnhKeyword) EndWhile EndEvent The only thing I change from the default value is the magnitude of the cloak effect in the ability window (not the magic effect window). It seems to control the range (not any Area setting) Right now my conclusion is that the cloak applying effect only works on enemies that are alive. So if I kill a rat, out of effect range, it works. The keyword is applied to the corpse when I come in range and the corpse is automatically looted. It doesn't work on containers and corpses that were already dead (like the dog and raider dead near the sanctuary bridge). I need something like this to keyword containers too. Edited November 21, 2017 by lasere200 Link to comment Share on other sites More sharing options...
anphab Posted May 24, 2018 Share Posted May 24, 2018 why do you need remove or add a keyword? Link to comment Share on other sites More sharing options...
Recommended Posts