Jump to content

CRE modding questions


Miloch

Recommended Posts

Well it makes an odd sort of sense if you take his statement:
I've read that section now; he's recommending sticking the targeting and the code that will use it at the bottom of the script. The targeting always comes before the blocks that will actually be using LastSeenBy() (without their own See() or Detect() triggers).

 

The code you posted has no effect beyond looking at an enemy. LastSeenBy() will be the nearest visible living object of allegiance 255, regardless of its class.

 

If a block is going to be used for targeting only, stick the False() in there. Continue() will hiccup the action queue and lead to some twitchiness.

Link to comment

I'm determined to get this thing working now. So maybe something like this?

IF
 See([ENEMY])
 !Class(LastSeenBy(Myself),FIGHTER)
 !Class(LastSeenBy(Myself),THIEF)
 !Class(LastSeenBy(Myself),FIGHTER_THIEF)
 False()
THEN
 RESPONSE #100
NoAction()
END

IF
 GlobalLT("t-cmm","LOCALS",2)
 !GlobalTimerNotExpired("t-cna","LOCALS")
 !StateCheck(LastSeenBy(Myself),STATE_SLEEPING)
 !StateCheck(LastSeenBy(Myself),STATE_HELPLESS)
 CheckStatLT(LastSeenBy(Myself),80,SPELLFAILUREMAGE)
THEN
 RESPONSE #100
SetGlobalTimer("t-cna","LOCALS",6)
IncrementGlobal("t-cmm","LOCALS",1)
SpellNoDec(NearestEnemyOf(Myself),CLERIC_MISCAST_MAGIC)
END

Or should I leave out the first block and add a See([ENEMY.0.0.MAGE]) or something to the second, and repeat for each casting class ad nauseum in a mad frenzy of CPU-bandwidth guzzling?

Link to comment

IF
!See([255.0.0.2])
!See([255.0.0.14])
!See([255.0.0.3])
False()
THEN
RESPONSE #100
Continue()
END

IF
GlobalLT("var","GLOBAL",2)
!GlobalTimerNotExpired("vat","GLOBAL")
!StateCheck(LastSeenBy(),33)
CheckStatLT(LastSeenBy(),80,51)
CheckStatLT(LastSeenBy(),80,52)
THEN
RESPONSE #100
SetGlobalTimer("vat","GLOBAL",6)
IncrementGlobal("var","GLOBAL",1)
SpellNoDec(LastSeenBy(),1310)
END

If you're scripting for BG1 and you're using LOCALS, you're on your own. I wouldn't call them an "officially" supported feature of the engine.

 

Don't be surprised if any of this fails to do anything close to what you want. You can extend the targeting in order of precedence with all the multi-class combos you want.

 

Unless you have a million blocks, there's never been anything wrong with just having one block per target.

Link to comment

Does using the IDS value instead of the identifier reduce lag or just make the script harder to read?

 

I'm reading that first block now as "if I don't see an enemy who is (of these classes), cast" Whereas I would've read the original as "if I see an enemy who isn't (of these classes), cast." If so, those'd have 2 different effects.

 

Incidentally, 2, 14 and 3 reference fighter, C/M and cleric in class.ids (another reason I'd use the descriptions if it makes no performance difference).

 

Edit: Also, I thought you said not to use Continue() with the targetting block...

Link to comment

Using the IDS values has no effect. Both compile to a number that the engine automatically knows how to handle. It makes it harder to read for you; it makes things much easier for me. The benefit of using the actual values is that anybody can compile the BAF regardless of the contents of their IDS files; your symbol for 1310 may be CLERIC_MISCAST_MAGIC and mine might be CLERIC_WIZARD_BITCH_SLAP; by using 1310, it would compile fine for both of us without any need to change the IDS symbol.

 

Fighter maps to 2; it should have been 1 (this is all from memory; I'm not perfect, and I'm used to using 202, so I often mix up the old class values). The intent was MAGE, CLERIC_MAGE, CLERIC.

 

Your block says "if I see an ENEMY" then LastSeenBy() is the ENEMY I saw. Your class checks do nothing to influence LastSeenBy().

 

My block says "if I see an ENEMY MAGE" then LastSeenBy() is the ENEMY MAGE otherwise "if I see an ENEMY CLERIC_MAGE" then LastSeenBy() is the ENEMY CLERIC_MAGE otherwise "if I see an ENEMY CLERIC" then LastSeenBy() is the ENEMY CLERIC. It's equivalent to the following:

IF
OR(3)
See([255.0.0.3])
See([255.0.0.14])
See([255.0.0.1])
False()
THEN
RESPONSE #100
Continue()
END

The Continue() is there only to provide the engine a complete trigger/response block; due to the False(), this code will never run (it's just there to be a proper BCS file).

 

Note that you probably didn't intend to look for ENEMY (remember, this is the static EA value that denotes most red-circled characters; if this is for an enemy script, they're going to start shooting each other).

 

I don't like talking about AI scripting; there's too much to cover. You're running directly from targeting to action, which doesn't account for the possibility that the character has seen somebody from somewhere else that wouldn't be considered its enemy; there's no code to account for the possibility that I saw somebody before but now don't see anybody, but LastSeenBy() will still point to the same object. Remember that if a block evaluates to false, the engine simply skips it and moves on to the next block; if you have a See() action that returns true and another trigger returns false, it will just move on to the next block (but LastSeenBy() will still point to the See()n object), and unless you have a block that's always true before your targeting section, you will always reach the blocks that depend on the targeting (regardless of whether the targeting worked or not).

 

Which is, more or less, why I tend to recommend just single blocks. ;) It's always the case that you should start simple, and as you become more comfortable with scripting, move on to more advanced techniques. There's a lot of pitfalls when doing the more complex things (especially stuff like this that it's doubtful the engine was designed to handle).

Link to comment

Well I switched to a different script without the Miscast Magic, but I left the priority targetting stuff in, because I think it makes sense for some chars to go after enemy spellcasters first. When I say enemy, I mean enemy to the CRE with the script... I'm still not quite clear on this GOODCUTOFF/EVILCUTOFF business, and I read both scripting guides and the relevant sections of the IESDP several times. Also there doesn't seem to be a clear definition on the preference of LOCALS vs. GLOBAL (except that you *can't* use LOCALS in some cases).

 

But, the good news is it kind of, sort of works. Yeah it's flaky as hell and I've probably done a couple dozen things wrong, but I'm encouraged by the fact it seems to do most of what I want and once I nail this sucker down, I can apply the same template to most of the other scripting I'm planning.

 

Here is the premise for this particular script. Nimbul (assassin in Nashkel ch. 3 of BG1) doesn't know nearly as many spells as he should, doesn't use any thief skills and fights like a pansy. Also I want him to have some sort of defense/offense against stealth and invis tactics such as described here. So he'll run a bit and/or quaff heals if his HPs get too low, otherwise he'll cast or hide and backstab in between the cast/stealth delay. That much seems to be working (more or less), but there are a few quirks:

 

1) He isn't picky about attacking the PC before technically becoming an "enemy."

2) His web ensnares himself and half the pub more often than not (maybe this is expected behaviour for the spell and I should consider another).

3) His haste buffs himself and half the pub (kind of puts a whole new spin on "buying a round for the house").

4) Sometimes he'll just stand around when the enemy PC is clearly in sight.

 

I guess most of those things could boil down to targetting issues and I should just do away with that block and rely on NearestEnemyOf() or maybe put the targetting in each block. Whatever works. This is for Tutu btw, but I have the same for BG1 with some minor changes. The initial couple of blocks involving setting "tor" is from Vlasák's guide (here depending on if BWL is up ;)). What I'm not sure about is he has the variable check negated (!GlobalGT"tor",etc.) once you get to the action, and I'm thinking it shouldn't be. But I'm probably wrong on that too. :D Though I tested it both ways and this one seemed to work a little better. This script replaces the wussy MAGE2 class script he currently has. He also has an override of INITDLG (replaced with SHOUTDLG in SCS) and a default of WTARSGT.

 

Nimbul (Mage/Thief Level 7/7)

Assigned kit Transmuter and "original class mage" flag to give 1 extra spell per level (no Abjuration spells):

5 L1: *6 WIZARD_MAGIC_MISSILE (one more than legal but whatever)

4 L2: *1 WIZARD_HORROR, *1 WIZARD_MIRROR_IMAGE, 1 WIZARD_DETECT_INVISIBILITY, 1 WIZARD_WEB

3 L3: 1 WIZARD_HASTE, 1 WIZARD_SLOW, 1 WIZARD_HOLD_PERSON

2 L4: 1 WIZARD_IMPROVED_INVISIBILITY, 1 WIZARD_CONFUSION

* spells already memorized

 

Edit: Revised script below.

Link to comment
Well I switched to a different script without the Miscast Magic, but I left the priority targetting stuff in, because I think it makes sense for some chars to go after enemy spellcasters first. When I say enemy, I mean enemy to the CRE with the script... I'm still not quite clear on this GOODCUTOFF/EVILCUTOFF business, and I read both scripting guides and the relevant sections of the IESDP several times. Also there doesn't seem to be a clear definition on the preference of LOCALS vs. GLOBAL (except that you *can't* use LOCALS in some cases).
GOODCUTOFF is an EA mask that includes all good allegiances (PC, ALLY, etc.). EVILCUTOFF is the reverse. Neither include neutrals; NOTGOOD and NOTEVIL can be used to include neutrals, but be aware that they include non-actor objects (trigger points, doors, containers, etc.), so you shouldn't ever use it without specifying other spec parameters ([31.1] is fine, but you wouldn't want just [31]).

 

If you think about LOCALS vs. GLOBAL, it should make sense; the problem is that LOCALS wasn't ever used in BG, and it's not guaranteed to do what you might expect from BG2.

 

1) He isn't picky about attacking the PC before technically becoming an "enemy."
You need code to make sure Allegiance(Myself,255) before he runs combat stuff.

 

2) His web ensnares himself and half the pub more often than not (maybe this is expected behaviour for the spell and I should consider another).
!Range(LastSeenBy(),15) (but it will ensnare everybody within range; this is expected).

 

3) His haste buffs himself and half the pub (kind of puts a whole new spin on "buying a round for the house").
It shouldn't if he's an enemy (unless the whole pub turns hostile too.

 

For this script, I really would just cut out the targeting; it doesn't look to be necessary in most cases.

Set the cast/attack timer before the spell; while you should set globals and timers at the very end with most blocks, spellcasting actions aren't interruptible, and you want to include the casting time (if I cast a spell that takes me 5 seconds to cast, I can cast another in one second, not 6); it's OK starting it after UseItem(), which is interruptible.

Don't use Continue() after setting the globals; the triggers of all blocks are going to be checked before the actions in the block(s) with Continue() are performed, so you're going to get a whole pass through the script with the current value of "TOR" instead of setting the value first and then restarting the script.

Use AttackReevaluate() instead of AttackOneRound(). 45 or 60 seems like a good reevaluation period for this character (I wouldn't go lower than 30).

Link to comment

Well, with your help, Badass Nimbul v.001 is working pretty well now. Even the targetting block seems to work. I spawned a few NPCs and went after him and he took out Xan in short order.

If you think about LOCALS vs. GLOBAL, it should make sense; the problem is that LOCALS wasn't ever used in BG, and it's not guaranteed to do what you might expect from BG2.
Is there any potential conflict if, for example, I use the same GLOBAL in two different scripts, or in the same script on two CREs present at the same time? I actually changed everything to LOCALS in the version below and it seems to be working better, since I noticed some oddness with GLOBALS when respawning him (I guess they continue to stay set even after death). Though I haven't tested it in BG1 yet - I want to get the BG2-engine version working before messing with that.

 

So just a few more glitches to iron out:

 

1) He doesn't seem to want to enter stealth mode anymore. I think all I introduced here was the cast-n-attack timer so he wasn't insta-stealthing all the time.

2) I want him to run when his HPs get low, but once he gets to a certain distance to attack again. Though by this time he's usually out of throwing daggers, but earlier he was hiding then coming up to backstab (which is what I want).

3) I only want him to cast detect invisible if he thinks someone is sneaking or invisible. But I guess !See(LastSeenBy()) doesn't work - kind of oxymoronic I guess. Is there another way to implement this?

 

Also I swapped his improved invisibility for monster summoning 2 since it didn't seem to be doing him much good (he has mirror image and stealth of 100). And added some SCS compatibility.

 

Nimbul (Mage/Thief Level 7/7)

Assigned kit Transmuter to give 1 extra spell per level (no Abjuration spells):

5 L1: *6 WIZARD_MAGIC_MISSILE (1 more than legal but whatever) SCS changes 2 to WIZARD_SLEEP

4 L2: *1 WIZARD_HORROR *1 WIZARD_MIRROR_IMAGE 1 WIZARD_DETECT_INVISIBILITY 1 WIZARD_WEB

3 L3: 1 WIZARD_HASTE 1 WIZARD_SLOW 1 WIZARD_HOLD_PERSON

2 L4: 1 WIZARD_MONSTER_SUMMONING_2 1 WIZARD_CONFUSION

* spells already memorized

 

IF
 HPPercentLT(Myself,70)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 HasItem("_POTN08",Myself)
THEN
 RESPONSE #100
UseItem("_POTN08",Myself)
SetGlobalTimer("T-NCA","LOCALS",6)
END

IF
 Allegiance(Myself,ENEMY)
 See(NearestEnemyOf())
 Range(NearestEnemyOf(),15)
 !StateCheck(Myself,STATE_INVISIBLE)
THEN
 RESPONSE #100
RunAwayFrom(LastSeenBy(),60)
END

IF
 Allegiance(Myself,ENEMY)
 Detect([GOODCUTOFF])
 !GlobalGT("T-NDI","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !See(LastSeenBy())
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NDI","LOCALS",1)
SpellNoDec(Myself,WIZARD_DETECT_INVISIBILITY)
END

IF
 Allegiance(Myself,ENEMY)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 HasItem("_POTN24",Myself)
THEN
 RESPONSE #100
UseItem("_POTN24",Myself)
SetGlobalTimer("T-NCA","LOCALS",6)
END

IF
 Allegiance(Myself,ENEMY)
 HaveSpell(WIZARD_MIRROR_IMAGE)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(Myself,STATE_MIRRORIMAGE)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
Spell(Myself,WIZARD_MIRROR_IMAGE)
END

IF
 Allegiance(Myself,ENEMY)
 !GlobalGT("T-NHA","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(Myself,STATE_HASTED)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NHA","LOCALS",1)
SpellNoDec(Myself,WIZARD_HASTE)
END

IF
 Allegiance(Myself,ENEMY)
 Detect([PC])
 !GlobalTimerNotExpired("T-NHI","LOCALS")
 !StateCheck(Myself,STATE_INVISIBLE)
 !StateCheck(Myself,4032)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #75
SetGlobalTimer("T-NHI","LOCALS",6)
ApplySpell(Myself,WIZARD_INVISIBILITY)
DisplayString(Myself,19944)
 RESPONSE #25
SetGlobalTimer("T-NHI","LOCALS",6)
DisplayString(Myself,17120)
END

IF
 GlobalGT("T-NOR","LOCALS",0)
THEN
 RESPONSE #100
SetGlobal("T-NOR","LOCALS",0)
END

IF
 !Allegiance(Myself,ENEMY)
THEN
 RESPONSE #100
SetGlobal("T-NOR","LOCALS",1)
END

IF
 Allegiance(Myself,ENEMY)
 !See([GOODCUTOFF.0.0.SORCERER])
 !See([GOODCUTOFF.0.0.MAGE_ALL])
 !See([GOODCUTOFF.0.0.CLERIC_ALL])
 !See([GOODCUTOFF.0.0.DRUID_ALL])
 !See([GOODCUTOFF.0.0.BARD_ALL])
 !See([GOODCUTOFF])
THEN
 RESPONSE #100
SetGlobal("T-NOR","LOCALS",1)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 !GlobalGT("T-NWB","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(LastSeenBy(),STATE_SLEEPING)
 !StateCheck(LastSeenBy(),STATE_HELPLESS)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NWB","LOCALS",1)
SpellNoDec(LastSeenBy(),WIZARD_WEB)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !GlobalGT("T-NCF","LOCALS",0)
 !StateCheck(LastSeenBy(),STATE_SLEEPING)
 !StateCheck(LastSeenBy(),STATE_HELPLESS)
 !StateCheck(LastSeenBy(),STATE_CONFUSED)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobal("T-NCF","LOCALS",1)
SetGlobalTimer("T-NCA","LOCALS",6)
SpellNoDec(LastSeenBy(),WIZARD_CONFUSION)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 HaveSpell(WIZARD_SLEEP)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
Spell(LastSeenBy(),WIZARD_SLEEP)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 !GlobalGT("T-NSL","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(LastSeenBy(),STATE_SLOWED)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NSL","LOCALS",1)
SpellNoDec(LastSeenBy(),WIZARD_SLOW)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 HaveSpell(WIZARD_HORROR)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(LastSeenBy(),STATE_SLEEPING)
 !StateCheck(LastSeenBy(),STATE_HELPLESS)
 !StateCheck(LastSeenBy(),STATE_PANIC)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
Spell(LastSeenBy(),WIZARD_HORROR)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 !GlobalGT("T-NMS","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NMS","LOCALS",1)
SpellNoDec(LastSeenBy(),WIZARD_MONSTER_SUMMONING_2)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 !GlobalGT("T-NHP","LOCALS",0)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !StateCheck(LastSeenBy(),STATE_SLEEPING)
 !StateCheck(LastSeenBy(),STATE_HELPLESS)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
SetGlobal("T-NHP","LOCALS",1)
SpellNoDec(LastSeenBy(),WIZARD_HOLD_PERSON)
END

IF
 !GlobalGT("T-NOR","LOCALS",0)
 HaveSpell(WIZARD_MAGIC_MISSILE)
 !GlobalTimerNotExpired("T-NCA","LOCALS")
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
SetGlobalTimer("T-NCA","LOCALS",6)
Spell(LastSeenBy(),WIZARD_MAGIC_MISSILE)
END

IF
 !GlobalGT("T-NOR","GLOBAL",0)
 !StateCheck(Myself,STATE_INVISIBLE)
 !Range(LastSeenBy(),15)
THEN
 RESPONSE #100
AttackOneRound(LastSeenBy())
END

IF
 !GlobalGT("T-NOR","GLOBAL",0)
 StateCheck(Myself,STATE_INVISIBLE)
THEN
 RESPONSE #100
AttackReevaluate(LastSeenBy(),45)
END

Edit: Script revised.

Link to comment
Is there any potential conflict if, for example, I use the same GLOBAL in two different scripts, or in the same script on two CREs present at the same time? I actually changed everything to LOCALS in the version below and it seems to be working better, since I noticed some oddness with GLOBALS when respawning him (I guess they continue to stay set even after death). Though I haven't tested it in BG1 yet - I want to get the BG2-engine version working before messing with that.
Yes, GLOBAL is global (the variables are stored in the GAM file and exist for all objects). You can't really use them for effective AI. The problem is that BG doesn't completely support LOCALS (as far as I know); they weren't fully implemented until BG2.

 

1) He doesn't seem to want to enter stealth mode anymore. I think all I introduced here was the cast-n-attack timer so he wasn't insta-stealthing all the time.
You'll need a guru to deal with the modal action scripting.

 

2) I want him to run when his HPs get low, but once he gets to a certain distance to attack again. Though by this time he's usually out of throwing daggers, but earlier he was hiding then coming up to backstab (which is what I want).
What's the problem? I'd guess your targeting system isn't really helping; move the RunAwayFrom() block above the targeting, and change the !GlobalGT() trigger to See(NearestEnemyOf()) -- he'll run away only until he doesn't see anybody that he considers an enemy (you can use a Range() trigger if you want him to stop running before he goes offscreen; default visual range is 30 exact). I'd also change LastAttackerOf() to LastSeenBy() (LastAttackerOf() is an automatic object; you have no control over who it's going to point to).

 

3) I only want him to cast detect invisible if he thinks someone is sneaking or invisible. But I guess !See(LastSeenBy()) doesn't work - kind of oxymoronic I guess. Is there another way to implement this?
Move it before your targeting block; replace the target !GlobalGT() check with Allegiance(Myself,255) Detect([2]) !See(LastSeenBy()). This will work, but only when the nearest PC is invisible.
Link to comment

For what it's worth, the script actually seems to be working better in BG1 than BG2. The LOCALS all seem to work, and he actually does the Hide() more often than not. At least I can see when it fails (there's a message), and when it succeeds he disappears. In BG2 (or Tutu), it doesn't say one way or the other whether he hid, and I'm pretty sure he stays visible, so I'm kind of thinking it's broken. I can ForceSpell invisible on him instead, but that's kind of cheesy. So... wtf?

 

Edit: Revised script above.

Link to comment

Better. Keep in mind that RunAwayFrom() is interruptible, so it's not really worthwhile to RunAwayFrom(SOMEBODY,45) Hide() (the engine should stop the running as soon as it starts the hiding). This may be why it's so crappy in BG2.

 

UseItem() is interruptible, so set the timer after using it (you want the block where he's using the item to return true until he's actually used the potion so that the engine doesn't decide to give him other actions and drop the UseItem() call altogether). With only one potion, though, it probably won't be that big a problem.

Link to comment

I expect that the LOCALS won't be stored in the save game, which for a combat script is not much of a disadvantage.

 

Might want to try temporarily swapping out the Hide() with a Use potion of invisibility block and to see if your difficulty becomes more apparent (I'm not seeing anything amiss on a casual lookover, but I'm sure no guru ;) ) It's less cheesy for sure ( :D ) and less work than inserting some ModalState triggers and a timer to ensure that Nimbul doesn't immediately break his own stealth.

Link to comment
His haste buffs himself and half the pub (kind of puts a whole new spin on "buying a round for the house").
It shouldn't if he's an enemy (unless the whole pub turns hostile too.
I thought this was fixed when I put in the Allegiance check. But I just spawned him in BG1 Candlekeep and got this after the initial dialogue is done and he turns enemy:
Nimbul- Hide In Shadows Failed

Nimbul- Casts Haste

Nimbul- Hasted

Cow- Hasted

Cow- Hasted

Tutor- Hasted

Cow- Hasted

Nimbul- Casts Mirror Image

Nimbul- Mirror Imaged

Link to comment

It's possible that it works differently in BG, or that the EA targeting (for the projectile) includes neutrals (if that's the way it is, that's the way it is; I don't bother with projectiles often enough to know for certain what should be happening).

 

Beyond looking a bit ridiculous, it's something I'd probably suggest sticking at the end of the list of stuff to worry about. :)

Link to comment

In BG2 at least, a spell using the allies only flag in its projectile only targets members of the same e/a superclass (anyone below evilcutoff can haste anyone else below evilcutoff, including evilbutgreen, but not anyone above evilcutoff - including goodbutred, and neutral).

 

I have no idea how it works in the BG1 engine ;)

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...