Author Topic: AI Scripting: Question about Objects  (Read 1882 times)

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
AI Scripting: Question about Objects
« on: May 08, 2009, 09:22:04 AM »
Okay, here's the deal.
Game: IWD+HOW+TOTLM

I have a spell that has been coded to cast under certain conditions. One of which is See(FifthNearestEnemyOf(Myself)). Okay so the way I understand it, there should be at least 5 enemies before the spell gets cast.  Why then does the spell get cast when there are two or more?

Example:  Area outside of Orc Cavern (where the caravan supplies are at).
Total number of area creatures aside from the party is 4 which consists of 3 wolves and 1 Orc.  When I fight at least two of the wolves at the same time my scripted spells take affect.  Here is one of the script blocks that is being triggered.
Code: [Select]
//------------------------------------------------------------------
//CLERIC_MAGICAL_STONE - 1106
IF
  ActionListEmpty()                                 //not doing anything
  See(FifthNearestEnemyOf(Myself))                  //see enemy
  HaveSpell(CLERIC_MAGICAL_STONE)                   //have spell
  CheckStatLT(Myself,50,SPELLFAILUREPRIEST)         //have a good chance of casting the spell
  GlobalTimerExpired("ab_cast_a_spell","LOCALS")    //local timer for any spells
THEN
  RESPONSE #100
    SetGlobalTimer("ab_cast_a_spell","LOCALS",7)    //start personal timer
    Spell(LastSeenBy(Myself),CLERIC_MAGICAL_STONE)  //cast spell
END
Is there something wrong with the above code? Is my understanding of the Second thru TenthNearestEnemyOf wrong?  Is there a different way to prevent my spell casters from using spells on really small parties of enemy?
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-altherin.webs.com

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: AI Scripting: Question about Objects
« Reply #1 on: May 08, 2009, 10:20:14 AM »
Took a deeper look into the IESDP and IDS files and tried something else out.
I changed the See(FifthNearestEnemyOf(Myself) to the following two line check
Code: [Select]
  See([ENEMY])                                      //see enemy
  NumCreatureGT(LastSeenBy(Myself),10)               //more than 10 of them 6 party members + 4 enemy
Just using 6 caused the spell to still be cast so I added 4 to see if the spell would not be cast with just those 3 wolves. The spell was not cast.  Perhaps this is a better method...
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-altherin.webs.com

Offline devSin

  • Planewalker
  • *****
  • Posts: 1632
  • Gender: Male
Re: AI Scripting: Question about Objects
« Reply #2 on: May 08, 2009, 01:58:12 PM »
Working as expected. FifthNearest will return the fifth nearest (which will just be the farthest if there are less than five enemies visible). So yeah, unless you know the PCs are getting mobbed, it probably won't usually mean that there are five or more enemies onscreen. NthNearest will always be valid when Nearest is valid, and vice versa.

Did you try just NumCreatureGT([255],4)?
« Last Edit: May 08, 2009, 02:00:52 PM by devSin »

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: AI Scripting: Question about Objects
« Reply #3 on: May 08, 2009, 04:01:13 PM »
Working as expected. FifthNearest will return the fifth nearest (which will just be the farthest if there are less than five enemies visible). So yeah, unless you know the PCs are getting mobbed, it probably won't usually mean that there are five or more enemies onscreen. NthNearest will always be valid when Nearest is valid, and vice versa.

Did you try just NumCreatureGT([255],4)?
No.  Would 255 represent ENEMY from the EA file or would that represent something else?

The only reason for using it is that should other people (once I'm done) wish to use my scripts, I don't want the spell casters to be casting all their spells on just a single creature wandering into view.  For cases like that, I think the player should decide if they want to use a spell or not...
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-altherin.webs.com

Offline devSin

  • Planewalker
  • *****
  • Posts: 1632
  • Gender: Male
Re: AI Scripting: Question about Objects
« Reply #4 on: May 08, 2009, 06:40:14 PM »
Oops, yeah. That's [ENEMY]. It might behave more sensibly than using LastSeenBy(), but I'm not sure for IWD.

You wouldn't need to See([ENEMY]) beforehand since an object [spec] is the nearest living visible object of spec (in this case, EA ENEMY, and if one's not around and visible to the caller, the NumCreatureGT() would be false).
« Last Edit: May 08, 2009, 06:41:51 PM by devSin »

Offline plainab

  • Sasha al'Therin
  • Planewalker
  • *****
  • Posts: 491
    • Infinity Engine Modding
Re: AI Scripting: Question about Objects
« Reply #5 on: May 08, 2009, 08:19:32 PM »
Oops, yeah. That's [ENEMY]. It might behave more sensibly than using LastSeenBy(), but I'm not sure for IWD.

You wouldn't need to See([ENEMY]) beforehand since an object [spec] is the nearest living visible object of spec (in this case, EA ENEMY, and if one's not around and visible to the caller, the NumCreatureGT() would be false).
Well I tried NumCreatureGT([ENEMY],3) and even surrounded by all those orcs in the main part of the cavern they never tried to cast spells.  Well, the paladins did but I hadn't adjusted their file. Smite Evil is a pretty cool spell glad they added it to HOW. The clerics didn't cast spells.  I changed it to NumCreatureGT([255],3) and it worked.

NI shows me that 255 can be one of the following:
Code: [Select]
CLASS.IDS 255 NO_CLASS
EA.IDS 255 ENEMY
GENERAL.IDS 255 MONSTER
RACE.IDS 255 NO_RACE
So perhaps [255] in this case actually points to one of the other ids files.

Another question:
I have this block setup to cast Entangle.
Code: [Select]
//------------------------------------------------------------------
//CLERIC_ENTANGLE - 1105
IF
  ActionListEmpty()                                 //not doing anything
  See(TenthNearestEnemyOf(Myself))                                      //see several enemy
  Range(LastSeenBy(Myself),40)                      //far enough out
  !Range(LastSeenBy(Myself),20)                     //but not too close that I get caught in spell too
  NumCreatureGT([255],3)                            //greater than 3 enemy
  HaveSpell(CLERIC_ENTANGLE)                        //have spell
  CheckStatLT(Myself,50,SPELLFAILUREPRIEST)         //have a good chance of casting the spell
  GlobalTimerExpired("ab_cast_a_spell","LOCALS")    //local timer for any spells
THEN
  RESPONSE #100
    SetGlobalTimer("ab_cast_a_spell","LOCALS",7)    //start personal timer
    Shout(5204)                                                  //shout to try and get party members to get out of area
    Spell(LastSeenBy(Myself),CLERIC_ENTANGLE)       //cast spell
END
I had See([ENEMY]) and it wasn't getting cast unless the creature was seen within the specified range. If I understand what you said earlier, See([ENEMY]) will return the nearest seen enemy. Usually, the nearest is always pretty close so this block wouldn't trigger.  If I change it to See(TenthNearestEnemyOf(Myself)) as I did above, it will always return the furthest away enemy if there are less than ten enemy. Is that correct?

Sometimes ActionListEmpty() can be a real pain.  Personally, I like to have my party start fighting as soon as the enemy is spotted. But when scripting with other players in mind, you have to include ActionListEmpty() so that they can have the ability to manually control their party if they so choose.  There is nothing worse than setting everything up for a good fireball, and your dense fighter's script takes over and he walks right into the hot zone.

Is BG's range of sight different than IWD's?  I think so, I can set this up in BG and it will execute real quickly. The same block in IWD takes almost an entire round to execute, by that time the enemy has sometimes already advanced to melee.
Code: [Select]
IF
ActionListEmpty()
See([ENEMY])
THEN
RESPONSE #100
AttackOneRound(LastSeenBy(Myself))
END
I did do some testing with a hotkey and moving my party members around.  I found out that 28 is the farthest out that a party member can see and respond to. However the viewable area is 29 with 30 being the fuzzy edge between clear and fog of war. Composite bows can reach that far, but the enemy has to be targeted manually, because the party member can't see that far.  Why can't they see what I can see?  In BG they would see them right as I started to see them.  I suppose part of it might be speed of attack and at what point in the round their weapons and stats allow them to attack.
Also, even though it's setup to attack when the enemy is seen they don't seem to attack until one of the party is actually hit or it's the next round.  I wonder if the viewable area doesn't change but the distance at which the party members can 'see' is reduced depending upon area conditions.  It's probably all hardcoded...

BTW who gets the report that SCRLEV.IDS is broken?
Original file:
Quote
0 OVERRIDE
1 AREA
2 SPECIFICS
4 CLASS
5 RACE
6 GENERAL
7 DEFAULT
With the original file using ChangeAIScript(S:ScriptFile*,I:Level*Scrlev) CLASS assigns the RACE script, RACE assigns the GENERAL script, GENERAL assigns the DEFAULT script, and DEFAULT does nothing. OVERRIDE, AREA, and SPECIFICS are all okay. I changed the file to
Quote
0 OVERRIDE
1 AREA
2 SPECIFICS
3 CLASS
4 RACE
5 GENERAL
6 DEFAULT
and everything assigns to the correct script slots.

All the games have this file, so they are all probably broken.

Fixing the file gives new possibilities to party ai modding.  Right now I'm experimenting with script switching once every turn or when enemies are present. I have spells scripted in the class level and basic combat in the race level.  That means that when enemy appears and the party member is a multi-class, the current spell script is read and if nothing is true except the switch block, the script switches to the other spell script.  With this idea, we no longer need a really large script for multi-class characters we can just switch between the true class scripts.  Since the basic combat blocks are one level lower in their own script file, they do not get interfered with. It's the same principle as not assigning a party script and just letting them use whatever was pre-coded in the dplayer scripts.

The only drawback (and I just thought about it so now I have to figure a solution for it) is that if the player installs scripts using this process. They try them, like them, but decide they don't want to use them for their current game. They change the scripts within the game. The race script wouldn't get reset and would cause all kinds of problems later on.... If they uninstalled the script mod, then the file would not exist and be the same as if the file existed and was empty.  But what to do if they don't uninstall it.... 
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-altherin.webs.com

Offline devSin

  • Planewalker
  • *****
  • Posts: 1632
  • Gender: Male
Re: AI Scripting: Question about Objects
« Reply #6 on: May 08, 2009, 09:56:54 PM »
Well I tried NumCreatureGT([ENEMY],3) and even surrounded by all those orcs in the main part of the cavern they never tried to cast spells.  Well, the paladins did but I hadn't adjusted their file. Smite Evil is a pretty cool spell glad they added it to HOW. The clerics didn't cast spells.  I changed it to NumCreatureGT([255],3) and it worked.
This is likely just flakiness if there was any difference in behavior. Both will compile to identical BCS code.

I had See([ENEMY]) and it wasn't getting cast unless the creature was seen within the specified range. If I understand what you said earlier, See([ENEMY]) will return the nearest seen enemy. Usually, the nearest is always pretty close so this block wouldn't trigger.  If I change it to See(TenthNearestEnemyOf(Myself)) as I did above, it will always return the furthest away enemy if there are less than ten enemy. Is that correct?
Correct. TenthNearestEnemyOf() will be the enemy farthest from the caller (or the tenth if there are that many enemies) and will always be a valid object as long as there's a single enemy visible (NearestEnemyOf()).

Is BG's range of sight different than IWD's?  I think so, I can set this up in BG and it will execute real quickly. The same block in IWD takes almost an entire round to execute, by that time the enemy has sometimes already advanced to melee.
I think this is just the way IWD runs scripts (on PCs at least). IIRC, Kulyok had some more exact observations about what IWD does and doesn't do.

All the games have this file, so they are all probably broken.
It works correctly in BG and BG2. Probably nobody ever tested it for IWD.

 

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.

Name: Email:
Verification:
Type the letters shown in the picture
Listen to the letters / Request another image
Type the letters shown in the picture:
What color is grass?:
What is the seventh word in this sentence?:
What is five minus two (use the full word)?: