kingtitan Posted December 3, 2012 Share Posted December 3, 2012 (edited) While I don't think this question is extremely technical, I have just a couple questions about the messagebox and message functions. I am still learning the oblivion scripting language, so any clarification is much appreciated! Here are my issues: 1) When I use the message function, the message displays indefinitely until I go into menu mode. 2) Secondly, I know this is elementary, but when I use the messagebox function the message goes into an infinite loop. What do I add to the script so that it terminates properly? The messages are being used in an "object" script if that helps. I have also already looked at the cs wiki, but so far it has been no help. Any assistance would be greatly appreciated! Edit: I also forgot to mention that the message is executed under an "if" expression. So basically I want to limit the message to only a few seconds or make the messagebox terminate after "done" is pressed once. Edited December 3, 2012 by kingtitan Link to comment Share on other sites More sharing options...
DocRob Posted December 3, 2012 Share Posted December 3, 2012 A "DoOnce" variable should fix the problem, like so: scn ScriptName short DoOnce Begin GameMode If (DoOnce==0) Message "This is the message"Set DoOnce to 1elsereturnendifend I used GameMode there as an example but any block type (OnAdd, OnActivate, etc.) will benefit from using a DoOnce. There might be better/more elegant ways (I leave that to those with more experience than myself) but this should pretty much solve your problem. :smile: Link to comment Share on other sites More sharing options...
kingtitan Posted December 3, 2012 Author Share Posted December 3, 2012 (edited) That works better, but the only problem within my context is that the message literally only prints out once. Once the item is re-equiped the message does not print out at all. Any suggestions? Here is my code that I am trying to add the message to if it helps: Scn ATPrisonerCollarScript ref self ref wearer Begin GameMode Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( self.GetEquipped ATPrisonerCollar ) self.SetFactionRank ATPrisonerFaction, 0 else self.SetFactionRank ATPrisonerFaction, -1 endif End I didn't include a doOnce variable / statement because it was giving me the aforementioned behavior. I want to add a message that displays a confirmation message everytime the NPC is added to the faction, to be precise. Here is an idea (nonworking with doOnce) of what I have in mind: Scn ATPrisonerCollarScript ref self ref wearer short doOnce short doOnceNPC Begin GameMode Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( self.GetEquipped ATPrisonerCollar ) self.SetFactionRank ATPrisonerFaction, 0 if wearer != player && doOnceNPC == 0 Message "NPC has been added to the faction", 5 set doOnceNPC to 1 elseif wearer == player && doOnce == 0 Message "You have been added to the faction", 5 set doOnce to 1 endif else self.SetFactionRank ATPrisonerFaction, -1 endif End Edited December 3, 2012 by kingtitan Link to comment Share on other sites More sharing options...
DrakeTheDragon Posted December 4, 2012 Share Posted December 4, 2012 (edited) Hmm, that's a tougher one. These are the times I wish I could still start the CS to give it a try, but the game is installed on an external drive which is just on the verge of dying and I'm not going to power it up again before I have another one ready for backups. I think this could be handled by catching the response you give by clicking the ok button (GetButtonPressed should return "0").Try adding these lines to the start of your modified script and see if it helps already: Scn ATPrisonerCollarScript ref self ref wearer short doOnce short doOnceNPC short button ; for storing the result of the messagebox Begin GameMode set button to GetButtonPressed ; store the result of the messagebox if ( button != -1 ) ; reset do-once flags when a button was pressed set doOnce to 0 set doOnceNPC to 0 endif Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( self.GetEquipped ATPrisonerCollar ) self.SetFactionRank ATPrisonerFaction, 0 if wearer != player && doOnceNPC == 0 Message "NPC has been added to the faction", 5 set doOnceNPC to 1 elseif wearer == player && doOnce == 0 Message "You have been added to the faction", 5 set doOnce to 1 endif else self.SetFactionRank ATPrisonerFaction, -1 endif End In theory, or going by documentation, GetButtonPressed should return a value != -1 the first time it's called after the messagebox closed. If this doesn't work the way I did it up there, try adding a MenuMode block instead and catch it in there.I always call my messageboxes in GameMode and catch their result in MenuMode, which you're in while the messagebox is open. But if the documentation is right, it can also be done in GameMode, which you return to anyways right after the button was clicked and the messagebox closed. I have no way to test this though. edit: No, wait a second. The bottom part of the code will execute over and over again, putting self into the faction again and again, and popping up the messagebox again and again. A check if self already "is" in the faction (e.g. faction rank >= 0) becomes really mandatory here. Edited December 4, 2012 by DrakeTheDragon Link to comment Share on other sites More sharing options...
kingtitan Posted December 4, 2012 Author Share Posted December 4, 2012 Well I realized that a game mode type script won't work very well for having only a temporary message. However I had another idea, what if I were to write a whole other script and make it the collar's enchantment? That way the message can operate under a different block instead of having to use the GameMode block. If this would work could any of you guys get me started with it? I'm really not sure which block should be / could be used to get this working... Link to comment Share on other sites More sharing options...
DrakeTheDragon Posted December 4, 2012 Share Posted December 4, 2012 (edited) Hmm, while you could solve this task via an enchantment as well, saving you the need to check the container for if the item is worn (if it is worn, the enchantment runs, else it won't), it won't help you much with your current issues.I don't know if there is a way to detect when the enchanted item is unequipped at all in enchantments. Right now I see no way for the enchantment approach to remove the no-longer-affected actor from the faction again. ScriptEffectStart blocks always work, execute once as soon as the spell effect gets applied, and never repeat, ever.ScriptEffectFinish blocks act the same, just when the spell effect runs out, but I don't know if they're even triggered at all when an enchanted item gets unequipped/dropped/whatever!ScriptEffectUpdate blocks, in my observations, turned out absolutely unreliable, period. You cannot tell if they will execute or not in all cases, and do not expect them to "regularly" repeat either. Plus neither do I know if they're even executed in an enchantment at all. So, from my point of view we're back at a GameMode block, repeatedly checking for the affected actor having the item equipped, for the scripted effect spell the enchantment uses anyways. And this time, when you unequip the item, the script of the enchantment "dies", stopping execution right on the spot and taking all stored variables with it. There is no way an unequipped item could remove you from the faction via an enchantment approach, as while not worn no script will exist. You're pretty close with what you have already. Why not stick with what's already working? Scn ATPrisonerCollarScript ref self ref wearer Begin GameMode Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( ( self.GetEquipped ATPrisonerCollar ) && (self.GetFactionRank ATPrisonerFaction < 0 ) ) self.SetFactionRank ATPrisonerFaction, 0 if wearer != player && doOnceNPC == 0 Message "NPC has been added to the faction", 5 elseif wearer == player && doOnce == 0 Message "You have been added to the faction", 5 endif elseif ( self.GetFactionRank ATPrisonerFaction >= 0 ) self.SetFactionRank ATPrisonerFaction, -1 endif End That script should do, and also pop up the message only the first time the collar gets detected as worn while it is worn, as the actor now is only put into the faction once when he's not already in it.If you put on the collar, whether on yourself or an NPC, the messagebox should pop up, only once. If you take it off and put it on again, again the messagebox should pop up, and again only once.(That is only if GetButtonPressed actually works the way I expected it to work in this script.) Is this coming closer to what you had in mind? edit: Hey, just realized the whole "do-once" stuff and button checking is no longer needed at all now that the whole "put into faction"/"remove from faction" business is also only happening once each time! (cleaned up the code accordingly) Edited December 4, 2012 by DrakeTheDragon Link to comment Share on other sites More sharing options...
kingtitan Posted December 4, 2012 Author Share Posted December 4, 2012 (edited) The only flaw with that script though is the fact that the message does not go away after a certain period of time (assuming the collar is still equipped). A couple of the doOnce variables were left in the other script, so I finished cleaning it up and updated it to this: Scn ATPrisonerCollarScript ref self ref wearer Begin GameMode Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( ( self.GetEquipped ATPrisonerCollar ) && (self.GetFactionRank ATPrisonerFaction < 0 ) ) self.SetFactionRank ATPrisonerFaction, 0 if wearer != player Message "NPC has been added to the faction", 5 elseif wearer == player Message "You have been added to the faction", 5 endif elseif ( self.GetFactionRank ATPrisonerFaction >= 0 ) self.SetFactionRank ATPrisonerFaction, -1 endif End As far as I can tell, the script is evaluating the code to say that as long as the "self.GetEquipped" condition is true, the message should not terminate. I have a couple of questions though: Could we use another block entirely within the same script (not using GameMode) that uses the other established variables (self and wearer) to send the message? Maybe something like Begin OnEquip if self != player Message "NPC has been added to the faction", 5 elseif self == player Message "You have been added to the faction", 5 endif End which I could simply put below the GameMode block. What would be the estimated behaviour for this? Edit: I tested this added block of script and have at least some good news to report. The message appeared and disappeared in the five seconds allotted it, but there was never any message for the NPC character. Ha it's never that easy! But, that being said, can that block be improved upon to output the message for an NPC? Also, as another side note, I am still using Active Inventory to test this. My assumption is that 'self' is not holding the actor's reference between blocks. Edited December 4, 2012 by kingtitan Link to comment Share on other sites More sharing options...
DrakeTheDragon Posted December 4, 2012 Share Posted December 4, 2012 (edited) Hmm, I mixed up the Message you're using with a MessageBox call. My bad. That's different behavior for the two. Yes, you can use this OnEquip approach just as fine. Variables exist for the whole script. All blocks share the same and as such have access to the same values. Setting "wearer" to something in the GameMode block makes "wearer" also accessible from inside the OnEquip block. The trouble with the Message call not appearing for an NPC perhaps lies within the fact that you cannot always compare "player" and "self". A condition like "self != player" is not always guaranteed to work. The WiKi advises to use "self.GetIsReference player == 0" instead. So maybe this will help. The same comparison worked for you before though, so that's not very likely the problem. Oh, but I just realized "self" is not necessarily initialized in this case. It could help adding the "set self to GetContainer" line at the start of this block, too. Just so it is always initialized by all means. And coming to think of it, it depends on the inner workings of the inventory exchange mod you're using if the OnEquip block will be called at all.If the NPC itself decides to equip the item, so the mod only exchanges inventory contents, it will be fine.But if the mod uses the old "EquipItem" calls to force-equip those items onto the NPCs, this will fail. EquipItem does "not" trigger the OnEquip event. (I learned that the hard way.) I'm still clueless as to why the script I posted doesn't cease to display the Message though. Putting the wearer into the faction and only displaying the Message when this is not the case should work the same as a do-once condition. Technically it "is" a do-once condition. Yet, it still doesn't work as one... something must go wrong behind the scenes. Or the condition line is messed up but still compiles. For some cause the game doesn't like multiple function calls in a condition. It always mixes up what's a function parameter and what's another condition then. Edited December 4, 2012 by DrakeTheDragon Link to comment Share on other sites More sharing options...
kingtitan Posted December 5, 2012 Author Share Posted December 5, 2012 (edited) Well, I have a couple of interesting things to report. But first off the up to date code: Scn ATPrisonerCollarScript ref self ref wearer Begin GameMode Set self To GetContainer if ( wearer != 0 && wearer != self ) ; container changed and still has reference to previous wearer wearer.SetFactionRank ATPrisonerFaction, -1 set wearer to 0 ; delete reference to previous wearer endif if ( self.IsActor == 0 ) ; item got dropped, previous wearer got removed from faction by previous check in this case, too Return endif set wearer to self ; store reference to current wearer if ( self.GetEquipped ATPrisonerCollar ) self.SetFactionRank ATPrisonerFaction, 0 self.EquipItem2 ATPrisonerCollar else self.SetFactionRank ATPrisonerFaction, -1 endif End Begin OnEquip self set self to GetContainer if self.GetIsReference Player == 0 Message "They are now in the faction", 5 elseif self.GetIsReference Player Message "You are now in the faction", 5 endif End I did a bit of editing, for some reason one of the newer scripts was giving me strange behavior (the player would sometimes be in the faction and sometimes not). But I did have some interesting finds. First off, just to test the actual validity of the script's logic, I added the collar to an NPC via console commands - the traditional additem ref 1 and equipitem2 ref 1. I highlighted that console command because it is an OBSE command (as I'm sure you are well aware) so that I could bypass the traditional equipitem behavior. As it is no surprise, the message fired correctly and the NPC was placed into the faction. Would it be good to post the code from the Active Inventory spell so that we can write this code in conjunction with it? Edited December 5, 2012 by kingtitan Link to comment Share on other sites More sharing options...
kingtitan Posted December 5, 2012 Author Share Posted December 5, 2012 Here is the Active Inventory script, if that helps anything: scn xxU005SpellSCRIPT ref xNpc ref xInv short xAccess Begin ScriptEffectStart if (IsInCombat == 0) && (GetDead == 0) && (IsActor == 1) set xNpc to getself set xAccess to 1 xInBoxRef.Enable ;set xInv to PlaceAtMe xInBox 1 0 -50 xInBoxRef.SetOwnership ;xInv.SetOwnership else dispel xxUSP005 endif End Begin ScriptEffectUpdate if (xAccess == 3) AddItem xURing 1 EquipItem2 xURing RemoveItem xURing 1 set xAccess to 4 endif if (xAccess == 2 && MenuMode == 0) set xAccess to 3 xInBoxRef.RemoveAllItems xNpc ;xInv. RemoveAllItems xNpc xInBoxRef.Disable ;xInv.Disable endif if (xAccess == 1) xNpc.RemoveAllItems xInBoxRef ;xNpc.RemoveAllItems xInv xInBoxRef.activate player ;xInv.activate player set xAccess to 2 endif End For now though, I think I am going to just write up a simple spell that adds and equips a collar on the NPC that it is cast upon. Link to comment Share on other sites More sharing options...
Recommended Posts