BlockActivation not working on Alias

Post » Thu Jun 21, 2012 4:35 pm

OK, so I have a quest that will set an actor (NPC/creature) to a ReferenceAlias.

I have pre-defined this alias in the editor, and have story manager handle setting it on an event I have specified, no problem there.

I have a script on said alias, and that is where the problem is occurring. I want to be able to pass the BlockActivation() command to the alias through its script. Here is what I have so far:

Scriptname phiTame_S1P1AliasScript extends AliasphiTame_S1P1Script Property phiTame_S1P1 auto     ; reference to the parent quest/scriptReferenceAlias Property phiS1P1Alias auto	       ; set to this alias manually in the editorMessage Property phiReanimate auto	         ; simple 3-button message set in editorphiS1P1Alias.BlockActivation()Event OnActivate(ObjectReference akActionRef)    Actor phiActor = phiS1P1Alias.GetActorReference() as Actor    int ibutton = phiReanimate.Show()        if (ibutton != -1)            if (ibutton == 0)                phiS1P1Alias.Clear()                phiTame_S1P1.Stop()            elseif (ibutton == 1)                phiActor.Resurrect()            elseif (ibutton == 2)            endif        endifEndEvent

I thought I should be able to call BlockActivation() directly on the alias since it wants an object reference and the alias is itself a reference alias. I also tried casting the alias as an object with no luck.

Here's the real funny thing. If I take out that one line the rest of the script compiles, but when I activate the alias in-game I get the message "You must have a pickaxe to do that!"

Is there some undocumented bug about activation and alias references that are actors?

Basically, I want to be able to prevent the player from looting all their minions stuff every time they die before being resurrected, so you can't just sit there chain-killing them getting rich!
User avatar
Joe Bonney
 
Posts: 3466
Joined: Tue Jul 17, 2007 12:00 pm

Post » Thu Jun 21, 2012 7:52 pm

I tried this:
ObjectReference phiObject = phiS1P1Alias as ObjectReferencephiObject.BlockActivation()

To that the compiler says: "no viable alternative at input 'phiS1P1Alias'"

So, I am guessing you can't cast a reference as an object that way. At least not for BlockActivation's purposes; it seems rather picky.

If there is a better way to bypass the activation routine for actors I would love to hear it!

EDIT: I also tried having the script itself extend ObjectReference instead of Alias since the wiki says "If you are adding a script to an object that is going to be a reference in the world (like a button for example) your script will need to extend this (the ObjectReference) script."

Still can't get BlockActivation to work, not using the alias reference nor the alias cast as an Object or Actor or even as Self.

Picky compiler is picky! =P
User avatar
Nims
 
Posts: 3352
Joined: Thu Jun 07, 2007 3:29 pm

Post » Thu Jun 21, 2012 3:13 pm

It isn't BlockActivation() that is the problem, it is that you can't have code like that in the "body" of the script, outside of events or user-defined functions. You'd need to put the BlockActivation call in something like an OnInit event.

Also note that your script should probably be extending ReferenceAlias, not Alias (in which case you don't need the ReferenceAlias property).
User avatar
Ebony Lawson
 
Posts: 3504
Joined: Fri Feb 16, 2007 11:00 am

Post » Thu Jun 21, 2012 5:29 pm

i can't remember if Alias scripts take OnInit events

but you can try one of these:

Event OnInit()phiS1P1Alias.GetRef().BlockActivation()EndEvent

or

Event OnCellAttach()phiS1P1Alias.GetRef().BlockActivation()EndEvent


in any case, you cant call a function by itself outside an event block or another function.
also, to obtain the reference of the filled alias, you use GetRef() which will return the reference as an objectref or GetActorRef() to return the ref as an actor
User avatar
Stephani Silva
 
Posts: 3372
Joined: Wed Jan 17, 2007 10:11 pm

Post » Thu Jun 21, 2012 2:33 pm

also if phiS1P1Alias is the refalias that this script is attached to, you dont need to declare it as a property. in which case it will be

GetRef().BlockActivation()

and your script should extend referencealias any time it is attached to a quest alias. otherwise it will dump a papyrus error saying it cant bind the script due to type mismatch

you also dont need to declare the parent quest script as a property either. you can use

(GetOwningQuest() as phiTame_S1P1Script).DoSomething()

GetOwningQuest() will always return the parent quest that the alias is attached to. you can use it to execute any quest related functions of your parent quest rather than declaring a property
User avatar
Daniel Holgate
 
Posts: 3538
Joined: Tue May 29, 2007 1:02 am

Post » Thu Jun 21, 2012 8:22 pm

Just a note, the OnInit() event in a reference alias script is only received when the owning quest is initiated. Using ForceRefTo() will not fire the OnInit() event in the script.
User avatar
Sophie Miller
 
Posts: 3300
Joined: Sun Jun 18, 2006 12:35 am

Post » Thu Jun 21, 2012 5:47 pm

It isn't BlockActivation() that is the problem, it is that you can't have code like that in the "body" of the script, outside of events or user-defined functions. You'd need to put the BlockActivation call in something like an OnInit event.

Event OnInit()phiS1P1Alias.GetRef().BlockActivation()EndEvent

also if phiS1P1Alias is the refalias that this script is attached to, you dont need to declare it as a property. in which case it will be

GetRef().BlockActivation()

and your script should extend referencealias any time it is attached to a quest alias. otherwise it will dump a papyrus error saying it cant bind the script due to type mismatch

you also dont need to declare the parent quest script as a property either. you can use

(GetOwningQuest() as phiTame_S1P1Script).DoSomething()

GetOwningQuest() will always return the parent quest that the alias is attached to. you can use it to execute any quest related functions of your parent quest rather than declaring a property

Just a note, the OnInit() event in a reference alias script is only received when the owning quest is initiated. Using ForceRefTo() will not fire the OnInit() event in the script.

All wonderful knowledge, thank you three! The CK and especially the community truly are wonderful!

@Amethyst: In your 2nd post just to clarify for anyone else reading this where you said "(GetOwningQuest() as phiTame_S1P1Script).DoSomething()", this is actually saying: (GetOwningQuest() as nameofscriptonowningquest).DoSomething()

Also, you don't have to declare the quest name as a property of that quest's script name in your owning quest's script to call this.

@DreamKing: I had a feeling that was part of it. I had seen people using OnInit events and it was something I was about to test. Also I did figure out to have my quest alias script extend ReferenceAlias all on my own! =P

@RandomNoob: Such invaluable information to know! I am both starting the quest and assigning the alias during the same Story Manager script event, so this tells me I am getting exactly the information I need from OnInit when I need it. =)

The script is now working perfectly! At least for the stage of development the project is currently at. Here is the current alias reference prototype for anyone following along:

Scriptname phiTame_S1P1AliasScript extends ReferenceAliasEvent OnInit()	GetRef().BlockActivation()EndEventEvent OnCellAttach()EndEventEvent OnActivate(ObjectReference akActionRef)	int ibutton = -1	Actor phiActor = GetActorReference() as Actor	ibutton = (GetOwningQuest() as phiTame_S1P1Script).phiReanimate.show()	while ibutton == -1		return	endwhile	if (ibutton == 0)		Clear()		GetOwningQuest().Stop()		ibutton = -1	elseif (ibutton == 1)		phiActor.Resurrect()		ibutton = -1	elseif (ibutton == 2)		ibutton = -1	endifEndEvent

On a side note: I could do this for a living! =P
User avatar
Kevin S
 
Posts: 3457
Joined: Sat Aug 11, 2007 12:50 pm

Post » Thu Jun 21, 2012 12:05 pm

couple small things to clean up your script:

if you are not currently using OnCellAttach for anything you should either comment it out (type a semi-colon ; at the start of the line) or delete it

also GetActorRef() already returns the ref as an actor, so there is no need to cast it as an actor.
User avatar
Shiarra Curtis
 
Posts: 3393
Joined: Thu Jan 04, 2007 3:22 pm

Post » Thu Jun 21, 2012 9:06 am

And you don't need to check for MessageBox menus returning -1 in Skyrim. That was how they worked in older games, you first showed a MessageBox and then called GetButtonPressed to detect when the player finally made a choice. But with the new Skyrim Show function, it does both things and doesn't give control back to your script until a button is pressed.

So I would rewrite your script like this.
Scriptname phiTame_S1P1AliasScript extends ReferenceAliasEvent OnInit()	GetRef().BlockActivation()EndEventEvent OnActivate(ObjectReference akActionRef)	int ibutton = (GetOwningQuest() as phiTame_S1P1Script).phiReanimate.show()	if (ibutton == 0)		Clear()		GetOwningQuest().Stop()	elseif (ibutton == 1)		GetActorReference().Resurrect()	;elseif (ibutton == 2)		; no action needed here for this choice	endifEndEvent

And if you don't use that phiReanimate messagebox in your main script, you might want to move the property into this one so you don't have to do the "(GetOwningQuest() as phiTame_S1P1Script)" part.
User avatar
tegan fiamengo
 
Posts: 3455
Joined: Mon Jan 29, 2007 9:53 am

Post » Thu Jun 21, 2012 7:56 pm

And you don't need to check for MessageBox menus returning -1 in Skyrim.
That's not necessarily true, depending upon the menu. If it's a one shot deal that only does A, B, or C, the check for -1 isn't necessary, but if it loops, offers sub-options, or sub-menus, the check is absolutely necessary.
Function Menu(Bool abMenu = True, Int aiButton = 0)	While abMenu		If (aiButton != -1) ; Wait for input or this menu WILL fail			aiButton = MainMenuMESG.Show() ; Main Menu			abMenu = False ; End the function			If (aiButton == 0) ; Breakfast				aiButton = BreakfastMESG.Show()				If (aiButton == 0) ; Sweet Roll & Coffee				ElseIf (aiButton == 1) ; Pancakes, Bacon & Eggs				ElseIf (aiButton == 2) ; Chicken Fried Pony Steak				EndIf			ElseIf (aiButton == 1) ; Lunch				aiButton = LunchMESG.Show()				If (aiButton == 0) ;  Glazed Turkey Sandwich				ElseIf (aiButton == 1) ; Grilled Ham Sandwich				ElseIf (aiButton == 2) ; Shredded Pony Sandwich				EndIf			ElseIf (aiButton == 2) ; Dinner				aiButton = DinnerMESG.Show()				If (aiButton == 0) ; Filet Mignon				ElseIf (aiButton == 1) ; Pony Fajitas				ElseIf (aiButton == 2) ; Lobster				EndIf			EndIf		EndIf	EndWhileEndFunction
User avatar
katie TWAVA
 
Posts: 3452
Joined: Tue Jul 04, 2006 3:32 am

Post » Thu Jun 21, 2012 10:54 am

It was the
	while ibutton == -1		return	endwhile
logic that I was talking about, but I still think your're wrong even in your new case. I strongly suspect that your code can be reduced to this without any problems.
Spoiler
Function Menu(Bool abMenu = True, Int aiButton = 0)	While abMenu		aiButton = MainMenuMESG.Show() ; Main Menu		If (aiButton == 0) ; Breakfast			aiButton = BreakfastMESG.Show()			If (aiButton == 0) ; Sweet Roll & Coffee			ElseIf (aiButton == 1) ; Pancakes, Bacon & Eggs			ElseIf (aiButton == 2) ; Chicken Fried Pony Steak			EndIf		ElseIf (aiButton == 1) ; Lunch			aiButton = LunchMESG.Show()			If (aiButton == 0) ;  Glazed Turkey Sandwich			ElseIf (aiButton == 1) ; Grilled Ham Sandwich			ElseIf (aiButton == 2) ; Shredded Pony Sandwich			EndIf		ElseIf (aiButton == 2) ; Dinner			aiButton = DinnerMESG.Show()			If (aiButton == 0) ; Filet Mignon			ElseIf (aiButton == 1) ; Pony Fajitas			ElseIf (aiButton == 2) ; Lobster			EndIf		Else  ; the fourth "that's all, we're done now option"			abMenu = False ; End the function		EndIf	EndWhileEndFunction
Of course that assumes you quit on a fourth option on that that top level.
User avatar
pinar
 
Posts: 3453
Joined: Thu Apr 19, 2007 1:35 pm

Post » Thu Jun 21, 2012 10:34 pm

I strongly suspect that your code can be reduced to this without any problems.
Well, kinda, but that necessitates that fourth button which isn't always appropriate as the main menu would show more than once, allowing breakfast, lunch, and dinner to be ordered. Particularly when you get into multilevel, looping menus, the -1 check becomes a necessity. I usually add it from the onset as menus tend to grow...
User avatar
Oscar Vazquez
 
Posts: 3418
Joined: Sun Sep 30, 2007 12:08 pm


Return to V - Skyrim