Jump to content


Photo

Attack, AttackOneRound, AttackReevaluate


  • Please log in to reply
8 replies to this topic

#1 aigleborgne

aigleborgne
  • Member
  • 95 posts

Posted 07 February 2012 - 02:03 PM

I know this is hot subject but I think AttackOneRound doesn't work properly.

Here is my test case:
- PC : 1 attack per round
- monster : 1 attack per round

=> No other party member to distract my monster
In feedback, I checked to hit rolls.

PC and monster attack each other, they should attack once each round, equally.

Test case 1 : AttackOneRound
Many rounds, I simply see : <monster> attacks <PC> but no hit rolls
It is quite random but sometimes, it can attacks 6 rounds without any hit rolls.
On other hand, my PC makes a hit roll every round.

Test case 2 and 3 : Attack and AttackReevaluate
They are grouped because they produce the same result
Each round, I can see a hit roll for both of them.

Conclusion:
AttackOneRound is not reliable, monster will be a lot weaker than he really is because he won't attack every time he should.
I did the same tests with 2 APR, I still saw no hit rolls with AttackOneRound, but I saw at least one attack per round most of the times (instead of 2).
I guess that, maybe, a creature needs a full round to make its attack or it can be lost depending on how the script is made.

Now, there are other things to consider : cast & attack, or any action that can be done between attacks. AttackOneRound is good for these ones but there is a cost...

Here my test script:
IF
	Global("JA#INIT","LOCALS",0)
THEN
	RESPONSE #100
		SetGlobal("JA#INIT","LOCALS",1)
		SetGlobalTimer("JA#REST","LOCALS",2400)
		SetGlobal("JA#COMBAT","LOCALS",0)
		SetGlobal("JA#DISABLE_SPELLCASTING","LOCALS",0)
END

IF
	Global("JA#INIT","LOCALS",1)
	GlobalTimerExpired("JA#REST","LOCALS")
	!Detect([GOODCUTOFF])
THEN
	RESPONSE #100
		SetGlobal("JA#INIT","LOCALS",0)
		Rest()
		ApplySpellRES("JA#HEAL",Myself) // No such index
END

IF
	!Allegiance(Myself,ENEMY)
	AttackedBy([GOODCUTOFF],DEFAULT)
THEN
	RESPONSE #100
		Enemy()
END

IF
	Global("JA#COMBAT","LOCALS",0)
	Allegiance(Myself,ENEMY)
	See([GOODCUTOFF])
THEN
	RESPONSE #100
		SetGlobal("JA#COMBAT","LOCALS",1)
		Shout(95)
END

IF
	Global("JA#COMBAT","LOCALS",0)
	Heard([EVILCUTOFF.0.SPECTRE],95)
THEN
	RESPONSE #100
		SetGlobal("JA#COMBAT","LOCALS",1)
		Enemy()
END

IF
	Global("JA#COMBAT","LOCALS",0)
	ActionListEmpty()
THEN
	RESPONSE #100
		RandomWalk()
END

IF
	Global("JA#COMBAT","LOCALS",0)
THEN
	RESPONSE #100
		NoAction()
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player6,0,SANCTUARY)
	!StateCheck(Player6,STATE_NOT_VISIBLE)
	HPGT(Player6,0)
	Range(Player6,150)
	RandomNumGT(1000,167)
THEN
	RESPONSE #100
		MoveToObject(Player6)
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player5,0,SANCTUARY)
	!StateCheck(Player5,STATE_NOT_VISIBLE)
	HPGT(Player5,0)
	Range(Player5,150)
	RandomNumGT(1000,200)
THEN
	RESPONSE #100
		MoveToObject(Player5)
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player4,0,SANCTUARY)
	!StateCheck(Player4,STATE_NOT_VISIBLE)
	HPGT(Player4,0)
	Range(Player4,150)
	RandomNumGT(1000,250)
THEN
	RESPONSE #100
		MoveToObject(Player4)
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player3,0,SANCTUARY)
	!StateCheck(Player3,STATE_NOT_VISIBLE)
	HPGT(Player3,0)
	Range(Player3,150)
	RandomNumGT(1000,333)
THEN
	RESPONSE #100
		MoveToObject(Player3)
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player2,0,SANCTUARY)
	!StateCheck(Player2,STATE_NOT_VISIBLE)
	HPGT(Player2,0)
	Range(Player2,150)
	RandomNumGT(1000,500)
THEN
	RESPONSE #100
		MoveToObject(Player2)
END

IF
	!StateCheck(Myself,STATE_BLIND)
	!See([GOODCUTOFF])
	!CheckStatGT(Player1,0,SANCTUARY)
	!StateCheck(Player1,STATE_NOT_VISIBLE)
	HPGT(Player1,0)
	Range(Player1,150)
THEN
	RESPONSE #100
		MoveToObject(Player1)
END

IF
	ActionListEmpty()
	!See([GOODCUTOFF])
THEN
	RESPONSE #100
		RandomWalk()
END

IF
	ActionListEmpty()
	OR(3)
		General(NearestEnemyOf(Myself),WEAPON)
		CheckStatGT(NearestEnemyOf(Myself),0,SANCTUARY)
		!See(NearestEnemyOf(Myself))
	OR(3)
		General(SecondNearestEnemyOf(Myself),WEAPON)
		CheckStatGT(SecondNearestEnemyOf(Myself),0,SANCTUARY)
		!See(SecondNearestEnemyOf(Myself))
	OR(3)
		General(ThirdNearestEnemyOf(Myself),WEAPON)
		CheckStatGT(ThirdNearestEnemyOf(Myself),0,SANCTUARY)
		!See(ThirdNearestEnemyOf(Myself))
	OR(3)
		General(FourthNearestEnemyOf(Myself),WEAPON)
		CheckStatGT(FourthNearestEnemyOf(Myself),0,SANCTUARY)
		!See(FourthNearestEnemyOf(Myself))
	OR(3)
		General(FifthNearestEnemyOf(Myself),WEAPON)
		CheckStatGT(FifthNearestEnemyOf(Myself),0,SANCTUARY)
		!See(FifthNearestEnemyOf(Myself))
	OR(3)
		General(SixthNearestEnemyOf(Myself),WEAPON)
		CheckStatGT(SixthNearestEnemyOf(Myself),0,SANCTUARY)
		!See(SixthNearestEnemyOf(Myself))
THEN
	RESPONSE #100
		Continue()
END

IF
	!General(LastSeenBy(Myself),WEAPON)
	!CheckStatGT(LastSeenBy(Myself),0,SANCTUARY)
	See(LastSeenBy(Myself))
THEN
	RESPONSE #100
		Attack(LastSeenBy(Myself))
END


#2 Sasha Al'Therin

Sasha Al'Therin
  • Modder
  • 615 posts

Posted 07 February 2012 - 03:47 PM

I think AttackOneRound was intended for PC use rather than monsters....

My working mods:
an AI Party Script for BG2 game engine DOWNLOAD LINK ONLY!
Interactive Tweaks for BG series with some IWD support. DOWNLOAD LINK ONLY!
Rest For 8 Hours an IWD mod
-------------------------------------------
My contributions: BG1Fixpack, BG1Tweaks
On Hold: Solestia an NPC for SOA
-------------------------------------------
My website: http://sasha-altheri...s.com/index.htm


#3 aigleborgne

aigleborgne
  • Member
  • 95 posts

Posted 07 February 2012 - 10:08 PM

I will make tests for humans enemies then (fighter, mage, thief...)

I think AttackOneRound was intended for PC use rather than monsters....



#4 Wisp

Wisp
  • Modder
  • 1353 posts

Posted 08 February 2012 - 12:26 AM

I think it is just that Bioware wrote a lot of buggy, barely working code.
I have observed AttackReevaluate bugging out under certain conditions as well.

#5 Azazello

Azazello

    The Anti-Spammer

  • Staff
  • 1912 posts

Posted 08 February 2012 - 03:06 AM

@aigleborgne: you're revisiting your own research, lol - http://forums.pocket...ic,20861.0.html

#6 aigleborgne

aigleborgne
  • Member
  • 95 posts

Posted 08 February 2012 - 04:04 AM

hehe thanks for the link, very old one, totally forgot this post ! :)

I will implement Attack as cirerrek suggested and see if it works well.
I still suspect than AttackOneRound is broken for humans too.

I will post my final report here just for informations.

#7 aigleborgne

aigleborgne
  • Member
  • 95 posts

Posted 09 February 2012 - 11:28 PM

Well, Attack with a timer to interrupt seems to work but, I think that a mage attacks a bit more than AttackOneRound.
This is not a big issue for me as my mages don't attack unless they have no offensive spells or magical weapons.

Biggest issue is Melf meteor, usually, mage will attack until no meteor left, even if it takes 2 or 3 rounds...
This issue happens with AttackOneRound too if I remember correctly.

Finally, Attack seem to not work properly sometimes (missing attacks), but I can't be sure.

To conclude, I will never use AttackOneRound again.
Attack seems to be the best, or eventually AttackReevaluate.

#8 aVENGER

aVENGER
  • Modder
  • 1680 posts

Posted 03 March 2012 - 03:00 AM

I found that using AttackReevaluate() can sometimes get a creature "stuck" in an attack pattern, even if there are valid actions that could be carried out (i.e. spellcasting) before the attack block.

To circumvent this, I've tried including a block which clears the characters actions before the targeting blocks. This seems to help a bit, but it doesn't resolve the issue completely. For reference, here's how one of my scripts looks like:

IF
	!GlobalTimerNotExpired("rr#clear","LOCALS") // this block clears the creature's actions every round (prevents getting stuck in an attack pattern)
	See(NearestEnemyOf(Myself))
THEN
	RESPONSE #100
		SetGlobalTimer("rr#clear","LOCALS",6)
		ClearActions(Myself)
END

IF
	!CheckStatGT(SixthNearestEnemyOf(Myself),0,WIZARD_PROTECTION_FROM_MAGIC_WEAPONS)  // no Mantle of higher
	CheckStatLT(SixthNearestEnemyOf(Myself),100,RESISTCRUSHING)
	See(NearestEnemyOf(Myself))
	False()
THEN
	RESPONSE #100
		NoAction()
END

... more targeting blocks...

IF
	GlobalTimerNotExpired("rr#clear","LOCALS")
	!StateCheck(LastSeenBy(Myself),STATE_REALLY_DEAD)
	!StateCheck(LastSeenBy(Myself),STATE_INVISIBLE)	
THEN
	RESPONSE #100
		AttackReevaluate(LastSeenBy(Myself),15)
END

With that in place, every spellcasting action placed above the ClearActions() block seems to be checked slightly more often.

Edited by aVENGER, 03 March 2012 - 04:40 AM.


#9 Miloch

Miloch

    Barbarian

  • Modder
  • 6573 posts

Posted 08 March 2012 - 11:11 PM

I think it is just that Bioware wrote a lot of buggy, barely working code.

Quoted for truth and depression. Sigh.

We are trying to fix such unknown scripting glitches in the BG1 Fixpack, but with probably not much chance of success if the engine can't handle it. Still, we have made some progress. Perhaps it is worth reporting some things we have found, if they're not reported elsewhere (I don't remember seeing them in the Bible i.e. the IESDP). For example, 0.0.0.VARIABLE flags on one line seem to work where multiple checks fail.

Also, I remember from some time ago AttackReevaluate being glitchy, as attested by several veteran scriptors. AttackOneRound should work, as should Attack, no? The latter being that it's a more-or-less permanent condition, so it should be the last script block evaluated. AttackOneRound, however, is commonly used in spellcaster modded scripts for being able to throw daggers (or whatever) in between the 1-round wait between casting spells. I'd always assumed that worked as the veterans and my own testing said it did. Does it not?

Infinity Engine Contributions
Aurora * BG1 NPC * BG1 Fixpack * Haiass * Infinity Animations * Level 1 NPCs * P5Tweaks
PnP Free Action * Thrown Hammers * Unique Containers * BG:EE * BGII:EE * IWD:EE
================================================================
Player & Modder Resources
BAM Batcher * Creature Lister * Creature Checker * Creature Fixer * Tutu/BGT Area Map & List * Tutu Mod List
================================================================
"Infinity turns out to be the opposite of what people say it is. It is not 'that which has nothing beyond itself' that is infinite, but 'that which always has something beyond itself'." -Aristotle