Jump to content
DavidW

Coding scripts in SSL: some lessons

Recommended Posts

Posted (edited)
On 7/29/2019 at 4:33 PM, DavidW said:

Yes.

Is there any particular reason for that? In other words, how would you automate something like this

Spoiler

IF
	!StateCheck(SixthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(SixthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(FifthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(FifthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(FourthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(FourthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(ThirdNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(ThirdNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(SecondNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(SecondNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(NearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(NearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(SixthNearestEnemyOf(Myself),STATE_BLUR)
	See(SixthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(FifthNearestEnemyOf(Myself),STATE_BLUR)
	See(FifthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(FourthNearestEnemyOf(Myself),STATE_BLUR)
	See(FourthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(ThirdNearestEnemyOf(Myself),STATE_BLUR)
	See(ThirdNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(SecondNearestEnemyOf(Myself),STATE_BLUR)
	See(SecondNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(NearestEnemyOf(Myself),STATE_BLUR)
	See(NearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	// Possibly something else...
	See(LastSeenBy(Myself))
THEN
	RESPONSE #100
		Attack(LastSeenBy(Myself))
END

 

I mean, 'Combine()' is really useful to generate False() blocks, but I cannot use it in this case since there are different triggers.... Actually, I can use it but then I would generate two attack blocks (one for STATE_MIRRORIMAGE and another one for STATE_BLUR), which is kinda bad.....

Do you have any suggestions? Is defining two separate ACTIONs and manually create the False() blocks (i.e., without using 'Combine()) the only solution? That is:

Spoiler

TARGET=EnemiesInReverseOrder
	SixthNearestEnemyOf(Myself)
	FifthNearestEnemyOf(Myself)
	FourthNearestEnemyOf(Myself)
	ThirdNearestEnemyOf(Myself)
	SecondNearestEnemyOf(Myself)
	NearestEnemyOf(Myself)

BEGIN_ACTION_DEFINITION
	Name(TargetMI)
	TRIGGER
		!StateCheck(scstarget,STATE_MIRRORIMAGE)
	ACTION
		RESPONSE #scsprob1
			NoAction()
END

BEGIN_ACTION_DEFINITION
	Name(TargetBlur)
	TRIGGER
		StateCheck(scstarget,STATE_BLUR)
	ACTION
		RESPONSE #scsprob1
			NoAction()
END

IF TRIGGER
	TargetBlock(EnemiesInReverseOrder)
	False()
THEN DO
	Action(TargetMI)
	Action(TargetBlur)
END

 

 

Edited by Luke

Share this post


Link to post

I would do:

IF TRIGGER 

       TargetBlock(EnemiesInReverseOrder)

       StateCheck(scstarget,STATE_MIRROR_IMAGE)

      False()

THEN DO

    Action(Literal)

END

IF TRIGGER 

       TargetBlock(EnemiesInReverseOrder)

       StateCheck(scstarget,STATE_BLUR)

      False()

THEN DO

    Action(Literal)

END

 

 

Share this post


Link to post
Posted (edited)

@DavidW

No, your SSL code generates the following BAF file, which is not what I was looking for...

Spoiler

IF
	See(SixthNearestEnemyOf(Myself))
	!StateCheck(SixthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(FifthNearestEnemyOf(Myself))
	!StateCheck(FifthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(FourthNearestEnemyOf(Myself))
	!StateCheck(FourthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(ThirdNearestEnemyOf(Myself))
	!StateCheck(ThirdNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(SecondNearestEnemyOf(Myself))
	!StateCheck(SecondNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(NearestEnemyOf(Myself))
	!StateCheck(NearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	False()
THEN
	RESPONSE #100
END

IF
	See(SixthNearestEnemyOf(Myself))
	StateCheck(SixthNearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

IF
	See(FifthNearestEnemyOf(Myself))
	StateCheck(FifthNearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

IF
	See(FourthNearestEnemyOf(Myself))
	StateCheck(FourthNearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

IF
	See(ThirdNearestEnemyOf(Myself))
	StateCheck(ThirdNearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

IF
	See(SecondNearestEnemyOf(Myself))
	StateCheck(SecondNearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

IF
	See(NearestEnemyOf(Myself))
	StateCheck(NearestEnemyOf(Myself),STATE_BLUR)
	False()
THEN
	RESPONSE #100
END

 

I need those See() triggers to be second last, immediately before False() – just like Combine() would do.

Is there a way to achieve that? Moreover, it's still not clear for me what 'Action(Literal)' is supposed to do.....

Edited by Luke

Share this post


Link to post
6 minutes ago, DavidW said:

Oh, I see. Don’t know, then.

Guess this is the problem: why does TargetBlock() always come before all the other triggers defined in the IF TRIGGER part? If that was not the case, then your code would work...

Share this post


Link to post

No very deep reason. (But don't look for it to change: I touch the underlying code in SSL as rarely as I can possibly manage.) Ultimately SSL's development cycle is that features get added to it as and when I need them for some SCS purpose. The use case you're considering just isn't one I've particularly needed.

Share this post


Link to post
Posted (edited)

@DavidW

I see. To sum up:

  1. I could use Combine() => this will put the See() triggers in the right position but will also generate multiple attack blocks (useless, but not wrong).
  2. I could define multiple ACTIONs and manually put the False() triggers in the IF TRIGGER part => this won't generate multiple attack blocks but it's not very flexible (since I need to define lots of ACTIONs instead of using TriggerBlock()....).

 

Spoiler

BEGIN_ACTION_DEFINITION
	Name(TargetOption1)
	TRIGGER
  		WeaponEffectiveVs(scstarget,MAINHAND)
		WeaponCanDamage(scstarget,MAINHAND)
		!StateCheck(scstarget,STATE_PANIC)
		CheckStatLT(scstarget,1,STONESKINS)
		!StateCheck(scstarget,STATE_CONFUSED)
	ACTION
		RESPONSE #scsprob1
			NoAction()
END

BEGIN_ACTION_DEFINITION
	Name(AttackOneRound)
	TRIGGER
		!StateCheck(scstarget,STATE_REALLY_DEAD)
	ACTION
		RESPONSE #scsprob1
			AttackOneRound(scstarget)
END

//////////////////////////////////////////////////////////////////

IF TRIGGER
	TargetBlock(EnemiesInOrder)
	TriggerBlock(IsWeaponUsable)
	!StateCheck(scstarget,STATE_PANIC)
	CheckStatLT(scstarget,1,STONESKINS)
	!StateCheck(scstarget,STATE_CONFUSED)
THEN DO
	Combine()
	Action(AttackOneRound)
END

// Versus

IF TRIGGER
	TargetBlock(EnemiesInReverseOrder)
	False()
THEN DO
	Action(TargetOption1)
END

 

 

Alternatively: how much is difficult to define a "Combine()" command that does not generate a "LastSeenBy(Myself)" block? That will solve my issue 🙂

Edited by Luke

Share this post


Link to post
Posted (edited)

More questions.

Could you provide additional details about Action(Literal)? Let's consider your example:

Spoiler

IF TRIGGER
	!See(NearestEnemyOf(Myself))
	TargetBlock(PlayersInRandomOrder)
	!StateCheck(scstarget,STATE_INVISIBLE)
THEN DO
	Action(Literal)
	MoveToObject(scstarget)
END
 
// Versus

IF TRIGGER
	!See(NearestEnemyOf(Myself))
	TargetBlock(PlayersInRandomOrder)
	!StateCheck(scstarget,STATE_INVISIBLE)
THEN DO
	MoveToObject(scstarget)
END

 

The aforementioned SSL blocks generate the same BAF file, namely:

Spoiler

IF
	See(Player4)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player4,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player4)
END

IF
	See(Player5)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player5,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player5)
END

IF
	See(Player6)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player6,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player6)
END

IF
	See(Player3)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player3,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player3)
END

IF
	See(Player2)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player2,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player2)
END

IF
	See(Player1)
	!See(NearestEnemyOf(Myself))
	!StateCheck(Player1,STATE_INVISIBLE)
THEN
	RESPONSE #100
		MoveToObject(Player1)
END

 

 

What am I missing?

Edited by Luke

Share this post


Link to post
6 hours ago, Luke said:

how much is difficult to define a "Combine()" command that does not generate a "LastSeenBy(Myself)" block?

That depends on how good your Perl coding is. The source code for ssl is in stratagems/ssl; I don't mind you modifying it provided you continue to give full credit, and of course you'd need to recompile and distribute the executable if you wanted to hot-compile ssl code at install time. (Though the other examples of SSL mods out there - all by Wisp, I think - do their compiling ahead of time, so that a live copy of ssl doesn't need to be distributed.)

If what you actually meant was a request for *me* to modify SSL to do this: No, sorry. SSL isn't WEIDU: it's not a community resource, it's something I wrote for my own purposes which I'm happy for other people to use, but which I don't support in any stronger way. 

 

Share this post


Link to post
16 hours ago, DavidW said:

Precious little. It's syntactic sugar, basically.

What do you mean exactly? Why is it precious? Unfortunately, 'Action(Literal)' is still pointless for me 😕 ... When exactly should I use it?

Share this post


Link to post
17 hours ago, DavidW said:

That depends on how good your Perl coding is

I see. Well, I don't know Perl but I may look at someday.....

In the meantime, I found out a workaround: I'll stick with "Combine()" and then will delete the additional attack blocks using your function DELETE_SCRIPT_BLOCK: it's not very elegant but it should work.....

Share this post


Link to post
Posted (edited)

OK, I fear I spotted a bug: if you compile the following SSL block

Spoiler

IF TRIGGER
	Target(LastSeenBy(Myself))
THEN DO
	Action(CustomAction)
END

 

the resulting BAF/BCS block won't have the See(LastSeenBy(Myself)) trigger 🤨......

The same holds if you define a custom target for that in your .slb file, i.e.:

Spoiler

TARGET=LastSeen
	LastSeenBy(Myself)

 

 

Edited by Luke

Share this post


Link to post

That's intentional: SSL explicitly avoids adding a See block for LastSeenBy(Myself), because in my use cases it's always redundant.

If you want it for some reason, either put the See() command into your action definition explicitly, or else use %luke_myself_var% or something, and set that variable to LastSeenBy(Myself) in your TP2, so that it gets replaced in the BAF->BCS phase. (IIRC SSL doesn't evaluate WEIDU variables in the SSL->BAF phase.)

Upthread: "Precious little" is an expression, roughly synonymous with "almost nothing". Action(Literal) is just a hardcoded action with no trigger conditions and no actions. Mostly it's syntactic sugar (i.e., language that makes code easier for humans to read but doesn't matter to the compiler); there are one or use cases (if you want to use probabilities in a literal action, notably).

Share this post


Link to post
19 hours ago, DavidW said:

That's intentional: SSL explicitly avoids adding a See block for LastSeenBy(Myself), because in my use cases it's always redundant.

If you want it for some reason, either put the See() command into your action definition explicitly, or else use %luke_myself_var% or something, and set that variable to LastSeenBy(Myself) in your TP2, so that it gets replaced in the BAF->BCS phase. (IIRC SSL doesn't evaluate WEIDU variables in the SSL->BAF phase.)

I see, thanks for clarifying.

Thing is that I need it because of what I told you before, i.e., the automation of something like this

Spoiler

IF
	!StateCheck(SixthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(SixthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(FifthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(FifthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(FourthNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(FourthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(ThirdNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(ThirdNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(SecondNearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(SecondNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(NearestEnemyOf(Myself),STATE_MIRRORIMAGE)
	See(NearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(SixthNearestEnemyOf(Myself),STATE_BLUR)
	See(SixthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(FifthNearestEnemyOf(Myself),STATE_BLUR)
	See(FifthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(FourthNearestEnemyOf(Myself),STATE_BLUR)
	See(FourthNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(ThirdNearestEnemyOf(Myself),STATE_BLUR)
	See(ThirdNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(SecondNearestEnemyOf(Myself),STATE_BLUR)
	See(SecondNearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	StateCheck(NearestEnemyOf(Myself),STATE_BLUR)
	See(NearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

IF
	// Possibly something else...
	See(LastSeenBy(Myself))
THEN
	RESPONSE #100
		Attack(LastSeenBy(Myself))
END

 

Anyway, thank you for the workaround, it works. I opted for the following one:

Spoiler

IF TRIGGER
	Target(LastSeenBy(Myself))
	See(scstarget)
THEN DO
	Action(AttackOneRound)
END

 

 

Share this post


Link to post
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...