Jump to content
Xyx

Large number of BG2 script findings

Recommended Posts

i always use displaystringhead for debugging (hotkeys are not reliable enough).

I always use DisplayStringHead() when debugging to see which response gets executed. What do you use the hotkeys for?

 

You will find that you can easily ditch your attacker (by another nearer pc), if it is using AttackReevaluate.

I've seen scripts attack and kill different targets over the course of several turns and still refuse to cast a spell in between. I'm not concerned about target fixation (there's usually little need for a party member to stop attacking a certain monster before it is dead), but I do need my summoned critters to use all their spells in between attacks.

Share this post


Link to post
i always use displaystringhead for debugging (hotkeys are not reliable enough).

I always use DisplayStringHead() when debugging to see which response gets executed. What do you use the hotkeys for?

 

You will find that you can easily ditch your attacker (by another nearer pc), if it is using AttackReevaluate.

I've seen scripts attack and kill different targets over the course of several turns and still refuse to cast a spell in between. I'm not concerned about target fixation (there's usually little need for a party member to stop attacking a certain monster before it is dead), but I do need my summoned critters to use all their spells in between attacks.

Maybe I wasn't clear.

I use DisplayStringHead AND HotKeys, because HotKeys alone are unreliable. But DisplayStringHead removes modals.

See the example.

As for the second concern, i didn't yet experiment with "cast AND attack". But I know it is possible.

I just addressed the false belief that Attack and AttackReevaluate are the same.

 

Also, a single attack action can make your actor attack several opponents with/without killing.

See this snippet (from memory):

 

If

hotkey(b)

then

response #100

attack( [pc])

end

 

In this script block, the attack action is executed only once (but since it is a blocking action, it continues until a new action is executed).

As i learned from someone, object ids are reevaluated every turn, even in an active action.

 

[note]

hotkey (a) is usable, but tricky, because it toggles the party AI. (Every second usage works)

Edited by Avenger

Share this post


Link to post

I think your compound states work/don't work not because of the specific numbers, but because of the targeting.

Share this post


Link to post
I could find no difference between Attack() and AttackReevaluate(somevalue), but that is no proof that there is no difference.
IIRC, reevaluate allows a change in target that typically would not be possible without stopping the action and restarting it.

 

If you have Attack(NearestEnemyOf()), the script runner will attack that object until it dies or until the action times out (or until it's given something else to do).

 

If you have AttackReevaluate(NearestEnemyOf(),90), the script runner will attack that object, every 6 seconds determining if the object has changed (if a different enemy comes closer during that time, you switch to it and attack it).

 

This is done so that it's not constantly switching blocks (otherwise you'd have to stop attacking and check your targets all the time). Neither Attack() nor AttackReevaluate() return until the target becomes invalid, meaning ActionListEmpty() not returning true in the example above is the expected behavior.

 

All of the attack actions are interruptible (if the engine finds something else for the object to do, then it will do it).

 

At least, that's what I seem to remember of it.

Edited by devSin

Share this post


Link to post
I just addressed the false belief that Attack and AttackReevaluate are the same.

I get that they're technically not the same... but what is the noticeable difference?

 

object ids are reevaluated every turn, even in an active action.

OK, that's interesting. That would explain some of this mess.

 

I think your compound states work/don't work not because of the specific numbers, but because of the targeting.

If you are referring to the STATE_DISABLED example in my comments... I could get other states (compound or otherwise) to work, but not this one, even if my "targeting" was just See(NearestEnemyOf()).

 

If you have AttackReevaluate(NearestEnemyOf(),90), the script runner will attack that object, every 6 seconds determining if the object has changed (if a different enemy comes closer during that time, you switch to it and attack it).

How does this interact with the "object ids are reevaluated every turn" that Avenger mentioned?

 

All of the attack actions are interruptible (if the engine finds something else for the object to do, then it will do it).

...except that, in many cases, no interruption happens even if ActionListEmpty() isn't used anywhere.

 

I scripted a bunch of summoned critters (Nishruu, Efreeti, Planetar, etcetera) to cast one of their spells every 6 seconds and attack in between. They all use the same principle; a 6-second timer that forbids spellcasting while it runs, with an Attack() order at the end of the script. Some of them worked fine, others got hung up on attacking. I then switched to AttackOneRound(), and they all worked fine. I then added ActionListEmpty() to keep them from interrupting manual player commands, and some of them got hung up on attacking again. I now use a mixture, with some of them checking ActionListEmpty() in every block and others only in the block containing the attack order. This means that some of them are properly obedient, and others can be a bit unruly (they will occasionally abort the player's orders).

Share this post


Link to post
I just addressed the false belief that Attack and AttackReevaluate are the same.

I get that they're technically not the same... but what is the noticeable difference?

Did you test that script I posted? AttackReevaluate allows for reevaluating the target (even if it isn't in the [x.y.z] form.

So, a single AttackReevaluate can switch targets every given seconds AI cycles.

Edited by Avenger

Share this post


Link to post

I'll take your word for it (since I wouldn't want my targets reevaluated anyway)... but I was under the impression that we just established that Attack() already did something of the sort, in which case the difference would be academic at best.

Share this post


Link to post

Some of these notes are already in the IESDP, others are self-evident, others don't belong in the IESDP (in my opinion at least). However, I have added a number of these notes to various places within the IESDP - thanks :)

 

 

EquipItem()

- Perhaps it would move an item to an appropriate slot, but it will not switch weapons.

 

SelectWeaponAbility(SLOT_WEAPON0,1):

- Haven't seen this produce any results.

 

Can anyone confirm or deny these?

Share this post


Link to post

Can anyone confirm or deny these?

 

SelectWeaponAbility() works fine. I use it in RR/aTweaks to make ranged characters switch between different ammo types. Sample code:

 

IF
Global("RR#Heal","LOCALS",0)
HasItem("AROW07",Myself) // Arrows of Dispelling
DifficultyGT(EASY)
See(Player1)
!HasItemEquiped("SHLD24",LastSeenBy(Myself)) // Reflection Shield +1
!CheckStatGT(LastSeenBy(Myself),0,HELD)
!CheckStat(LastSeenBy(Myself),1,CLERIC_PHYSICAL_MIRROR)
!CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_MAGIC_WEAPONS)  // protected from +1 weapons and above
!CheckStatLT(LastSeenBy(Myself),-10,ACMISSILEMOD)
!StateCheck(LastSeenBy(Myself),STATE_DISABLED)
CheckStatGT(LastSeenBy(Myself),0,TRUE_SIGHT)
THEN
RESPONSE #100
	EquipRanged()
	SelectWeaponAbility(SLOT_AMMO2,0)
	AttackReevaluate(LastSeenBy(Myself),15)

IF
Global("RR#Heal","LOCALS",0)
HasItem("AROW04",Myself) // Acid Arrows
See([PC.0.0.CLERIC_ALL])
CheckStatLT(LastSeenBy(Myself),100,RESISTACID)
!CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_MAGIC_WEAPONS)  // protected from +1 weapons and above
!CheckStatLT(LastSeenBy(Myself),-10,ACMISSILEMOD)
!CheckStat(LastSeenBy(Myself),1,CLERIC_PHYSICAL_MIRROR)
!HasItemEquiped("SHLD24",LastSeenBy(Myself)) // Reflection Shield +1
THEN
RESPONSE #100
	EquipRanged()
	SelectWeaponAbility(SLOT_AMMO1,0)
	AttackReevaluate(LastSeenBy(Myself),15)
END
END

 

For reference, this has been used for years in RR's Chosen of Cyric encounter and can be easily verified in-game. Not sure why Xyx couldn't get it to work.

Share this post


Link to post
Guest
You are commenting as a guest. If you have an account, please sign in.
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.


×