Jump to content

Some scripting questions


elezraita

Recommended Posts

Hi all,

 

I'm pretty new to papyrus, as in I really just started in earnest a day ago; I've been reading about it for a couple of weeks and doing some tutorials. Also, I don't really have a whole lot of coding experience. I've just been reading a lot. Anyway, I have some questions about a script I'm trying to write in which I'm trying to prevent the equiping of certain armors based on their models' compatibility with a given actor's body type. I've experimented with duplicating armors and changing their model paths in the duplicated armor addons such that there exist both a compatible armor and an incompatible one in the game. That seems to work pretty well. Now, I've tried writing a script that will disallow equiping armors that are linked as properties to the script. Honestly, I have no idea if I'm even close.

 

 

ScriptName ArmorFit Extends ObjectReference

ObjectReference property tArmor auto

Event OnEquipped(Actor akActor)
race playerrace = Game.GetPlayer.GetRace() ;Get the player character race and store it as playerrace
if akActor.GetRace() == playerrace ;if the equipping actor's race is that of the PC
akActor.UnEquipItem(tArmor, true) ;should prevent the actor from equipping the property, tArmor???
debug.Trace ("This doesn't fit very well.")
endif
endevent

 

 

I've probably done a bunch of stuff wrong here; I haven't tried to compile this, as I'm not at my main computer. I just wrote it to get ideas about how to implement what I'm trying to do.

 

I tried to use race to determine body type since I figured that the only Actors with different body types in my game would be those of a custom race. If I ever get this mod to the point at which I'd be comfortable releasing it, I'll find a better implementation. I originally thought of using getmodelpath to determine whether the armor should be equiped, but I couldn't see anyway of manipulating strings.

 

Anyway, my first question has to do with persistence. Eventually, I want to use skyproc to add this script to every piece of armor in the main meshes folder that has a corresponding mesh in a different folder. I think that this is possible, though I'm not even close to being to that point. What I want to know is if I call a property in this way, will it be persistent even though there is an event associated with it? I imagine that property will be persistent once the UnEquipItem is called, but I'm okay with that, because that armor will eventually be deleted and exchanged for the corresponding one from the other folder. (That should unload the reference, right?) What I don't want is for every single armor to which I attach this script (once it's done) to be loaded forever during runtime. If the way I've done this will cause persistence, is there a way you can think of to avoid that?

 

It's possible that I'm asking this question because I don't understand how properties work. I think I do, but maybe not. If I understand right, you define properties in your script and then link objects or actors to the properties in the CK. This would mean that I could, for example, link the studded leather armor to this script and then link corresponding boots. If I then try to equip either the studded leather armor or the boots, this script will run for whichever I try to equip. Is that right?

 

Finally, I'm really not even sure of the syntax, especially with the akActor.GetRace() and the akActor.UnEquipItem(tArmor, true). I'm not sure if I use "akActor" to refer to the actor that's trying to equip the property. I think that's right, but the CK wiki isn't huge into detailing this type of syntax, or maybe I just missed it.

 

So, hopefully that made sense; I know there is a lot here. Thanks in advance for any help.

Link to comment
Share on other sites

This would be my approach.

 

I would create the following:

a formlist that contains all of the armor for body type A

a formlist that contains all of the armor for body type B

a formlist that contains all of the races for body type A

a formlist that contains all of the races for body type B

a quest (perhaps start game enabled) with a player alias

The following script would be applied to the player alias

 

 

ScriptName PlayerWearsOnlyOneBodyTypeOfArmor Extends ReferenceAlias

FormList Property BodyTypeA_Armor Auto
FormList Property BodyTypeB_Armor Auto
FormList Property BodyTypeA_Race Auto
FormList Property BodyTypeB_Race Auto
Actor Property PlayerRef Auto
Race PlayerRace

Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
	PlayerRace = PlayerRef.GetRace()
	If BodyTypeA_Race.HasForm(PlayerRace)
		If BodyTypeA_Armor.HasForm(akBaseObject)
			;allow equip
		Else
			;disallow equip
			PlayerRef.UnequipItem(akBaseObject)
		EndIf
	ElseIf BodyTypeB_Race.HasForm(PlayerRace)
		If BodyTypeB_Armor.HasForm(akBaseObject)
			;allow equip
		Else
			;disallow equip
			PlayerRef.UnequipItem(akBaseObject)
		EndIf
	Else
		Debug.MessageBox("You are using an unexpected race. Armor may not fit appropriately.")
	EndIf
EndEvent

Event OnInit()
	RunMaint()
EndEvent

Event OnPlayerLoadGame()
	RunMaint()
EndEvent

Float Version = 0.0
Function RunMaint()
	Version = 0.1 ;change this value with every update to the script
	If Version > 0.0
		;examples of adding support for mod items without requiring them to be linked as parent plugins.
		Form CustomRace001 = Game.GetFormFromFile(0x00123456,"SomeOtherMod.esp")
		BodyTypeA_Race.AddForm(CustomRace001)
		Form CustomArmor001 = Game.GetFormFromFile(0x00abcdef,"YetAnotherMod.esp")
		BodyTypeB_Armor.AddForm(CustomArmor001)
	EndIf
EndFunction 

 

You could get deeper into it and use an MCM menu. With a menu list option you can ask the user to select the body type that they have installed for their player character. This way you wouldn't need to check by race but rather assign a numerical value to a global variable. Depending upon the value of the global variable, you know which formlist of armor to check against.

Link to comment
Share on other sites

I've thought about using an MCM eventually. The race thing was simply placeholder until I figure this stuff out. I didn't even know you could do most of the stuff you did in that script. My intention wasn't to get someone to do this for me, but to tell me what I was doing wrong. I guess that when you try to do something like this as a complete noob, it helps to have someone show you an elegant solution. Eventually, I'll get to the point where I can do this. Thanks for the reply; I really do appreciate the help. I'll try to figure out how to actually do all of the things you suggested.

Edited by elezraita
Link to comment
Share on other sites

You didn't have anything "wrong". The problem is that scripts on objects which are in an inventory do not always run every function. They might catch certain events but may not run the called functions.

Quote from the OnItemAdded wiki page

 

 

  • Once an object has been added to a container it is no longer valid to call member functions on it. Member functions on akItemReference (which is often None) will most likely fail to run with an error.

 

 

Not to mention that your method would have required adding a script to every piece of armor. That is a tedious job at best and would cause issues when the mod is removed mid-game. More information....

Link to comment
Share on other sites

Thank you for clarifying that. I couldn't figure out why the script I'd attached to the armor I was testing wasn't doing anything. I'd read that quote, but for some reason, I wasn't getting it. I thought that I was just assigning the property wrong. I'm going to ask a naive question, just for future reference. In this case, I was attaching the script to a given piece of armor, but I wasn't sure what to do with the property. After I looked at it, I left the property value at default, even though I'm not certain what this really means. I figured that it meant that the property would be the piece of armor to which the script was attached. Is this correct, or am I missing something? I tried commenting out a bunch of different things to see if I could get the script to do anything at all, but I never could. I figured that it just wasn't being fired because it wasn't attached to the object correctly. At that point, I was tired, so I went to bed. I still don't know if the script was attached wrong and it wasn't pointing to the correct object, or if I just couldn't call member functions on something in my inventory. I still think it is the first one because I couldn't get the debug message to appear even if I commented out the uneqippeditem line.
Link to comment
Share on other sites

If you left the property at default, then there was no value assigned to it. This would explain why nothing was unequipped.

 

The debug message, if it appeared, would have appeared inside the papyrus log. Did you check there? If you want to see a message in game, use Debug.Notification("text here") to have it appear in the upper left corner. Or Debug.MessageBox("text here") to have a box that pops up and pauses the game.

 

If the trace line was/is not in your papyrus log, then the race check failed for some reason.

Link to comment
Share on other sites

Yeah, I'm an idiot. I changed it to debug.notification and the message appeared. I'm not sure how to assign the armor as a property. When I try to assign properties, I get a list of cells and a list of references found in each cell. No armors appear there. There is obviously something very fundamental about this that I'm missing. I'm going to use your approach eventually, but I think that getting this to work will clear up some misconceptions I have regarding certain fundamentals.

 

Never mind. I got it to work. I needed to change the "objectreference property tarmor auto" to "armor property tarmor auto" then I was able to set the right property value. Duh...Now I can move on. Thank you! One thing though is that I still don't know if calling the property this way will cause persistence.

Edited by elezraita
Link to comment
Share on other sites

The reason I set up the script the way I did was that I wanted it to apply to every actor (well, followers) as well as the player. That way, I can give the armor the PC is using to a follower, and they will not equip it. Better would be that they don't equip armor that is too small and they get debuffs if they equip armor that is too big. But, one step at a time.

Edited by elezraita
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...