Ironworks Moderator 
Join Date: June 10, 2001
Location: Pasir Ris, Singapore
Age: 42
Posts: 11,063
|
First off, I would like to give kudos to SimDing0 for his "Complete Scripting Guide". The following codeblocks below were inspired by his "False Conditions" method. I was wondering whether veteran coders can go through my codeblocks and see whether it can be further streamlined.
One problem with only having one codeblock to handle priority targetting is that the conditions can vary so wildly, making it impossible to make one without flaws. The most glaring one being overlooking more suitable targets just because they are lower on the list.
It was problematic though, to create a priority targetting system for each spell/attack without severely bloating the .BS file. I think I may have found a solution though.
Under my system, only 3 codeblocks are needed to enable priority targetting from the NearestEnemy to the TenthNearestEnemy. The following example below demostrates the handling of two spells. Melf's Acid Arrow and Magic Missile. Note that the numbers come from IWD, so it may not match up with the more familiar BG2 ones.
Note also that for brevity sake, I have removed some conditions and codeblocks for easier viewing and to place more emphasise on how the priority targetting works. This example is just about the bare minimum needed for the thing to work properly.
I have tested it a bit so far, and there seems to be no problems yet.
code:
// [*Melf's Acid Arrow*]
IF
See([ENEMY])
HaveSpell(2211)
!GlobalTimerNotExpired("MAArrow","LOCALS")
OR(3)
!See(NearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SecondNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(ThirdNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(FourthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(FifthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SixthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SeventhNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(EighthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(NinthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(TenthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
THEN
RESPONSE #100
SetGlobal("S2211","LOCALS",1)
Continue()
END
IF
!Global("S2211","LOCALS",1)
THEN
RESPONSE #100
SetGlobalTimer("MAArrow","LOCALS",18)
Spell(LastSeenBy(Myself),2211)
END
IF
Global("S2211","LOCALS",1)
THEN
RESPONSE #100
SetGlobal("S2211","LOCALS",0)
Continue()
END
// [*Magic Missile*]
IF
See([ENEMY])
HaveSpell(2112)
!GlobalTimerNotExpired("MAArrow","LOCALS")
OR(3)
!See(NearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(SecondNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(ThirdNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(FourthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(FifthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(SixthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(SeventhNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(EighthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(NinthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
OR(3)
!See(TenthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTMAGIC)
THEN
RESPONSE #100
SetGlobal("S2211","LOCALS",1)
Continue()
END
IF
!Global("S2112","LOCALS",1)
THEN
RESPONSE #100
Spell(LastSeenBy(Myself),2112)
END
IF
Global("S2112","LOCALS",1)
THEN
RESPONSE #100
SetGlobal("S2112","LOCALS",0)
Continue()
END
// [*Twiddle Thumbs*]
IF
ActionListEmpty()
THEN
RESPONSE #100
DisplayString(Myself,3678)
END [/QUOTE]Now I will go through each codeblock in detail.
code:
// [*Melf's Acid Arrow*]
IF
See([ENEMY])
HaveSpell(2211)
!GlobalTimerNotExpired("MAArrow","LOCALS")
OR(3)
!See(NearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SecondNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(ThirdNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(FourthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(FifthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SixthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(SeventhNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(EighthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(NinthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
OR(3)
!See(TenthNearestEnemyOf(Myself))
CheckStat(LastSeenBy(Myself),1,MINORGLOBE)
CheckStatGT(LastSeenBy(Myself),40,RESISTACID)
THEN
RESPONSE #100
SetGlobal("S2211","LOCALS",1)
Continue()
END [/QUOTE]This is the heart of the priority targetting process. It will start to execute when an enemy is seen.
First it checks that the character has the spell memorised.
The Global Timer ensures that Melf's Acid Arrow is only casted every three rounds. The setting of the Global Timer is done by the next codeblock.
The OR() statements are where the False Conditions come into play. When the character sees the NearestEnemy, LastSeenBy() is set and the first line in the OR() sequence is set as false.
When all the lines in the OR() statement are false, the target is a Valid one and the codeblock will return false, making it move on to the next codeblock where the spell will be cast on the LastSeenBy() target which has already been recognised as being a Valid one.
When one of the lines in the OR() statement is true, the target is considered Invalid and it will move on to the next OR() statement. This proceeds so on and so forth.
If ALL the OR() statements are true, meaning none of the nearest ten targets are valid. The codeblock will return true and execute the RESPONSE #100 statements.
In the RESPONSE #100 statements, the Global variable, "S2211", will be set to 1 and Continue() will cause the script to move on to the next codeblock, where it will be informed of the invalidity of the targets.
code:
IF
!Global("S2211","LOCALS",1)
THEN
RESPONSE #100
SetGlobalTimer("MAArrow","LOCALS",18)
Spell(LastSeenBy(Myself),2211)
END [/QUOTE]If "S2211" is 1, the codeblock returns false and moves on to the next codeblock.
If 0, the codeblock is executed, the Global Timer is set, and the spell is casted on the valid target.
code:
IF
Global("S2211","LOCALS",1)
THEN
RESPONSE #100
SetGlobal("S2211","LOCALS",0)
Continue()
END [/QUOTE]This codeblock serves to reset the "S2211" variable when the initial round of targetting reveals no valid targets. If executed, it will move on to the next set of codeblocks since there were no valid targets for Melf's Acid Arrow.
By the by, all the targetting conditions are in the priority targetting codeblock because it will prevent the flaw of accidentally looking over more suitable targets which are lower on the list.
code:
// [*Twiddle Thumbs*]
IF
ActionListEmpty()
THEN
RESPONSE #100
DisplayString(Myself,3678)
END [/QUOTE]Unless you ensure that the last codeblock has no Continue() line, this will make sure that your .BS file will not hang.
[ 01-21-2004, 05:56 AM: Message edited by: Dundee Slaytern ]
|