Jump to content


  • Content Count

  • Joined

  • Last visited

Everything posted by Gimble

  1. I didn't know that: it would have been a help a month or two ago (before I wrote my own script-helping tools based largely on the C++ preprocessor). It wasn't the tedium that bothers me ( it's been "macroed" to be just a _IsImmune1() call ), but the performance hit at run time. User script check blocks are already long, and the extra string lookups and inventory checks for three items don't make things faster. I've moved them to be last in evaluation (since they rarely fail), but it's that programmer tendency to always want to optimize things that is just kicking in. I appreciate the help you've provided and all the work you've done. (Side question: is there a way to detect Vocalize? It dawned on me some things like Silence 15' Radius could be safely cast without range checks if Vocalize was already on the caster).
  2. Ah, well it was worth asking. One thought: would it make sense to change the behavior of the MINORGLOBE stat? All the script snippets I've seen to date have just checked for non-zero (a binary flag), which would still work if it were switched to mean immunity to spell level N and below.
  3. The range check can be removed from WIZARD_SLEEP. After doing some things with WIZARD_COLOR_SPRAY lately, though, I found that its range is very considerable. As a result, it's not really possible to range check for WIZARD_COLOR_SPRAY that party members aren't too close... so it probably shouldn't be moved there.
  4. I'm not sure it belongs in this forum, but I've loaded a piece of SCS just for doing user scripting. A big annoyance for user scripting is the "immunity to spell level" checks, as they require tests like the following: !CheckStatGT(LastSeenBy(Myself),0,MINORGLOBE) !HasItemEquiped("RAKRING",LastSeenBy(Myself)) // Immune to 8th and below !HasItemEquiped("LICH",LastSeenBy(Myself)) //Immune to 5th and below !HasItemEquiped("MAGEAMUL",LastSeenBy(Myself)) // Immune to 3rd and below Instead, if there was a IMMUNE_TO_SPELL_LEVEL_AND_BELOW stat (and items and spells modified), it could be simplified to something much simpler, like: CheckStatLT(LastSeenBy(Myself),3, IMMUNE_TO_SPELL_LEVEL_AND_BELOW ) ... or at least, that's what I think could be done.
  5. That could be done, when coupled with a local variable to denote the timer was started. It's a slight performance penalty because of string checks, but probably doable. I haven't had any problems with the StartTimer(s) just because they're very transient and are just used to interrupt continuous actions in progress: something that is (automatically) interrupted during program loads and frequently during saves. If I encounter any problems, I'll use that as a fallback position. Thanks for the thought.
  6. After typing "continuous action timer"several times, I've decided to abbreviate it to CAT for this post at least. I believe so. I'm compiling my user scripts to .bcs ( I have a slot-loading system, with the user script loading position & class specific scripts in the RACE and GENERAL slots ), and so far in testing I have been... very happy with the results. The follow and move to combat code works like a charm, once I converted to MoveToObject() with a range check from FollowObjectFormation(). I had already worked out a solution for stealth / search combinations that does pretty well, and the BardSong ability actually works as stolen from the eSeries (with a Delay(2) IIRC). Attack() as mentioned above works like a charm. Since I also set a second CAT on spellcasting, it also makes "cast and attack" work: the Attack() action will also be broken whenever the spell CAT expires. Overall, I'm very happy with how the user scripts work with this model. The biggest problem is right after the end of combat: for a round or so, you still get expiring CATs. This makes looting a little annoying, because looting is also apparently a continuous action timer and can be broken by an expiring timer. You kill the last dude, click on the loot, and usually manage to walk to the corpse and open the container to loot. Then, the CAT expires from the last Attack(), and the container closes again... and you're standing on top of the loot. So, you have to either right-click into inventory, or move away and come back to the container to get the stuff. Yes, just a few second delay before you start looting avoids the whole mess, but I was surprised at how ingrained that natural "combat is over, let's start looting!" behavior is in my personality at least.
  7. Stupid question from a newbie: could you separate out this new functionality into a meta-tool that would translate your new user-readable stuff into raw Weidu-code, and then distribute that generated Weidu code as a way to reduce installation overhead? I more or less did that in my user-scripting land: I have a "C" style preprocessor that parses a BAF file ( with extra #includes, #defines, etc.) and generates a .BAF file as output, that I then hand off to Weidu for compiling. It's not a perfect solution but it does 90% of what I want, and doesn't pollute the Weidu language namespace with a different model. Even more cool would be something that would take an existing Weidu script and reverse-engineer it back into user-readable stuff. I don't do anything but AI scripting, but I can say if I were ever willing to take on modding, the stuff you have proposed is far more accessible than the raw data. I may be a good coder (I hope so, I get paid to do it), but I really don't relish grokking other people's Weidu ugliness to learn how to do basic modding. Yes, I'm lazy. It's part of not having a lot of free time to work with.
  8. Code first. Moderators, please move if in wrong forum. IF TimerExpired(11) // Continuous action timer THEN // Continuous actions, like Attack() or FollowObjectFormation() // has been running for a while. We want to break the continuous // action without aborting anything else that might be going on // instead (e.g. a user-selected and cast spell, for example). // Experimentation seems to indicate that starting a timer is // sufficient to break the continuous action without disrupting // useful activities. RESPONSE #100 StartTimer(12,6) // Timer 12 unused, just started to break the continuous action END IF ActionListEmpty() Range(Player2,0) !See(NearestEnemyOf(Myself)) !See([EVILCUTOFF]) THEN RESPONSE #100 StartTimer(11,2) // Start the continuous action timer FollowObjectFormation(Player1,3,2) END IF ActionListEmpty() OR(2) See(NearestEnemyOf(Myself)) See([EVILCUTOFF]) THEN RESPONSE #100 StartTimer(11,6) // Start the continuous action timer Attack(LastSeenBy(Myself)) END A lot of the AI Scripting code easily findable is geared towards monster AI (don't have to deal with user input). For user scripts, you have to do your best to avoid stopping an action the user requested. However, the two common methods used for attacking ( AttackOneRound() and AttackeReevaluate() ) are both known to have issues from posts gathered here and elsewhere. It's frustrating to watch a user script sit there, attack foes, but not actually get an attack role for some percentage of the time. The above code is something I figured out yesterday as an acceptable solution. Continuous actions (like Attack() ) are broken by almost any script action, including setting timers or globals. However, most "valuable" actions like casting spells are not broken by some actions. As a result, a local timer becomes an easy way to interrupt a continuous action without interrupting an overridden action. Early testing seems very promising: with my AI script (larger than the sample): the team follows the leader, attacks when in range, and I can override with spells or movement from the keyboard without issue. Hope this helps!
  9. I like the idea in general, although you would need to provide some basic equipment at the beginning of the catacombs, to not greatly handicap non-spellcasting parties. One way to give the player access to the items would be to add dialog to the guard outside Candlekeep. Unknown to CHARNAME (until now), he also runs a smuggling operation in and out of Candlekeep, and willing to smuggle items (including claimed equipment) out of Candlekeep to the PC for an appropriate bribe. The dialog could get wordy, though, unless there's a way to add the items via script to a custom Store the guard has access to (in which case it might be fairly easy to implement).
  10. From my limited understanding of bears, when angry they actually can be (for short periods of time) a fair amount faster than an equivalent human, although their normal pace is rather slow. If someone is bored enough, I would hope it would not be difficult to create an innate Rage like ability for bears, that they could trigger (via script) in combat, increasing their speed to wolf-like speed (I think wolves are a little faster than people) for a short period of time ( perhaps 10 rounds ). I would think the bear would fire the ability when AttackedBy([ANYONE],DEFAULT). But I've not done anything but AI Script modding so I don't know how practical this might be.
  11. Playing with the eSeries on BGT, I found that WIZARD_SLEEP does not fire. The offending script code is as follows: OR(2) Range(Player1,0) //Either I'm Player1 CheckStatGT(Player1,5,LEVEL) // or they're high enough to be immune to this OR(2) Range(Player2,0) //Either I'm Player2 CheckStatGT(Player2,5,LEVEL) // or they're high enough to be immune to this OR(2) Range(Player3,0) //Either I'm Player3 CheckStatGT(Player3,5,LEVEL) // or they're high enough to be immune to this OR(2) Range(Player4,0) //Either I'm Player4 CheckStatGT(Player4,5,LEVEL) // or they're high enough to be immune to this OR(2) Range(Player5,0) //Either I'm Player5 CheckStatGT(Player5,5,LEVEL) // or they're high enough to be immune to this OR(2) Range(Player6,0) //Either I'm Player6 CheckStatGT(Player6,5,LEVEL) // or they're high enough to be immune to this I suggest moving the above code block from the WIZARD_SLEEP block to the WIZARD_COLOR_SPRAY block. WIZARD_SLEEP affects enemies only, so the check is not necessary. WIZARD_COLOR_SPRAY, however, can affect party members, so the check would be helpful to be added (to avoid blasting fellow party members). I'm aware this is pretty much a non-issue in Amn and ToB, but for BG1 Sleep is a great spell and this simple change should make it more usable.
  12. Another note about TakePartyItemNum: If done within the party, the following seems to happen (assume 'source' and 'destination' are both in the party, and may or may not be the same person): With TakePartyItemNum("foo",1): Source has a stack of 'N' items replaced by 'N-1' items. Destination is given a stack of 'N-1' items. Note that this is patently wrong: Taking one goodberry from a stack of 10 results in two stacks of nine, even if the party only has one member. Talk about magical!
  13. Slot clarifications to SLOTS.IDS, based on testing. I isolated the main inventory slots by row and column (and verified the quick slots locations), using user script. A note about XEquipItem: if on an equip request the destination is filled, it merely swaps the location of the two items. This can be benign or disasterous, depending on if the swapped source is an invalid location for the item. 15 SLOT_QUICK_1 16 SLOT_QUICK_2 17 SLOT_QUICK_3 18 SLOT_MISC_R1_C1 19 SLOT_MISC_R2_C1 20 SLOT_MISC_R1_C2 21 SLOT_MISC_R2_C2 22 SLOT_MISC_R1_C3 23 SLOT_MISC_R2_C3 24 SLOT_MISC_R1_C4 25 SLOT_MISC_R2_C4 26 SLOT_MISC_R1_C5 27 SLOT_MISC_R2_C5 28 SLOT_MISC_R1_C6 29 SLOT_MISC_R2_C6 30 SLOT_MISC_R1_C7 31 SLOT_MISC_R2_C7 32 SLOT_MISC_R1_C8 33 SLOT_MISC_R2_C8 34 SLOT_MISC_R3_C1 35 SLOT_MISC_R3_C2 36 SLOT_MISC_R3_C3 37 SLOT_MISC_R3_C4 38 SLOT_MISC_R3_C5 39 SLOT_MISC_R3_C6 40 SLOT_MISC_R3_C7 41 SLOT_MISC_R3_C8
  14. I believe it's noted elsewhere, but the AI scripting for PCs does not run constantly. Particularly when you interactively move a character ( click on them, click on destination to walk to ), their script does not run during the move itself, or for a few seconds afterwards. This means that PC-based scripts in IWD2 have a significant disadvantage, as they don't "fire" right at the start of combat -- though the enemy monster AI does. As a result, you can have a swarm in your face before the first PC AI script action occurs.
  15. Thanks, Yovaneth. I hadn't gotten around to Hide-n-Search yet, and I'll put it on my really low-priority list of things to look at (I now expect failure). More notes: 215 FollowObjectFormation(O:Object*,I:Formation*,I:Position*) isn't in ACTION.IDS, but works fine. Useless for PC scripting as best I could tell, though, because there's no good way I could find to 'break' back into script when something valuable happens (e.g. monsters ). MoveToObject works fine for that, though. You can use it with an additional IF check that breaks the movement. However, don't expect fine-grained control here: between AI cycles your guy can move several circle-widths ( 5-10' in game terms? ). MoveToObject is unacceptable without a code check for breaking the move. Otherwise, the followers are constantly 'shoving' the leader forward as they push into them. I imagine this is really, really bad if you're close to traps or enemies, for example. Annoying, and important to remember, is that PC script slots one and two (and presumably zero) are not stored in the save file. If you save your game, with scripts in every slot, and then examine the save game, slots 3-5 will still be populated with the right script names, but slots 1 and 2 will be empty ("None" in Beyond Infinity terms).
  16. New annoyances. The Paladin description doesn't mention anything about Protection From Evil, but any Paladin gets one (and only one, as best I can tell) innate PFE spell. Also, no mention of the spell in SPELL.IDS (so I added, see above). The FindTraps() action doesn't work for a number of classes- I tested Paladin, Monk, Barbarian, Cleric, Druid, Wizard. Of those six, only the Monk would enable Search via script (the FindTraps() call). It's my strong suspicion that only rogue-like classes ( Rogue, Monk, Bard ) have this functionality enabled. To my surprise, even characters with "paid-for" skill points apparently may not be access their class abilities via the menus, much less script. I have a first-level Wizard with two purchased cross-class points in Disable device, and the unlock icon is "greyed out" when he selects the skill: so he is unable to unlock anything despite having bought points in the ability.
  17. It seems like it. As best I can tell, MSAO was built on an as-needed basis. Since AI scripts use few (if any) buffs, a lot of the buff triggers were ... less well done. I'll know more about the offensive spells once I get into them. MarkSpellAndObject, like everything else in IWD2, has some really great things to it and some very bizarre behaviors as well. I'm still sorting those through in my head. Getting closer to proof of concept, though.
  18. CheckSpellState and probably others rely on MultiPlayerSync() during buffing to get things right in a multiplayer game. Otherwise, if you're buffing another character, you very well may miss their spell state and cast on them repetitively.
  19. Enumerations added to SPELL.IDS: 3152 INNATE_SMITE_EVIL 3121 INNATE_PROECTION_FROM_EVIL Edit: Converted to list and added entry
  20. For some reason, CLERIC_HOLY_AURA is broken. It always fails the IsSpellTargetValid(Myself,CLERIC_HOLY_AURA,0) check. Also, MarkSpellAndObject will always fail to select the spell unless the SPELLCAST_IGNORE_VALID_SPELL_TARGET flag is set. Suggestions are welcome. Edit: CLERIC_MAGIC_RESISTANCE has the same problem. I suspect it has something to do with the spell setting resistance levels. We'll see when I get to other SR spells.
  21. Oh, a brief rant about spell durations. As I've long suspected (but not proven until now), a "minute" in a spell description is a very nebulous term. In various spells, a "minute" might mean a round, 2 rounds, three rounds, or even 10 rounds. An example of each: BLESS : Description says "one minute per level", spell does ten rounds per level SPELL RESISTANCE : Description says "one minute per level", spell does three rounds per level PROTECTION FROM EVIL : Description says "one minute per level", spell does two rounds per level REMOVE FEAR : Description says "ten minutes", spell does ten rounds
  22. Near Infinity apparently will corrupt a spell on occasion after editing if you've added an extra effect in a way it's not happy with. Still, overall it's a great tool. Tread carefully, and make changes in small increments! I'll be waxing eloquent before too long about the wonders of the MarkSpell system. Before I do so, though, let me give a warning. On occasion, MarkSpellAndObject with multiple selectable spells (at least in my usage) on a Sorceror will decrement an incorrect spell level. It's my guess that the level being wrongly decremented is the level of the first spell on the MSAO list. *Edit* After some time away and rest, I realize that my strange spell counts may be attributable to the effects of expiring/non-expiring Eagle's Splendor and the presence of multiple characters with similar spell sets, all performing buffs. More investigation is needed, but I think I cried "foul" too quickly this time.
  23. Spells not safe without extra checks for MarkSpellAndObject (See below): CLERIC_ANIMAL_RAGE -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPPR517 CLERIC_AURA_OF_VITALITY -- Use !CheckSpellState(Myself, AURA_OF_VITALITY) REQUIRES MODIFICATION OF SPELL SPPR729 and SPLSTATE.IDS CLERIC_AID -- Use !CheckSpellState(Myself, AID) CLERIC_BEAST_CLAW -- Use !CheckSpellState(Myself, SUMMONED_WEAPON) REQUIRES MODIFICATION OF ITEM BCLAW and SPLSTATE.IDS Done to prevent double-casting and also to start a spell state to keep someone with one summoned weapon from summoning another one. CLERIC_BLESS -- Use !CheckSpellState(Myself, BLESS) . Caliban's note in iwd2_scripting_info.txt is correct. CLERIC_CHAMPIONS_STRENGTH -- Use !CheckSpellState(Myself, CHAMPIONS_STRENGTH) REQUIRES MODIFICATION OF SPELL SPPR507 CLERIC_EXALTATION -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPPR316 CLERIC_HOLY_AURA -- Requires SPELLCAST_IGNORE_VALID_SPELL_TARGET as a flag to MarkSpellandObject. Use CheckStatLT(Myself,25,RESISTMAGIC) for detection if you don't want to modify the spell. CLERIC_IMPERVIOUS_SANCTITY_OF_MIND -- Use !CheckSpellState(Myself, IMPERVIOUS_SANCTITY_OF_MIND) REQUIRES MODIFICATION OF SPELL SPPR716 and SPLSTATE.IDS CLERIC_IRON_SKINS -- use CheckStatLT(Myself,1,STONESKINS) CLERIC_MAGIC_RESISTANCE -- Requires SPELLCAST_IGNORE_VALID_SPELL_TARGET as a flag to MarkSpellandObject. Use CheckStatLT(Myself,21,RESISTMAGIC) for detection if you don't want to modify the spell. CLERIC_NEGATIVE_ENERGY_PROTECTION -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPPR326 CLERIC_PRAYER -- use !CheckSpellState(Myself,BENEFICIAL_PRAYER) CLERIC_REMOVE_FEAR -- Use !CheckSpellState(Myself, REMOVE_FEAR) REQUIRES MODIFICATION OF SPELL SPPR108 and SPLSTATE.IDS WIZARD_CATS_GRACE -- Use !CheckSpellState(Myself, CATS_GRACE) WIZARD_DEATH_ARMOR -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPWI214 WIZARD_MIND_BLANK -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPWI804 WIZARD_MINOR_GLOBE_OF_INVULNERABILITY -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPWI406 WIZARD_STRENGTH (Bull's Strength) -- Use !CheckSpellState(Myself, CHAMPIONS_STRENGTH) REQUIRES MODIFICATION OF SPELL SPWI214 WIZARD_PROTECTION_FROM_PETRIFICATION -- Missing SetState on spell. REQUIRES MODIFICATION OF SPELL SPWI108 Additional entries added here as discovered MarkSpellAndObject is supposed to check for possible target validity. However, not all necessary checks are made, and as a result, you may have to do additional checking prior for MSAO for some spells. The above is just a (evolving) list of spells I've verified that are not properly state-checked.
  24. More snippets: The StrongestOf seems to apply to the party member with the most experience points. In my test game, StrongestOf selected my Sorceress 11/Paladin 2/Rogue 1 character, while bypassing my Paladin 2/Fighter 11 (most hitpoints, most BAB) and pure Sorceress 14 (more and higher level spells). HasItemEquiped seems to work just like HasItem: it resolves to true if the item is in the player inventory. I may edit this post and add more minor discoveries here. (And Yovaneth, thanks for the confirmation. I walk away from IWD2 every so often for a few months or years until I just can't help it.) As a side note, I'll probably post soon some findings about MarkedSpell and spell selection. While scripting for IWD2 is rather different than the other IE engines, I'm finding it a little easier to script massive spell lists than I have the other engines.
  25. New thing: CheckStat(Myself,*,ARMORCLASS) seems to crash the game. I'm a little confused, since the i2Series scripts uses it (actually, CheckStatGT(), but I've tested both), but I can say any attempt to look at the ARMORCLASS stat results in a game crash. IF CheckStatGT(Myself,6,ARMORCLASS) THEN RESPONSE #100 NoAction() END In my IDS file, ARMORCLASS maps to 2. If someone has an explanation, I'd love to hear it.
  • Create New...