More AliasForceGreet Oddness

Post » Wed Jun 20, 2012 2:37 pm

OK. I'm trying to get the player captured by a random bad guy.

I can intercept bleedout and run my capture quest. And then I run a subquest to ask the player to disarm.

The Subquest has an alias for a bad guy. I've been having trouble filling it, so I pared the conditions right down to HasKeyword ActorTypeNPC. The bad guy is supposed to say "yield or die" and present the player with a choice. It's not working. A MessageBox I put in the ForceGreet package's startup script fragment suggest the package is being executed, but no one says anything.

This is my trace from the log.

[03/16/2012 - 06:31:15AM] [SSG_PlayerScript ]: setting essential to TRUE[03/16/2012 - 06:31:39AM] starting capture quest[SSG_PlayerCaptureQuest ][03/16/2012 - 06:31:40AM] SSG_PlayerCapture: kicking off[03/16/2012 - 06:31:41AM] Disarm RQ: [ReferenceAlias ][03/16/2012 - 06:31:41AM] oref: [masterambushscript < (020018A4)>][03/16/2012 - 06:31:41AM] Package Eval on: [masterambushscript < (020018A4)>]

Is that really trying to execute the package on a script? Rather than the actor itself? Or is that just down to how pap stores these things internally?

[edit]

The other thing that could be messing things up is that these are leveled list actors rather than placed references. Although I'd have thought placing a package on an alias would still have worked. And of course it's already got an Ambush package running. That's largely because I chose the wrong leveled list marker, but again I would have thought the alias would override that.

Also I want this to work in the general case in any event.

Ideas welcome :)
User avatar
Emily Martell
 
Posts: 3469
Joined: Sun Dec 03, 2006 7:41 am

Post » Wed Jun 20, 2012 1:15 pm

One thing I can suggest is to ensure that in your package you have a Topic selected, and that the topic's conditions are valid so that the NPC can actually say them. Is this a custom NPC, or are you appending your own dialogue to, say, a generic bandit?
User avatar
stevie critchley
 
Posts: 3404
Joined: Sat Oct 28, 2006 4:36 pm

Post » Wed Jun 20, 2012 7:23 am

One thing I can suggest is to ensure that in your package you have a Topic selected, and that the topic's conditions are valid so that the NPC can actually say them. Is this a custom NPC, or are you appending your own dialogue to, say, a generic bandit?

It's a generic bandit.

The topic should be set. I had the same package working for an actor in a test cell.

I'm tending more and more towards the conclusion that it's the generic or levelled nature of the target that's causing the issue. Unfortunately I can't test that for another nine hours or so.

[edit]

The other thing that could be causing an issue is that this is launching from the Story Manager, mainly because I want to be able to select based on the type of assailant, and to randomise responses within those categories. But it's one more variable I suppose.
User avatar
Ymani Hood
 
Posts: 3514
Joined: Fri Oct 26, 2007 3:22 am

Post » Wed Jun 20, 2012 1:23 pm

Just as an update: It looks like this has been a dirty save problem.

The clue lay in the fact that, (the first time I tried it), the alias reported as non-null, but any attempt to get the underlying reference evaluated to null at runtime. When I slackened the criteria, it did pick something up, but it wasn't anything that had the keyword.

With a clean save and moving back to my test cell, I can confirm that this worked for radiant quests, and for actors from levelled lists.

So unless it all goes pear-shaped when I put the code back in the wild - problem solved. Hopefully.
User avatar
Krystal Wilson
 
Posts: 3450
Joined: Wed Jan 17, 2007 9:40 am

Post » Wed Jun 20, 2012 4:08 am

OK. Dirty save confirmed. Also, keywords set on race do not bubble up to the actor, so HasKeyword(ActorTypeNPC) doesn't work and I can't for the life of me think why I believed it might.

With those problems sorted out it seems to work, although I still have to iron out some wrinkles with combat.
User avatar
M!KkI
 
Posts: 3401
Joined: Sun Jul 16, 2006 7:50 am

Post » Wed Jun 20, 2012 2:56 am

... and then I added a condition so the package only worked on one quest stage, and it broke.

So I took the condition back off and it stayed broke.

This thing is fickle beyond belief.
User avatar
Brad Johnson
 
Posts: 3361
Joined: Thu May 24, 2007 7:19 pm

Post » Wed Jun 20, 2012 11:39 am

I'm going to keep going with this thing until I either understand how it works, or until I understand how it is broken well enough to report a bug.

Latest attempt:

I've noticed that the package starts, but the travel portion of it never completes, and so the force-greet never does. Probably this is because the bandit is already inside the target area. If I back off outside it and then close again, I can often trigger the package. I've also been worrying about what variables are shared between packages and how editing one package may affect another. Or another use of the same package. So:
  • Edited my ESP with TESVSnip and cleaned it. Removed a few unintentional edits to vanilla packages.
  • Created my own package template using just ForceGreet
  • Created a package based on that template and set a condition for quest stage 0
  • assigned it to the bandit alias
  • worked first time
Problem now, of course, is what do I do if the nearest assailant is some distance away? I want them to close the gap. Could I put a travel package after the ForceGreet, maybe? If they weren't close enough to trigger the talk, then they move closer.
User avatar
Taylrea Teodor
 
Posts: 3378
Joined: Sat Nov 18, 2006 12:20 am

Post » Wed Jun 20, 2012 6:05 am

I'm going to keep going with this thing until I either understand how it works, or until I understand how it is broken well enough to report a bug.

You don't say, but are you doing this as a scene?
User avatar
Vickey Martinez
 
Posts: 3455
Joined: Thu Apr 19, 2007 5:58 am

Post » Wed Jun 20, 2012 4:27 am

You don't say, but are you doing this as a scene?

Oops, sorry about that. I'm not. I'm using a quest with packages (mainly forcegreet and keep an eye on) tied to various stages. Can you skip over phases in scenes. Because if you can, this might work better that way.

My first attempt was a scene, and that didn't work - mainly because I didn't understand the forcegreet, I think.

Latest problem. The opening forcegreet fires, but for some reason the topic doesn't close after the player makes a selection. I have to tab out of it.


It's probably not much help, but here's the code for the script that drives it all.

Spoiler

Scriptname SSG_PlayerCaptureDisarm_RQ_Script extends Quest  ConditionalImport UtilityImport DebugFaction Property SlaveFactionRef  Auto  Quest Property ParentQ  Auto  Int stage_death_chosen	= 10;Int	stage_submitted		= 20;Int	stage_disarming1	= 30;Int	stage_disarming2	= 40;int	stage_disarming3	= 50;int	stage_disarmed		= 60;int stage_too_late		= 70;Function set_essential(Bool bval)	Trace(self + ": setting essential to " + bval);	Actor a = Game.GetPlayer()	ActorBase ab = a.GetActorBase();	ab.SetEssential(bval);EndFunctionFunction set_bulletproof(Bool bval)	Trace(self + ": setting bulletproof to " + bval);	Actor a = Game.GetPlayer()	ActorBase ab = a.GetActorBase();	ab.SetInvulnerable(bval);EndFunctionfunction stage_00(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script: 00 begins")	Actor p = Game.GetPlayer()	Actor b = bandit_ref.GetActorReference();		;	; make sure we have our actors	;	if p == None		MessageBox("Error: Can't get player in " + self)		Return	EndIf	if b == None		MessageBox("Error: Can't get 'bandit' in " + self)		Return	EndIf	set_essential(False)	;	; stop the combat, add player to a non-hostile faction,	; stop the combat alarm to stop it starting back up	; then stop the combat again in case it already started back up	;	p.StopCombat();	p.SetFactionRank(SlaveFactionRef, 0);	p.StopCombatAlarm();	p.StopCombat();		secs = GetCurrentRealTime();	Trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script: 00 done")		;	; make sure our aggressor knows that his packages have changed	;	b.EvaluatePackage()EndFunction;; call this if the player chooses death over dishonour;function stage_10(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  10 begins")	Actor p = Game.GetPlayer()	Actor b = bandit_ref.GetActorReference();		set_bulletproof(false);	b.EvaluatePackage()		;	; make sure we have our actors	;	if p == None		MessageBox("Error: Can't get player in " + self)		Return	EndIf	if b == None		MessageBox("Error: Can't get 'bandit' in " + self)		Return	EndIf		;	; make the player killable, remove from neutral faction	; restart the hostilities	;	set_essential(False)	p.RemoveFromFaction(SlaveFactionRef);	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  start combat with " + B)	b.StartCombat(p);		;	; set state to CoolingDown	;	GoToState("Cooldown")EndFunction;; I seem to only have one state left, which makes this a bit redundant; then again, things might change again, so I'm leaving it;State Cooldown	;	; when we start cooldown, set a timer for between 2 and 5 minutes	;	Event OnBeginState()		float secs = GetCurrentRealTime();		float delay = 120.0 + RandomFloat(0, 180)		RegisterForSingleUpdate(delay)		trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  restoring essential in " + delay)	EndEvent		;	; when we get that update, restore the player protection	; and then stop the quest	;	Event OnUpdate()		set_essential(True);		Stop()	EndEventEndState;; need a default handler;event OnUpdate()	; nothingEndEvent;; call this if the player begs for mercy;function stage_20(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  20 begins")	Actor p = Game.GetPlayer()	Actor b = bandit_ref.GetActorReference();		;	; make sure we have our actors	;	if p == None		MessageBox("Error: Can't get player in " + self)		Return	EndIf	if b == None		MessageBox("Error: Can't get 'bandit' in " + self)		Return	EndIf		set_bulletproof(false);	b.EvaluatePackage()	SetStage(stage_disarming1)EndFunction;; this stage is the player's first chance to disarm; we wait 5 secs and then check to see.;; Probably that duration needs to go down for more experienced slavers;; Actually, this is just a timing stage and only exists so I change what the bandit's package; In some ways this would work so much better as a scene;function stage_30(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  30 begins")	;	; force eval	;	Actor b = bandit_ref.GetActorReference();	b.EvaluatePackage();		;	; OK. The player has five seconds to empty his or her hands	;	Wait(5);	;	; check to see if they disarmed. hands must be empty, and fists unclenched	;	if check_disarm_status() == 0		SetStage(stage_disarmed)		Return	EndIf		;	; Go to stage 40 now where we can check to see if they complied	;	SetStage(stage_disarming2)EndFunction	;; check to see if the player has disarmed. If so, we can go to stage 60 without further ado; if not, the bandit gets to remind them, and we get some more time.;function stage_40(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  40 begins")		;	; force re-eval	;	Actor b = bandit_ref.GetActorReference();	b.EvaluatePackage();		;	; OK. The player has another five seconds. The bandit will remind	;	Wait(5);	;	; check to see if they disarmed. hands must be empty, and fists unclenched	;	if check_disarm_status() == 0		SetStage(stage_disarmed)		Return	EndIf		;	; no further chances - cut to the chase	;	SetStage(stage_too_late)EndFunction	;; no longer used - may delete;function stage_50(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  40 begins")		;	; force eval	;	Actor b = bandit_ref.GetActorReference();	b.EvaluatePackage();		;	; if we got here it's too late	;	SetStage(stage_too_late)EndFunction	;; Disarmed;function stage_60(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  60 begins")		;	; force re-eval	;	Actor b = bandit_ref.GetActorReference();	b.EvaluatePackage();		ParentQ.SetStage(10)EndFunction	;; It's too late!;function stage_70(ReferenceAlias bandit_ref)	float secs = GetCurrentRealTime();	trace(secs + ": SSG_PlayerCaptureDisarm_RQ_Script:  70 begins")	;	; force re-eval	;	Actor b = bandit_ref.GetActorReference();	b.EvaluatePackage();			;	; turn off immunities, restart combat	;	SetStage(stage_death_chosen)EndFunction	;; we can use these to select variant speech patterns:; "drop the weapons", "get rid of the magic", "hands empty and by your sides, won't tell you again.";int Property spells_ready	= 0 auto Conditionalint Property weapons_ready	= 0 auto Conditionalint Property fists_ready	= 0 auto Conditionalint Property mixed_weapons	= 0 auto Conditionalint Property weapons_drawn	= 0 auto Conditional		; probably not needed, but ...int function check_disarm_status()	Actor p = Game.GetPlayer()	trace("SSG_PlayerCaptureDisarm_RQ_Script: checking for disarm status");		;	; initialise values	;	spells_ready	= 0	weapons_ready	= 0	fists_ready		= 0	weapons_drawn	= 0		;	; check for weapons	;	if p.GetEquippedWeapon(0) != None		weapons_ready += 1	EndIf	if p.GetEquippedWeapon(1) != None		weapons_ready += 1	EndIf	trace("weapons equipped: " + weapons_ready);	;	; we don't want a ready weapon. We'll forgive spells unless they're "drawn" and ready to cast	;	if !p.IsWeaponDrawn()		return spells_ready + weapons_ready	EndIf		;	; check for spells	;	if p.GetEquippedSpell(0) != None		spells_ready += 1	EndIf	If p.GetEquippedSpell(1) != None		spells_ready += 1	EndIf	trace("spells equipped: " + spells_ready);		if spells_ready == 1 || weapons_ready == 1		mixed_weapons = 1	EndIf			If spells_ready + weapons_ready == 2		Return 2	EndIf		;	; we have at least one fist raised.	; two if no mixed weapons	;	fists_ready == 2 - mixed_weapons	trace("fists equipped: " + fists_ready);	;	; we return the number of weapons ready.  could be one, not sure how shields are counted	;	return spells_ready + weapons_ready + fists_readyEndFunction
User avatar
Jennie Skeletons
 
Posts: 3452
Joined: Wed Jun 21, 2006 8:21 am

Post » Wed Jun 20, 2012 5:35 am

Oops, sorry about that. I'm not. I'm using a quest with packages (mainly forcegreet and keep an eye on) tied to various stages. Can you skip over phases in scenes. Because if you can, this might work better that way.

I'd recommend you at least try moving the force greet into a scene and see if, now that you understand it better, it works for you. If it does then you can move the other phases of the scene in one by one and see how it goes. I'm pretty sure you will be able to script those scenes however you need them to play out and there are timers you can add to the phases. The thing about the scene is it seems to manage packages more reliably than scripting has ever managed to execute packages in my experience with the Gecks and force greets have always been a pita.
User avatar
Bambi
 
Posts: 3380
Joined: Tue Jan 30, 2007 1:20 pm

Post » Wed Jun 20, 2012 6:31 am

Do you launch the scene from using scene_property.Start() or do you have the scene start with the quest?

I'm getting an error saying the scene can't start because the quest isn't running. Which is a bit odd, considering that it's only launched from the quest.

[edit]

If I launch by ticking "begin on quest start" then it launches all right, and I get my dialog. But the damn dialogue refuses to go away at the end.

I want the Bandit to have the first and last word in the discussion. So:

Bandit: Yield or Die
PC : I Yield
Bandit : Then drop your weapons.

I have the "drop your weapons" line flagged as a goodbye, but the dialog UI persists
User avatar
Sophie Morrell
 
Posts: 3364
Joined: Sat Aug 12, 2006 11:13 am

Post » Wed Jun 20, 2012 11:50 am

Do you launch the scene from using scene_property.Start() or do you have the scene start with the quest?

I'm getting an error saying the scene can't start because the quest isn't running. Which is a bit odd, considering that it's only launched from the quest.

[edit]

If I launch by ticking "begin on quest start" then it launches all right, and I get my dialog. But the damn dialogue refuses to go away at the end.

I want the Bandit to have the first and last word in the discussion. So:

Bandit: Yield or Die
PC : I Yield
Bandit : Then drop your weapons.

I have the "drop your weapons" line flagged as a goodbye, but the dialog UI persists

Hmm. My force greet is neither. I set up the package to trigger based on quest stages and I trigger the quest start from another quest. The other scene I have going is triggered in a script with scene.start().

For getting the last dialogue of the phase to close out what do you have as your condition for that phase to complete? Do you have it checked to end when all actions are complete or when conditions are met? Either of those could be made to work with dialogue I should imagine by setting quest stages in the dialouge if you have to or just by setting it to complete when all actions are complete (I would expect dialogue to be complete once the line is delivered, but if it isn't you could always setstage() in the dialouge and then use that as a condition to complete the phase).
User avatar
Ezekiel Macallister
 
Posts: 3493
Joined: Fri Jun 22, 2007 12:08 pm

Post » Wed Jun 20, 2012 11:09 am

Hmm. My force greet is neither. I set up the package to trigger based on quest stages and I trigger the quest start from another quest. The other scene I have going is triggered in a script with scene.start().

mmm.. I've been trying to start the scene in stage 0 of the quest, once some initialisation has been done.

Maybe the quest is still starting up, and isn't yet visible as started to the scene. If I flag the scene as "starts when quest starts" then it behaves as expected. (and since I'm using a new quest in a new esp to test this, I'm not getting the blasted hanging dialogue problem either.

So maybe if I do my initialisation in stage 0, and the goto stage 5 and start the scene from there. I could really do with getting that initialisation in first.

I'd try using the scene's startup fragmen, but the CK crashes when I try that.

For getting the last dialogue of the phase to close out what do you have as your condition for that phase to complete? Do you have it checked to end when all actions are complete or when conditions are met? Either of those could be made to work with dialogue I should imagine by setting quest stages in the dialouge if you have to or just by setting it to complete when all actions are complete (I would expect dialogue to be complete once the line is delivered, but if it isn't you could always setstage() in the dialouge and then use that as a condition to complete the phase).
User avatar
Harry Leon
 
Posts: 3381
Joined: Tue Jun 12, 2007 3:53 am


Return to V - Skyrim