Jump to content

Proofreading the eSeries


Recommended Posts

I was originally going to do this for the BPSeries by seanas, but TBH, I cannot get them to even work. Since these install, and have only crashed once--I chose them.

 

Currently,I'm doing this for my sole benefit. If my judgements are correct, and I make these scripts run much more efficiently--I will be more than happy to share. Unless you wish to repeat my completed work on your own, or ignore the offer, or disagree with my results.

 

The singlemost important issue I have found, and am changing, is this: I have moved all the HaveSpell and HasItem checks to the very top of the block, above the ActionListEmpty() and its variants. Why? I see it as the most important condition, by far.

 

This differs from what I have done with BP. The reason is: those scripts have been carefully trimmed to offer only the spells and items that any/all of the script users possess. That means there is a fairly decent chance that an individual will have 30-60% of these spells/items.

 

In a PC script, however, the goal is different. These are a "catch-all" script, an attempt at being a good boyscout and preparing for every situation. Thus, a vast array of spells and items are offered. Even an epic-level PC only has a decent chance of having 10% of the available options.

 

You have anywhere from 3-5 conditions at the top of every block, to check aura cleansing, cast n' attack, and so on. This is five checks before they even check to see if they have the spell/item. Every block will do this, and at best maybe 1 in 10 will do something at the end. So, by setting it up this way--I have eliminated 2-4 checks per block, 90% or more of the time. This is bound to be a lot faster parsing.

 

In certain instances, I will put a directly-related CheckStat/StateCheck up top. A clear-cut example:

 

HaveSpell(WIZARD_STONESKIN)
CheckStatLT(Myself,1,STONESKINS)

 

If it is a script for self-curing, I also put the HPPercentLT(xxxx) check up top. If you don't have the potion, or you're not injured--who cares if you have the time, or if you're aura cleansed?

 

Smaller details:

 

Your Hill Giant Potion block has no HasItem() check.

 

I broke the huge OR(86) at the bottom down into 9 saller blocks. I added a check for

Global("gh_MeleeMissileToggle","LOCALS",0)

to the top of each sub-block, and a SmallWait(1) right before the Continue() at the end. Why? Continue() has a lousy habit of not setting Globals before continue()'ing. I'm not 100% sure they don't wait till parsing round is over before setting. The SmallWait(1) is an attempt to give them a slight "hiccup" and time to parse. If successful, and you had a missile weapon that was in the first block of OR(1)--just think of the time saved here. It's worth a 1/15th of a second delay on the chance it works.

 

I swapped the code for cloud spells with the BPDetectStatv1.2 WIZARD_GREATER_MALISON piggyback for Cloud spells, that I reported in a previous thread.

 

Other block orders were changed, moving this/that line up/down a notch. Too many variants to report, emphasis on level of relevance and probability of ringing true. A rarely tru block should be up top--it will save the additional 'parsing for naught' more often than not.

 

EDIT: oh, almost forgot. For the "Scripted Auto-Pause", I removed the HPLT(Myself,20) and upped the % check to LT 25%. The reason: the auto-pause gets highly annoying when you're only first level. :)

 

3 scripts down, 4 to go--then I'll see how well this works/doesn't work.

 

:D

 

Horred

Link to comment
I was originally going to do this for the BPSeries by seanas, but TBH, I cannot get them to even work. Since these install, and have only crashed once--I chose them.

 

Currently,I'm doing this for my sole benefit. If my judgements are correct, and I make these scripts run much more efficiently--I will be more than happy to share. Unless you wish to repeat my completed work on your own, or ignore the offer, or disagree with my results.

 

The singlemost important issue I have found, and am changing, is this: I have moved all the HaveSpell and HasItem checks to the very top of the block, above the ActionListEmpty() and its variants. Why? I see it as the most important condition, by far.

 

This differs from what I have done with BP. The reason is: those scripts have been carefully trimmed to offer only the spells and items that any/all of the script users possess. That means there is a fairly decent chance that an individual will have 30-60% of these spells/items.

 

In a PC script, however, the goal is different. These are a "catch-all" script, an attempt at being a good boyscout and preparing for every situation. Thus, a vast array of spells and items are offered. Even an epic-level PC only has a decent chance of having 10% of the available options.

 

You have anywhere from 3-5 conditions at the top of every block, to check aura cleansing, cast n' attack, and so on. This is five checks before they even check to see if they have the spell/item. Every block will do this, and at best maybe 1 in 10 will do something at the end. So, by setting it up this way--I have eliminated 2-4 checks per block,  90% or more of the time. This is bound to be a lot faster parsing.

 

In certain instances, I will put a directly-related CheckStat/StateCheck up top. A clear-cut example:

 

HaveSpell(WIZARD_STONESKIN)
CheckStatLT(Myself,1,STONESKINS)

 

If it is a script for self-curing, I also put the HPPercentLT(xxxx) check up top. If you don't have the potion, or you're not injured--who cares if you have the time, or if you're aura cleansed?

 

Smaller details:

 

Your Hill Giant Potion block has no HasItem() check.

 

I broke the huge OR(86) at the bottom down into 9 saller blocks. I added a check for

Global("gh_MeleeMissileToggle","LOCALS",0)

to the top of each sub-block, and a SmallWait(1) right before the Continue() at the end. Why? Continue() has a lousy habit of not setting Globals before continue()'ing. I'm not 100% sure they don't wait till parsing round is over before setting. The SmallWait(1) is an attempt to give them a slight "hiccup" and time to parse. If successful, and you had a missile weapon that was in the first block of OR(1)--just think of the time saved here. It's worth a 1/15th of a second delay on the chance it works.

 

I swapped the code for cloud spells with the BPDetectStatv1.2 WIZARD_GREATER_MALISON piggyback for Cloud spells, that I reported in a previous thread.

 

Other block orders were changed, moving this/that line up/down a notch. Too many variants to report, emphasis on level of relevance and probability of ringing true. A rarely tru block should be up top--it will save the additional 'parsing for naught' more often than not.

 

EDIT: oh, almost forgot. For the "Scripted Auto-Pause", I removed the HPLT(Myself,20) and upped the % check to LT 25%. The reason: the auto-pause gets highly annoying when you're only first level. :D

 

3 scripts down, 4 to go--then I'll see how well this works/doesn't work.

 

:)

 

Horred

 

Hey Horred,

 

Actually given what you posted here

 

http://forums.gibberlings3.net/index.php?showtopic=5542

 

I was planning on giving you a jingle to see where you might suggest some improvements.

 

In regards to your efforts. I'm whole heartedly in favor of some eSeries tidying :D

 

I've been considering re-ordering the blocks myself to be more efficient, but have stood on the fence using the "if it ain't broke, don't fix it." approach.

 

I would offer you the indiviudal script snippets, but sounds like you've already dived well into the larger scripts. No matter, they can be broken up relatively easily.

 

If you haven't made it to eMage, check out the Bard Song code, if you would. I've used it through an entire game using Haer'Dalis and it seems to work as intended. The bard doesn't do much, but that is okay in my opinion. Keeping that song going is more important than a Bard with a wimpy THAC0 trying to hit something with a weapon. And I have seen him break out of singing to throw a dart or cast a spell, if the scripting decided the situation was worth it.

 

I've also been thinking about an eFighterMage version that doesn't use the "stay out of harms way" reasoning of eMulti and eMage.

 

Other things I've been thinking about.

 

Better handling of invisibility. The scripts are happy to cast invisibility and just as happy to break it with the next action.

 

A no casting mage spells Hot Key. Primarily this is for Athkatla in order to prevent summoning the Cowled Wizards, but allow the character to continue to act. Right now I turn Mages AI off or go pay the bribe.

 

How about Cleaning, Vacuuming, and Rearranging courtesy of Horred the Plague in the ReadMe :D ?

 

Let me know your thoughts.

 

Thanks,

Link to comment

Hey, I'm glad to help--it's not for accredidation, though I won't refuse it. :)

 

After several years, I'm finally trying Party AI out. And, as per usual--if something isn't (IMO) working up to snuff, I am compelled to fix it. An obsessive trait I wish I could shed at times.

 

 

Better invisibility handling? I have a small bead on that in BP AI. I set a global timer at casting time (BPIP,LOCALS,15). I figure 15 seconds is enough time to pull off a couple things, and not exclude yourself from a foray.

 

Right after my targetting blocks for offensive activity, before the brawl is started, I keep the following block:

 

IF
 OR(2)
   StateCheck(Myself,STATE_INVISIBLE)//I'm not 100% sold on STATE_NOT_VISIBLE
   StateCheck(Myself,STATE_IMPROVEDINVISIBILITY)//are you 100% sure it works?
 GlobalTimerNotExpired("BPIP","LOCALS")
THEN
 RESPONSE #15
   Continue()
 RESPONSE #60
   IncrementGlobal("BPIP","LOCALS",-1)
 RESPONSE #90
   RunAwayFrom(NearestEnemyOf(Myself),10)
END

 

This gives them a small (~10% chance) per second of doing something offensive (continue). Or, just getting a little ancy(increment -1). Or, getting out of harm's way(run away).

 

With all my defensive casting blocks kept above this block, chances are they will cast a buff or two (or heal up, etc) before attacking--as they should be. Thieves, of course, have a little different code arrangement for STATE_INVISIBLE... :D

 

I'll definitely check your bard code out. Mine is working pretty well for the enemes as well. Of course, I had to make some custom songs with different PRO files to pull it off (much like NPC_BLADE_BARRIER does). They only seem to shut off under the following conditions:

 

IF
 OR(3)
   NumCreatureLT([EVILCUTOFF],3)//maximum of one ally to help out, he might need a hand in melee...or, I'm all alone in this endeavor
   HPPercentLT(Myself,45)//I'm getting toasted, and all I'm doing about it is singing XMas carols!
   GlobalTimerExpired("SONG","LOCALS")//for enemies, it's better to shut down once in a while. I use a five-round timer.
 Global("SING","LOCALS",1)
THEN
 RESPONSE #100
   SetGlobalTimer("SONG","LOCALS",0)
   SetGlobal("SING","LOCALS",0)
   ClearActions(Myself)
END

 

I've also eliminated a couple of Broken Objects, from my old Team BG post (preserved on Spellhold forums)and rigorous testing. Biggest offender I found was TenthNearestEnemyOfType. In order to work right, you need TenthNearest([EVILCUTOFF]), or whatever ID you need ATM. NearestEoT works fine, just not 2nd-10th. Same goes for NearestMyGroupOfType. :D

Link to comment

Another one I'm doing here is tinkering with the detectable stats. As the author of this package, I probably have the best understanding on how they work.

 

The biggest change I've done is to SCRIPTINGSTATE4 (the combat goodies)

 

I've changed all the

 

!CheckStat(Myself,[2-5],SCRIPTINGSTATE4) to

CheckStatLT(Myself,2,SCRIPTINGSTATE4).

 

When I set up the values for these stats, esp the ones with many spells apiece--I tried to layer them in tiers of power. That's why Greater Whirlwind is a 5, and Whirlwind is a 4. The purpose? So you don't cast a lessor buff while a greater is still in effect.

 

With players, who will face more than one battle in life, I took this a step further. A Whirlwind attack lasts for 9 seconds--the cast n' attack timer for only 6. What is to prevent you from casting (e.g.) Power Attack (SS4 value 2)? The above restriction wil make sure you don't overfire your combat buffers--that you get the most out of your innate.

 

Other stats include SS#5 (the armors) and SS#6 (strength/stat boosters). Why cast Divine Power when you have Righteous Magic in use?

 

BTW--I like the creative use of SS4-# 3, for invoke courage. I never thought of that one. :) Perhaps I should have lumped it in with WIZARD_RESIST_FEAR as well.

 

EDIT: Almost forgot. Came up with a new condition block for Breach spell, for both eSeries and BP :D

 

  OR(11)
    CheckStatGT(LastSeenBy(Myself),0,SHIELDGLOBE)                           
    CheckStatGT(LastSeenBy(Myself),0,STONESKINS) 
    CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_NORMAL_WEAPONS)
    CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_MAGIC_WEAPONS)
    CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_NORMAL_MISSILES) 
    CheckStatGT(LastSeenBy(Myself),0,SCRIPTINGSTATE5)
    CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_MAGIC_ENERGY) 
    CheckStatGT(LastSeenBy(Myself),0,WIZARD_PROTECTION_FROM_THE_ELEMENTS)
    //CheckStatGT(LastSeenBy(Myself),0,WIZARD_RESIST_FEAR)        These can be dispelled as well,
    //CheckStatGT(LastSeenBy(Myself),0,PROTECTION_FROM_EVIL)      but is it really worth it?
    CheckStatGT(LastSeenBy(Myself),0,CLERIC_CHAOTIC_COMMANDS)
    CheckStatGT(LastSeenBy(Myself),0,SCRIPTINGSTATE2)
    CheckStatGT(LastSeenBy(Myself),0,CLERIC_PHYSICAL_MIRROR)
 !CheckStat(LastSeenBy(Myself),1,WIZARD_SPELL_SHIELD)

Link to comment
If ya need a tester let me know.

 

ronin

 

I'm not doing surgery, just a "shave and a haircut". After hours of mouse-manipulation (my mouse started double-clicking about 3 hrs back, from fatigue, to boot!), I'm going to test these out myself for a bit. After I feed them to the NI script shredder (aka The Dropzone). I'd use DLTCEP, but it's not set up for .bs files.

 

I'll pass them along if all goes well, fear not my friend. :down:

Link to comment

Scripts compiled with very few (100% my typo) errors. I had an initial problem; the game crashed immediately when the scripts were set. I cam to find out that amongst others, TDD had "gone out of its way" to set many innate spell levels to zero. All in all, there were 897 innate spells that were off, from all the mods installed. Including BP-weidu. I saved a list, in case any modmakers are curious how they fared.

 

I HIGHLY recommend adding this code to your tp2 file, Cirerrek. Just as a safety net.

 

PRINT ~Patching all the existing innate spells, setting level to one.....~

COPY_EXISTING_REGEXP GLOB ~.*\.spl~ ~override~
 READ_SHORT 0x1c spell_type
 PATCH_IF (%spell_type% = 4) BEGIN
   READ_LONG 0x34 spell_level
   PATCH_IF (%spell_level% =0) BEGIN
     WRITE_LONG 0x34 ~1~
   END
   PATCH_IF (%spell_level% > 1) BEGIN
     WRITE_LONG 0x34 ~1~
   END
 END
BUT_ONLY_IF_IT_CHANGES

 

This took ~ 1 minute to parse, and caught almost 900 errors. Good, commonly-used innates amongst them.

 

I've now played a few battles with it, and I've made a couple observations. PC's on the fringe of battle seem to be standing around. I think I saw a Ra+

nge(15) check around somewhere in there, and I'm gonna tweak it. The extent of sight range, as I'm sure you know, is 28. I've actually measured fireball's radius at 15 before. My newly-developed "bomb a mage offscreen, he'll bomb you back" tactic has a near-invisible (transparency effect :down: ) CRE stop at a range of 12, and the mage focuses on him. Party members do get hurt. I mention this because some of your enemy vs party memeber range checks aren't adding up. PC's will bleed...

Link to comment
I HIGHLY recommend adding this code to your tp2 file, Cirerrek. Just as a safety net.

 

PRINT ~Patching all the existing innate spells, setting level to one.....~

COPY_EXISTING_REGEXP GLOB ~.*\.spl~ ~override~
 READ_SHORT 0x1c spell_type
 PATCH_IF (%spell_type% = 4) BEGIN
   READ_LONG 0x34 spell_level
   PATCH_IF (%spell_level% =0) BEGIN
     WRITE_LONG 0x34 ~1~
   END
   PATCH_IF (%spell_level% > 1) BEGIN
     WRITE_LONG 0x34 ~1~
   END
 END
BUT_ONLY_IF_IT_CHANGES

 

This took ~ 1 minute to parse, and caught almost 900 errors. Good, commonly-used innates amongst them.

 

There is a potential downside to this that you may not be aware of. Although it may not really be that much of a headache. SpellCastInnate only returns true when the innate spell is of the correct level. As far as I know, this only effects Saldrex's (the dragon in Watcher's Keep) script. It is used to detect a thief laying traps near him, IIRC.

 

I've now played a few battles with it, and I've made a couple observations. PC's on the fringe of battle seem to be standing around. I think I saw a Ra+

nge(15) check around somewhere in there, and I'm gonna tweak it. The extent of sight range, as I'm sure you know, is 28. I've actually measured fireball's radius at 15 before. My newly-developed "bomb a mage offscreen, he'll bomb you back" tactic has a near-invisible (transparency effect :down: ) CRE stop at a range of 12, and the mage focuses on him. Party members do get hurt. I mention this because some of your enemy vs party memeber range checks aren't adding up. PC's will bleed...

 

Yeah, verifying ranges was on my list of things "To Get Around To Sometime." The way it is currently set up, AOE spells are scripted fairly strictly. Meaning that they don't often cast them, so it wouldn't necessarily be obvious that the ranges checks were off. Not enough test cases... Any improvements you can come up with there are greatly appreciated.

 

Thanks,

Link to comment
Listening in.... taking notes.... goes away to fix his own scripts.... :down:

 

-Y-

 

 

A wise man... :devil:

 

I've totally revamped the shouts and melee/ranged system. No more need for 86 ranged weapons in a list, when one simple modded bow could bring the whole brick $hithouse down.

 

It all works, except for one very funky error. DART01.itm...

 

My main PC cannot switch to them on EquipRanged(). Though he throws them regularily. Neither can Montaron. Xzar, however, has no such problem.

 

I even wrote some hex-patch code to fix the darts, because of all the darts their damage was set to slashing instead of missile. This did nothing to remedy the situation. I gave my PC a sling, just for kicks. He can switch on/off with the greatest of ease.

 

Funky anomalies aside, this works, and well. The shouts will call the crew in from out of sight range. The (F) hot key not only switches from melee to missile mode--it switches weapons as well.

 

The overall speed and responsiveness/dynamics of the scripts have improved greatly.

 

And now, for the frendly observers--here is some code:

 

The shouts:

 

// **********************************************************************
// *           Segment Name: gs_HelpCall.baf
// **********************************************************************

// * PART OF COORDINATION SCRIPTLETS, SHOUT HELP
// * Requires the usual swag of Custom IDS files, see gs_Credits (gMulti)

// * Shout(HELP) if you need to
IF
 HPPercentLT(Myself,25)                                                   // if hp<25%
 AttackedBy([ANYONE],DEFAULT)                                             // and under any form of attack
 Detect(NearestEnemyOf(Myself))                                           // and opponents are still present
 !GlobalTimerNotExpired("WHINED","LOCALS")                                // one can only whine so often...
THEN
 RESPONSE #100
   SetGlobalTimer("WHINED","LOCALS",3)                                    // but the need is grim, 2/round at least
   GlobalShout(2001)
   Continue()                                                             // make sure we can do more than whine about it
END

// **********************************************************************
// *           Segment Name: gs_MoveToCombat.baf
// **********************************************************************

// * COORDINATION SCRIPT
// * A simple combination of Shout() and Heard() to ensure all PCS fight together, and
// * that damaged pc's opponents are priority targets.
// *
// * [Still in development, unsure of effectiveness, hence the DSH's]

// Call for help if someone is doing nothing
IF
 See([ENEMY])
 Global("CE_WasHelpCaller","LOCALS",0)
THEN
 RESPONSE #100
   SetGlobal("CE_WasHelpCaller","LOCALS",1)
   GlobalShout(5003)
   Continue()
END

// Clear the help flag
IF
 !See([ENEMY])
 Global("CE_WasHelpCaller","LOCALS",1)
THEN
 RESPONSE #100
   SetGlobal("CE_WasHelpCaller","LOCALS",0)
END

// * Stop Moving when I see an enemy
IF
 OR(2)
    CombatCounter(0)                                                      // if combat hasn't started, yet
    See([ENEMY])                                              // or I see an Enemy
 Global("move_to_enemy","LOCALS",1)                                       // and I am responding to a help call
THEN
 RESPONSE #100
   SetGlobal("move_to_enemy","LOCALS",0)                                  // clear the variable that lets me know that I am responding to a help call
   ClearActions(Myself)                                       // Stop
   Continue()                                                 //and replan my thinking, now that an enemy is in sight
END

// Respond to a help call
IF
 ActionListEmpty()
 Heard([PC],5003)                                    // and I have received a help call
 !Range(LastHeardBy(Myself),0)
 !See([ENEMY])                                                // I don't see an Enemy
 Global("move_to_enemy","LOCALS",0)                          // and the variable that lets me know that I am responding to a help call isn't set
THEN
 RESPONSE #100
   SetGlobal("move_to_enemy","LOCALS",1)                                  // set a variable to let me know that I am responding to a help call
   SmallWait(5)
   MoveToObject(LastHeardBy(Myself))                                      // move to the person who shouted for help
END

//Responding to a desperate cry for help, hold my calls!

IF
 Heard([GOODCUTOFF],2001)
 !Range(LastHeardBy(Myself),0)
 OR(2)
   See(LastHeardBy(Myself))                              //can we see our pal at least?
   See(LastAttackerOf(LastHeardBy(Myself)))               //or better yet, his attacker?
 Range(LastSeenBy(Myself),15)                            //are they within a reasonable distance?
 !GlobalTimerNotExpired("RESPOND","LOCALS")              //are we already busy playing good samaritan?
THEN
 RESPONSE #100
   SetGlobalTimer("RESPOND","LOCALS",12)                 //we won't hear any more cries for help for a bit, we're busy
   SmallWait(5)
   MoveToObject(LastSeenBy(Myself))                      //move in to assist
   Continue()                                            // and let the script do the talking
END

 

The new hotkey code:

 

// **********************************************************************
// *           Segment Name: ek_SetWeaponPreference.baf
// **********************************************************************

IF
 HotKey(F)                                          // and I hit the F key
 Global("hlid_UseRangedWeapon","LOCALS",1)          // and the global, hlid_UseRangedWeapon, is set to 1
THEN
 RESPONSE #100
   EquipMostDamagingMelee()
   SetGlobal("hlid_UseRangedWeapon","LOCALS",0)     // set the global, hlid_UseRangedWeapon to 0
   SmallWait(1)
   DisplayStringHead(Myself,15529)                  // say "Melee!"
END

IF
 HotKey(F)                                          // and I hit the F key
 Global("hlid_UseRangedWeapon","LOCALS",0)          // and the global, hlid_UseRangedWeapon, is set to 0
THEN
 RESPONSE #100
   EquipRanged()
   SetGlobal("hlid_UseRangedWeapon","LOCALS",1)     // set the global, hlid_UseRangedWeapon to 1
   SmallWait(1)
   DisplayStringHead(Myself,9403)                   // say "Missile Weapons"
END

// **********************************************************************
// *           Segment Name: gs_AIOffSwitch.baf
// **********************************************************************

// * AI OFF SWITCH ROUTINE

// * If AI is off, check for switching it back on
// * E=Enable AI
IF
 HotKey(E)
 Global("gh_AIOffSwitch","LOCALS",1)
THEN
 RESPONSE #100
   SetGlobal("gh_AIOffSwitch","LOCALS",0)
   SmallWait(1)
   DisplayStringHead(Myself,16469)                                        // "On"
END

// * If AI is on, check for switching if off
// * D=Disable AI
IF
 HotKey(D)
 Global("gh_AIOffSwitch","LOCALS",0)
THEN
 RESPONSE #100
   SetGlobal("gh_AIOffSwitch","LOCALS",1)
   SmallWait(1)
   DisplayStringHead(Myself,16470)                                        // "Off"
END

// * If AI is off, abort this script
IF
 ActionListEmpty()                                                        // player hasn't given any commands
 Global("gh_AIOffSwitch","LOCALS",1)                                      // AI switch is set to off
THEN
 RESPONSE #100
END

 

And, of course--the weapon switcher:

 

// **********************************************************************
// *           Segment Name: gs_SelectRangedThenMelee_ItemList.baf
// **********************************************************************

// * Notes:  TargetUnreachable seems to happen more often that one might think.  I believe if
// *         the character cannot reach LastSeenBy(), such as in the case of when they are 
// *         surrounded by other NPCs, then that counts as TargetUnreachable()

// * SELECT RANGED_WEAPON, if you have one in a quickslot
IF
 !GlobalTimerNotExpired("gh_ActionIsInterruptable","LOCALS")               // if we're still on our timer, & attacking--no need to add more time
 OR(2)
   Global("hlid_UseRangedWeapon","LOCALS",1)                             // or the global, hlid_UseRangedWeapon, is set to 1
   Global("gh_MeleeMissileToggle","LOCALS",0)                               // 1=Fire a Missile, we checked clean against them last block
 !Range(LastSeenBy(Myself),4)                                             // range is >4 steps away, therefore ranged
 !InWeaponRange(LastSeenBy(Myself))                                       // and my current wepaon won't reach there
 !InParty(LastSeenBy(Myself))                                             // and they're not in our party (double-check)
 !CombatCounter(0)                                                        // and combat is *not* over
 THEN
 RESPONSE #100
   SetGlobal("gh_MeleeMissileToggle","LOCALS",1)                          // 1=Missile
   EquipRanged()                                                          // Equip ranged weapon
   SmallWait(3)
   Continue()                                                             // and Continue to ranged weapons check block
END


// * SELECT MELEE ATTACK
IF
 !GlobalTimerNotExpired("gh_ActionIsInterruptable","LOCALS")               // if we're still on our timer, & attacking--no need to add more time
 OR(2)
   Global("hlid_UseRangedWeapon","LOCALS",0)                             // or the global, hlid_UseRangedWeapon, is set to 1
   Range(LastSeenBy(Myself),4)                                              // range is closer than 4 steps, therefore melee
 !InParty(LastSeenBy(Myself))                                             // and they're not in our party (double-check)
 !Class(Myself,MONK)                                                      // and we're not a monk
THEN
 RESPONSE #100
   SetGlobal("gh_MeleeMissileToggle","LOCALS",0)                          // 0=Melee
   EquipMostDamagingMelee()                                               // equip nasty Weapon
   SmallWait(3)
   Continue()                                                             // and Continue() to Attack() routine
END

IF
 !GlobalTimerNotExpired("gh_ActionIsInterruptable","LOCALS")               // if we're still on our timer, & attacking--no need to add more time
 Global("gh_MeleeMissileToggle","LOCALS",1)                               // 1=Fire a Missile, we checked clean against them last block
 Range(LastSeenBy(Myself),20)                                             //& we can still see them, and within dart range (minimum ranged weapon reach)
 !Range(LastSeenBy(Myself),4)                                             // range is >4 steps away, definitely for ranged attack
 OR(2)
   Global("hlid_UseRangedWeapon","LOCALS",0)                             // either the global, hlid_UseRangedWeapon, is set to 0
   !InWeaponRange(LastSeenBy(Myself))                                       //or they're not in range = we have no ranged weapon
 !CombatCounter(0)                                                        // and combat is *not* over
 THEN
 RESPONSE #100
   SetGlobal("gh_MeleeMissileToggle","LOCALS",0)                          // 1=Missile
   EquipMostDamagingMelee()                                               // Equip melee weapon instead                                                      // "Missile Weapons"
   SmallWait(3)
   Continue()                                                             // and Continue to Attack() routine
END

IF
 !GlobalTimerNotExpired("gh_ActionIsInterruptable","LOCALS")               // if we're still on our timer, & attacking--no need to add more time
 !Range(LastSeenBy(Myself),20)                                             //we're outside of dart range
 !InWeaponRange(LastSeenBy(Myself))                                        //and our weapon isn't "long" enough
 See(NearestEnemyOf(Myself))                                               //and we can see our nearest opponent
THEN
 RESPONSE #100
   Continue()                                                              //take whatever is in hand, and head to the attack block
END

// **********************************************************************
// *           Segment Name: gs_Attack.baf
// **********************************************************************

// * ATTACK CLAUSE

// * "Force" Reevaluation Clause of Attack()
// * ----------------------------------------
// * Thanks to Gebhard Blucher & Jochem for the source and inspiration for these bits :)

// * Simple Interruptable Attack Clause
IF
 ActionListEmpty()                                                         // not doing a thing...
 !GlobalTimerNotExpired("gh_ActionIsInterruptable","LOCALS")               // if we're still on our timer, & attacking--no need to add more time
 !Allegiance(LastSeenBy(Myself),GOODCUTOFF)                               // and they're not in our party (double-check)
 Detect([EVILCUTOFF])
THEN
 RESPONSE #100
   SetGlobalTimer("gh_ActionIsInterruptable","LOCALS",6)                  // set a 18-sec timer to indicate action is interruptable
   AttackOneRound(LastSeenBy(Myself))                                             // Attack()--if time expires, we reevaluate
END

// * Minimum Catch-All Attack
// * This is invoked if targetting produced no valid targets, and thus the LastSeenBy() is empty
// * but Combat is still going. This is usually when there are only targets left that
// * qualify as "helpless". I'm not so bothered about losing the attacks here, so I continue
// * to use AttackOneRound()

// * MINIMUM ATTACK
IF
 ActionListEmpty()
 See(NearestEnemyOf(Myself))                                              // but we can still see AN enemy
 !InParty(LastSeenBy(Myself))                                             // and they're not in our party (double-check)
 !Allegiance(LastSeenBy(Myself),GOODCUTOFF)                               // and not an Ally, Familiar, Minion or Simulacrum
THEN
 RESPONSE #100
   AttackOneRound(NearestEnemyOf(Myself))                                 // and attack
END

 

Note some of the bigger changes. I switched from Attack to AttackOneRound, and set the interrupt timer for the entire six seconds. Why? AOR is much more dynamic, as it shuts off the action list every six seconds. Allowing your script to freely parse info. The previous system had a timer of 1 second, constantly reset, constantly reaffirming the Attack() command. Very difficult to switch out of this mode, I've found from my enemy AI scripts. As difficult as getting out of a MoveToObject() command. Also, the !GlobalTimerNotExpired keeps it from adding rounds indefinitely. Less actions compouned in the list = more dynamic script runners.

 

 

 

I'll keep testing, fine-tuning as I go. Very promising progress has been made, but testing is not completed.

Link to comment

I figured out the "dart anomaly". My main PC had a buckler on his arm. So did Montaron. The second I took them off, they could switch on/off to dart.

 

Now, to figure out a little workaround (if one exists...). :devil:

 

EDIT: Damn, this engine makes things tough on you. I tried making a spell, that equipped a blank item in your shield slot. Then, script commands to EquipRanged() and to FillSlot(SHIELD).The spell "worked", but it destroyed your shield in the process.

 

Back to the drawing board, but it isn't looking good. This might just be a scripting limitation we cannot overcome, by any trickery.

 

ANOTHER EDIT: Nope, no sirree. I tried every trick I could devise, from invisible CRE's w/custom SPLs, to custom ACTIONs and TRIGGERs. Stupid engine cannot be beaten on this. Guess we'll need a limitation note in the readme file. :down:

Link to comment
I figured out the "dart anomaly". My main PC had a buckler on his arm. So did Montaron. The second I took them off, they could switch on/off to dart.

 

Now, to figure out a little workaround (if one exists...).  :devil:

 

EDIT: Damn, this engine makes things tough on you. I tried making a spell, that equipped a blank item in your shield slot. Then, script commands to EquipRanged() and to FillSlot(SHIELD).The spell "worked", but it destroyed your shield in the process.

 

Back to the drawing board, but it isn't looking good. This might just be a scripting limitation we cannot overcome, by any trickery.

 

ANOTHER EDIT: Nope, no sirree. I tried every trick I could devise, from invisible CRE's w/custom SPLs, to custom ACTIONs and TRIGGERs. Stupid engine cannot be beaten on this. Guess we'll need a limitation note in the readme file.  :down:

 

FillSlot() is evil. Use at your own peril.

 

Way back when someone came up with a way to switch items around reliably. But it only worked with specific items, liking passing around a ring of regeneration.

 

IIRC it involved the judicious use of DropItem, PickUpItem, FillSlot, and probably checks to make sure you have room in your inventory.

 

One thing you could do would be to check to see if your shield slot is full

 

!HasItemSlot(Myself,SLOT_MISC19) //note that SLOT_MISC19, is not the shield slot, you'd have to look that up.

 

The developers in their finite wisdom once said "We never envisioned needing to be able to take an item from the backpack and put it into an inventory slot." Sigh...

 

AttackOneRound vs Attack vs AttackReevaluate: just an FYI, Sarkyn went with Attack because someone did a bunch of testing with the various options and Attack was the only method that didn't lose attacks per round. I don't really care if I lose a few attacks here and there if the whole system becomes more robust.

 

On on a previous topic, I think you are right about Continue and Globals. I don't have any hard evidence to back it up, but I suspect it is the reason that my Sequencer Memory code would forget what it was locked in at.

 

Have you tried the switch weapons with the Sling of Everaard. I remember having some problems with that item at one time.

 

Thanks,

Link to comment
Way back when someone came up with a way to switch items around reliably.  But it only worked with specific items, liking passing around a ring of regeneration. 

 

IIRC it involved the judicious use of DropItem, PickUpItem, FillSlot, and probably checks to make sure you have room in your inventory.

 

You do recall correctly - I remember that one too. It was a Ring of Regeneration and no, there was no empty slot check. JC was the author, I believe (no, not Jason Compton) ; the same guy that went on to develop the original teamwork scripts. I still have them somewhere.

 

-Y-

Link to comment

I ended up leaving the darts vs. shields alone, it simply wasn't worth the hassle/potential for disaster.

It was a fun attempt at cheating fate, even if it did fail in the end. :down:

 

[EDIT: I have the code for taking/reacquiring/reequipping items down fairly well in BP-weidu's Improved Spellhold component. I use it to both take away party items, and store them in a desk--and to give back the NPC "non-removable" items (Nalia's Ring, et al) It's appears to work in this context, at least--but hasn't withstood the rigors of time yet ;) .]

 

My work is pretty much done on thesescripts; I'm satisfied enough with their efficiency. After all, my goal here wasn't a complete remake--just a makeover.

I'm more than happy to share my results, if any deem them worthy---but I did it more for the learning experience. This was my first real dabbling in party AI. :D

 

I've moved on to the BPSeries, by seanas. These will be included in the BP-weidu package, so I have to pay closer attention to them. I'm sure you'll understand, I saved a couple parlor tricks for my own side show... :down:

 

P.S: Please tell me how/where to post them for everybody...this forum has no attachments that I can see. :devil:

 

P.P.S: But it "does" have some cool smiles... :)

Link to comment
I ended up leaving the darts vs. shields alone, it simply wasn't worth the hassle/potential for disaster.

It was a fun attempt at cheating fate, even if it did fail in the end.   :down: 

 

[EDIT: I have the code for taking/reacquiring/reequipping items down fairly well in BP-weidu's Improved Spellhold component. I use it to both take away party items, and store them in a desk--and to give back the NPC "non-removable" items (Nalia's Ring, et al) It's appears to work in this context, at least--but hasn't withstood the rigors of time yet  ;) .]

 

My work is pretty much done on thesescripts; I'm satisfied enough with their efficiency. After all, my goal here wasn't a complete remake--just a makeover.

I'm more than happy to share my results, if any deem them worthy---but I did it more for the learning experience. This was my first real dabbling in party AI.  :D

 

I've moved on to the BPSeries, by seanas. These will be included in the BP-weidu package, so I have to pay closer attention to them. I'm sure you'll understand, I saved a couple parlor tricks for my own side show...   :down:

 

P.S: Please tell me how/where to post them for everybody...this forum has no attachments that I can see.  :devil:

 

P.P.S: But it "does" have some cool smiles...   :)

 

Send em' my way Horred and I'll get them up. cirerrek@hotmail.com

 

Take a look at uScript, Gebhard Blucher's ToB scripts, for further research material. The uScript package is available here. http://www.gibberlings3.net/cirerrek/uscript.php

 

If you're into HotKey customization, I'd suggest taking a look at Ivann Alvarado's XpertAI for IWD. I've got a WeiDUized version that I've yet to upload. Get me an e-mail address if you are interested and I'll fire the package off to you.

 

Thanks,

Cirerrek

Link to comment

Archived

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

×
×
  • Create New...