GamerRick Posted December 14, 2022 Share Posted December 14, 2022 I have a script that will scan all NPCs when I enter an interior. I only want this script to run when I enter a fort or ruin and only run on enemy NPCs. Right now, the only thing I could think of is to limit the script to NPCs in certain factions (Bandit, Necromancer, VampireFaction, and the like). Is there another way to determine if the NPC is an enemy of the player or not? Is there a way to make sure it doesn't run when I enter other places, like homes and businesses? Thanks. Link to comment Share on other sites More sharing options...
IcelandicPsychotic Posted December 14, 2022 Share Posted December 14, 2022 This mod adds torches only to NPCs who are in dungeons and who are part of an "evil" faction. If you can figure out how this mod does that, you can probably apply the same method to your script. Link to comment Share on other sites More sharing options...
RomanR Posted December 14, 2022 Share Posted December 14, 2022 Most simple, although not much reliable way, would be to use GetCellMusicType command (OBSE) - as most caves, forts and ruins cells are using Dungeon type music. CS Wiki mentions two ways of determining hostility of one actor to another - https://cs.elderscrolls.com/index.php?title=GetShouldAttack. Link to comment Share on other sites More sharing options...
GamerRick Posted December 16, 2022 Author Share Posted December 16, 2022 (edited) Most simple, although not much reliable way, would be to use GetCellMusicType command (OBSE) - as most caves, forts and ruins cells are using Dungeon type music. CS Wiki mentions two ways of determining hostility of one actor to another - https://cs.elderscrolls.com/index.php?title=GetShouldAttack. Thanks. That is similar to something else I saw. Here is the latest script. I was working on making the script solve another problem with my game, where some NPCs will start out rotated 90 degrees to my right, and will run and attack in that direction instead of at me. I have solved this by opening the console and doing a disable/enable on the ones that do this. Unfortunately, this causes them to get recreated by the game with re-rolled equipment, spells, and stats. I want to add the ability to scan exteriors too, but am unsure how I would do that and limit it to only run once per cell or area (like it does for interiors). I an trying to see if not letting it run in any cell that has an owner will work, assuming no ruins have an owner. scn RFScannerQuestScript float fQuestDelayTime ref rCurrInterior ref rInterior1 ref rInterior2 ref rInterior3 short rInteriorNum ref rDL9Faction ref rOwner ref rNPC ref rNPCBase ref rItem ref rItemBase ref rEnch short iType short iNumItems short iIndex short iObjType short iTemp float fRand float fTemp ; User set percentages float fAmazonArmorDegPctMin float fAmazonArmorDegPctMax float fAmazonWeapDegPctMin float fAmazonWeapDegPctMax float fAmazonWeapChargePctMin float fAmazonWeapChargePctMax float fAmazonStaffChargePctMin float fAmazonStaffChargePctMax float fMarauderArmorDegPctMin float fMarauderArmorDegPctMax float fMarauderWeapDegPctMin float fMarauderWeapDegPctMax float fMarauderWeapChargePctMin float fMarauderWeapChargePctMax float fMarauderStaffChargePctMin float fMarauderStaffChargePctMax float fBanditArmorDegPctMin float fBanditArmorDegPctMax float fBanditWeapDegPctMin float fBanditWeapDegPctMax float fBanditWeapChargePctMin float fBanditWeapChargePctMax float fBanditStaffChargePctMin float fBanditStaffChargePctMax float fConjurerArmorDegPctMin float fConjurerArmorDegPctMax float fConjurerWeapDegPctMin float fConjurerWeapDegPctMax float fConjurerWeapChargePctMin float fConjurerWeapChargePctMax float fConjurerStaffChargePctMin float fConjurerStaffChargePctMax float fNecroArmorDegPctMin float fNecroArmorDegPctMax float fNecroWeapDegPctMin float fNecroWeapDegPctMax float fNecroWeapChargePctMin float fNecroWeapChargePctMax float fNecroStaffChargePctMin float fNecroStaffChargePctMax float fUndeadArmorDegPctMin float fUndeadArmorDegPctMax float fUndeadWeapDegPctMin float fUndeadWeapDegPctMax float fUndeadWeapChargePctMin float fUndeadWeapChargePctMax float fUndeadStaffChargePctMin float fUndeadStaffChargePctMax float fVampArmorDegPctMin float fVampArmorDegPctMax float fVampWeapDegPctMin float fVampWeapDegPctMax float fVampWeapChargePctMin float fVampWeapChargePctMax float fVampStaffChargePctMin float fVampStaffChargePctMax float fDremArmorDegPctMin float fDremArmorDegPctMax float fDremWeapDegPctMin float fDremWeapDegPctMax float fDremWeapChargePctMin float fDremWeapChargePctMax float fDremStaffChargePctMin float fDremStaffChargePctMax float fOtherArmorDegPctMin float fOtherArmorDegPctMax float fOtherWeapDegPctMin float fOtherWeapDegPctMax float fOtherWeapChargePctMin float fOtherWeapChargePctMax float fOtherStaffChargePctMin float fOtherStaffChargePctMax float fCreatureArmorDegPctMin float fCreatureArmorDegPctMax float fCreatureWeapDegPctMin float fCreatureWeapDegPctMax float fCreatureWeapChargePctMin float fCreatureWeapChargePctMax float fCreatureStaffChargePctMin float fCreatureStaffChargePctMax ;================================= float fArmorDegPctMin float fArmorDegPctMax float fWeapDegPctMin float fWeapDegPctMax float fWeapChargePctMin float fWeapChargePctMax float fStaffChargePctMin float fStaffChargePctMax float fCurrentStat float fBaseStat array_var arItems string_var strHexID string_var strHexIDBase short bCantRun short bEnableNeeded Begin GameMode if GetGameLoaded set fQuestDelayTime to 0.5 if FileExists "Data\ini\RicksDegradeStuff.ini" PrintC"RicksDegradeStuff - Reading settings from ini file" RunBatchScript "Data\ini\RicksDegradeStuff.ini" set bCantRun to 0 if IsModLoaded "DLCMehrunesRazor.esp" set rDL9Faction to GetFormFromMod "DLCMehrunesRazor.esp" "14E9" else set rDL9Faction to 0 endif else set bCantRun to 1 MessageBox "Ricks Degrade Stuff - Can't read ini file." endif return endif if bCantRun return endif if bEnableNeeded set bEnableNeeded to 0 set fQuestDelayTime to 0.5 set rNPC to GetFirstRef 69 while (rNPC) ;PrintC"==================================== Found Actor: %n ==================" rNPC set rNPCBase to rNPC.GetBaseObject if rNPC.GetObjectType == 35 && rNPC.GetItemCount RFDisabledToken > 0 rNPC.RemoveItem RFDisabledToken 1 rNPC.Enable endif set rNPC to GetNextRef loop return endif if player.IsInInterior set rOwner to player.GetParentCellOwner if rOwner return endif set rCurrInterior to player.GetParentCell if rCurrInterior == rInterior1 || rCurrInterior == rInterior2 || rCurrInterior == rInterior3 return endif set rInteriorNum to rInteriorNum + 1 if rInteriorNum > 3 set rInteriorNum to 1 endif if rInteriorNum == 1 set rInterior1 to rCurrInterior elseif rInteriorNum == 2 set rInterior2 to rCurrInterior else set rInterior3 to rCurrInterior endif set bEnableNeeded to 0 set rNPC to GetFirstRef 69 while (rNPC) ;PrintC"==================================== Found Actor: %n ==================" rNPC set rNPCBase to rNPC.GetBaseObject if rNPC.GetObjectType == 35 || (rNPC.GetObjectType == 36 && rNPC.CreatureUsesWeaponAndShield) ; NPC or armed creature if rNPC.GetItemCount RFScannedToken == 0 rNPC.AddItem RFScannedToken 1 set fArmorDegPctMax to 0.0 if rNPC.GetInFaction AmazonFaction ;PrintC"NPC %n Being processed..." rNPCBase set fArmorDegPctMax to fAmazonArmorDegPctMax set fArmorDegPctMin to fAmazonArmorDegPctMin set fWeapDegPctMax to fAmazonWeapDegPctMax set fWeapDegPctMin to fAmazonWeapDegPctMin set fWeapChargePctMax to fAmazonWeapChargePctMax set fWeapChargePctMin to fAmazonWeapChargePctMin set fStaffChargePctMax to fAmazonStaffChargePctMax set fStaffChargePctMin to fAmazonStaffChargePctMin elseif rNPC.GetInFaction MarauderFaction || (rDL9Faction != 0 && rNPC.GetInFaction rDL9Faction) set fArmorDegPctMax to fMarauderArmorDegPctMax set fArmorDegPctMin to fMarauderArmorDegPctMin set fWeapDegPctMax to fMarauderWeapDegPctMax set fWeapDegPctMin to fMarauderWeapDegPctMin set fWeapChargePctMax to fMarauderWeapChargePctMax set fWeapChargePctMin to fMarauderWeapChargePctMin set fStaffChargePctMax to fMarauderStaffChargePctMax set fStaffChargePctMin to fMarauderStaffChargePctMin elseif rNPC.GetInFaction BanditFaction || rNPC.GetInFaction VeyondCaveBandits set fArmorDegPctMax to fBanditArmorDegPctMax set fArmorDegPctMin to fBanditArmorDegPctMin set fWeapDegPctMax to fBanditWeapDegPctMax set fWeapDegPctMin to fBanditWeapDegPctMin set fWeapChargePctMax to fBanditWeapChargePctMax set fWeapChargePctMin to fBanditWeapChargePctMin set fStaffChargePctMax to fBanditStaffChargePctMax set fStaffChargePctMin to fBanditStaffChargePctMin elseif rNPC.GetInFaction ConjurerFaction set fArmorDegPctMax to fConjurerArmorDegPctMax set fArmorDegPctMin to fConjurerArmorDegPctMin set fWeapDegPctMax to fConjurerWeapDegPctMax set fWeapDegPctMin to fConjurerWeapDegPctMin set fWeapChargePctMax to fConjurerWeapChargePctMax set fWeapChargePctMin to fConjurerWeapChargePctMin set fStaffChargePctMax to fConjurerStaffChargePctMax set fStaffChargePctMin to fConjurerStaffChargePctMin elseif rNPC.GetInFaction NecromancerDungeon || rNPC.GetInFaction NecromancerFaction set fArmorDegPctMax to fNecroArmorDegPctMax set fArmorDegPctMin to fNecroArmorDegPctMin set fWeapDegPctMax to fNecroWeapDegPctMax set fWeapDegPctMin to fNecroWeapDegPctMin set fWeapChargePctMax to fNecroWeapChargePctMax set fWeapChargePctMin to fNecroWeapChargePctMin set fStaffChargePctMax to fNecroStaffChargePctMax set fStaffChargePctMin to fNecroStaffChargePctMin elseif rNPC.GetInFaction UndeadFaction set fArmorDegPctMax to fUndeadArmorDegPctMax set fArmorDegPctMin to fUndeadArmorDegPctMin set fWeapDegPctMax to fUndeadWeapDegPctMax set fWeapDegPctMin to fUndeadWeapDegPctMin set fWeapChargePctMax to fUndeadWeapChargePctMax set fWeapChargePctMin to fUndeadWeapChargePctMin set fStaffChargePctMax to fUndeadStaffChargePctMax set fStaffChargePctMin to fUndeadStaffChargePctMin elseif rNPC.GetInFaction VampireFaction set fArmorDegPctMax to fVampArmorDegPctMax set fArmorDegPctMin to fVampArmorDegPctMin set fWeapDegPctMax to fVampWeapDegPctMax set fWeapDegPctMin to fVampWeapDegPctMin set fWeapChargePctMax to fVampWeapChargePctMax set fWeapChargePctMin to fVampWeapChargePctMin set fStaffChargePctMax to fVampStaffChargePctMax set fStaffChargePctMin to fVampStaffChargePctMin elseif rNPC.GetInFaction DremoraFaction set fArmorDegPctMax to fDremArmorDegPctMax set fArmorDegPctMin to fDremArmorDegPctMin set fWeapDegPctMax to fDremWeapDegPctMax set fWeapDegPctMin to fDremWeapDegPctMin set fWeapChargePctMax to fDremWeapChargePctMax set fWeapChargePctMin to fDremWeapChargePctMin set fStaffChargePctMax to fDremStaffChargePctMax set fStaffChargePctMin to fDremStaffChargePctMin elseif rNPC.isActorEvil if rNPC.GetDisposition player < 20.0 ; NPC is hostile to the player set fArmorDegPctMax to fOtherArmorDegPctMax set fArmorDegPctMin to fOtherArmorDegPctMin set fWeapDegPctMax to fOtherWeapDegPctMax set fWeapDegPctMin to fOtherWeapDegPctMin set fWeapChargePctMax to fOtherWeapChargePctMax set fWeapChargePctMin to fOtherWeapChargePctMin set fStaffChargePctMax to fOtherStaffChargePctMax set fStaffChargePctMin to fOtherStaffChargePctMin endif elseif rNPC.IsCreature set fArmorDegPctMax to fCreatureArmorDegPctMax set fArmorDegPctMin to fCreatureArmorDegPctMin set fWeapDegPctMax to fCreatureWeapDegPctMax set fWeapDegPctMin to fCreatureWeapDegPctMin set fWeapChargePctMax to fCreatureWeapChargePctMax set fWeapChargePctMin to fCreatureStaffChargePctMin set fStaffChargePctMax to fCreatureStaffChargePctMax set fStaffChargePctMin to fCreatureStaffChargePctMin endif ;======================================================================================= ; Weapon Type: ; 0: Blade1H ; 1: Blade2H ; 2: Blunt1H ; 3: Blunt2H ; 4: Staff ; 5: Bow ;=================================================================================== (min + GetRandomPercent * (max-min+1)) / 100 if fArmorDegPctMax > 0 if rNPC.GetDead == 0 && rNPC.GetDisabled == 0 ;rNPC.Reset3DState rNPC.EVP endif ;if rNPC.GetDisabled == 0 ;rNPC.Disable ;rNPC.AddItem RFDisabledToken 1 ;set bEnableNeeded to 1 ;set fQuestDelayTime to 0.02 ;endif ForEach rItem <- rNPC set rItemBase to rItem.GetBaseObject set iObjType to rItem.GetObjectType ;sv_Destruct strHexID strHexIDBase set fBaseStat to GetObjectHealth rItemBase if iObjType == 20 ; Armor let fRand := Rand fArmorDegPctMin, fArmorDegPctMax set fRand to fRand / 100.0 set fRand to fBaseStat * fRand rItem.SetCurrentHealth fRand ;PrintC"Setting Armor %n to Health %.2f (of max %.2f" rItem, fRand, fBaseStat elseif iObjType == 33 ; Weapon set iType to rItem.GetWeaponType if iType != 4 set fBaseStat to GetObjectHealth rItemBase let fRand := Rand fWeapDegPctMin, fWeapDegPctMax set fRand to fRand / 100.0 set fRand to fBaseStat * fRand rItem.SetCurrentHealth fRand ;PrintC"Setting Weapon %n to Health %.2f (of max %.2f" rItem, fRand, fBaseStat let rEnch := GetEnchantment rItemBase if rEnch set fBaseStat to GetObjectCharge rItemBase let fRand := Rand fWeapChargePctMin, fWeapChargePctMax set fRand to fRand / 100.0 set fRand to fBaseStat * fRand rItem.SetCurrentCharge fRand ;PrintC"Setting Weapon charge for %n to charge %.2f (of max %.2f" rItem, fRand, fBaseStat endif else let fRand := Rand fStaffChargePctMin, fStaffChargePctMax set fRand to fRand / 100.0 set fRand to fBaseStat * fRand rItem.SetCurrentCharge fRand ;PrintC"Setting Staff %n to Charge %.2f (of max %.2f" rItem, fRand, fBaseStat endif endif loop endif endif endif set rNPC to GetNextRef loop ; endif end Edited December 16, 2022 by GamerRick Link to comment Share on other sites More sharing options...
RomanR Posted December 17, 2022 Share Posted December 17, 2022 That rotation ... would be enough to set angle on z axis on affected NPCs? I think that the angle can be computed from difference of x and y coordinates and then using trigonometric functions like sinus and arcsinus. Link to comment Share on other sites More sharing options...
GamerRick Posted December 17, 2022 Author Share Posted December 17, 2022 (edited) I don't know. All I know is that doing a disable/enable on that NPC fixes it, but it also rerolls them again from scratch (different equipment and spells for starters). I also have no idea how to ID an NPC in a script that has this bug. I will try to rotate them in the console and see what happems. This is a problem in my script, because I would change the NPC's weapons and armor and then disable them, and then the next time the script is called it enables them. I would need to do the weapon and armor changes after enabling them. But for now, I am trying to see if something as simple as doing an EVP on them will work. So far it has. The Reset3DState command caused a CTD eventually. Edited December 17, 2022 by GamerRick Link to comment Share on other sites More sharing options...
RomanR Posted December 19, 2022 Share Posted December 19, 2022 OK, for now I made a script in form of function which takes an NPC reference as a parameter and will rotate the NPC to face you. I can't say if it will be enough, but here it is: scn RomRFaceMeFnSetAngle ref actor float actor_x float actor_y float player_x float player_y float a float b float c float temp float angle short quadrant begin function { actor } set angle to -1 set quadrant to 0 set actor_x to actor.GetPos X set actor_y to actor.GetPos Y set player_x to player.GetPos X set player_y to player.GetPos Y set a to player_x - actor_x set b to player_y - actor_y ;print $a ;print $b if a != 0 || b != 0 ; most simple case if a == 0 if b > 0 set angle to 0 endif if b < 0 set angle to 180 endif endif if b == 0 if a > 0 set angle to 90 endif if a < 0 set angle to 270 endif endif ; all other cases if angle == -1 ; determining quadrant if a > 0 && b > 0 set quadrant to 1 ; 0 - 89 endif if a > 0 && b < 0 set quadrant to 2 ; 90 - 179 endif if a < 0 && b > 0 set quadrant to 4 ; 270 - 359 endif if a < 0 && b < 0 set quadrant to 3 ; 180 - 269 endif ;print $quadrant ; "distance" c set c to a if c < 0 set c to 0 - c endif set c to c * c set temp to b if temp < 0 set temp to 0 - temp endif set temp to temp * temp set c to c + temp let c := sqrt c ;print $c ; angle set angle to a/c if angle < 0 set angle to 0 - angle endif let angle := ASin angle endif if angle != -1 if quadrant == 0 actor.SetAngle Z angle else if quadrant == 1 actor.SetAngle Z angle endif if quadrant == 2 set angle to 180 - angle actor.SetAngle Z angle endif if quadrant == 3 set angle to 180 + angle actor.SetAngle Z angle endif if quadrant == 4 set angle to 360 - angle actor.SetAngle Z angle endif endif ;print $angle endif endif end Link to comment Share on other sites More sharing options...
GamerRick Posted December 20, 2022 Author Share Posted December 20, 2022 (edited) Thanks! I am seeing the problem still occur, which means the EVP doesn't do squat. But I just found that doing a 'setangle y' on an NPC in the console has no effect at all. With other objects, you would have to do the disable/enable thing to get any setpos or setangle to work. What I found with NPCs is that this doesn't work at all on them anyway. Even it you disable them first and then do a setpos or setangle on them, when they're enabled, the game re-rolls them and then places them where it wants to, probably based a bit on the path-grid. So, years ago when I tried to replace one NPC with another, I could never get the new NPC to appear exactly where the first one was. So, since the ONLY way to fix this is to disable/enable them anyway, I decided to just change my script to perform the weapon and armor degrades after then are enabled. It all happens when I first enter the cell for the first time, so I only notice this when I enter an interior that has NPC(s) that I can see right away. I see no way to determine what NPCs are at the 90 degree CCW angle to me. Even doing a getangle shows nothing that would indicate this NPC needs to be actioned. However, it never happens to creatures. So, I can just limit it to NPCs only. I would love to figure out why this happens. Is it something you've heard about before? It it just me? Edited December 20, 2022 by GamerRick Link to comment Share on other sites More sharing options...
RomanR Posted December 20, 2022 Share Posted December 20, 2022 (edited) If you look closely to my script, you see that I'm setting angle on Z axis, not Y. I tested this function as a part of experimental Face Me spell and result was good - the affected NPC was always facing the player's direction as I moved PC around. You can easily modify the script to return the angle only and compare it to actual NPC's. I haven't much ideas why the NPC are rotated that way you're speaking, I can only speculate it's some init thing as you enter particular cell. It sometimes happens to me to, often if there are NPCs or creatures of opposite faction - seems the PC is somewhat last in init order and sometimes I witness already running battle, for example between marauders and bandits. Of course I can't deny possibility of some mod's influence. But I was never concerned about it much, because I must often kill all hostile actors anyway. Edited December 20, 2022 by RomanR Link to comment Share on other sites More sharing options...
Recommended Posts