Jump to content

Need Script Help For IWD: II


Meanfred

Recommended Posts

Greetings Gibberlings, I must admit I am pretty handy with a computer but when it comes to things like scripting AI, I am a little slow off the mark. I have read a few How-To's and Tutorials and I still don't have a strong grip on how to write my own custom character AI scripts.

 

So I figured since I came here before to get a script written by one of the kind G3 members that had some extra time, that I might as well try my luck again.

 

There are pretty much two scripts I am in need of. If you have to pick one to write for me then my priority would be the Sorcerer script. Both scripts need to be compatible with Icewind Dale II.

 

#1. A basic Sorcerer combat casting script ( That doesn't cast Mage Armor over and over and over ).

 

#2. A basic Mage/Cleric script that casts basic Cleric spells and focuses mainly on offensive Mage spells.

 

I would like to thank you all ahead of time for any help that you can muster up for me, because I want the G3 community to know that their work is very much appreciated and it is something I definitely do not take for granted. Thanks again everyone, have a great day!

 

 

PS: I have downloaded and tested the existing outdated Beta scripts for IWD: II, and all they did was make my Sorcerer cast Mage Armor repeatedly and die.

Link to comment

Well, since there isn't an easy way of checking if you have something up, you can use globals to make sure you cast a spell when needed, and a timer if you want to keep it up constantly.

 

So,

IF
 HasSpell(Myself,MAGE_ARMOR)
THEN
RESPONSE #100
 Spell(Myself,MAGE_ARMOR)
END

//this will continue casting the 1st level spell Armor over and over and over again until you run out of Armor spells.
//Instead, we use a global timer of 8 hours to keep it running constantly, not that an enemy will ever last that long

IF
HasSpell(Myself,MAGE_ARMOR)
RealGlobalTimerExpired("hasArmor","LOCALS")
THEN
RESPONSE #100
 Spell(Myself,MAGE_ARMOR)
 RealSetGlobalTimer("hasArmor","LOCALS",720) //I use RealGlobalTimers because I can't think in in-game time.
END
//Timers are set by script runs, which is approximately 15 a second, so 720 SHOULD be 8 in-game hours.
//This script will cast one Armor spell every 8 hours, if it has one left. Sure, this isn't the most intelligent way of doing it,
//because the AI can't tell if it is dispelled or not, without something like Detectable Spells, which is a pain to implement.

 

I apologize if there is any needed conversion between BGII and IWDII, because I don't own or write for IWDII.

 

Icen

Link to comment

*Modding Newbie Here*

 

Ok let me try to get this sorted out.

 

The script you just posted is not another script, but if I put it into my sorcerer script it will make him stop spamming mage armor over and over?

 

If I'm wrong let me know. I am a little confused.

 

And if I'm right, then should I just copy and paste this into the script file?

 

 

Thanks for your time in trying to help me get my game going, I greatly appreciate your time and effort, as I am a player that considers the AI essential ( I like to play my main character alone so that I feel like I am actually with a party of other people. Without the AI it just feels like I'm playing with copies of myself ). So you're help is really doing more for me than you think since I appreciate what people do for me unlike 70% of America at large today. Later Days! :)

Link to comment
The script you just posted is not another script, but if I put it into my sorcerer script it will make him stop spamming mage armor over and over?
Yes and no.

 

The code he posted is an example of how to change from the code that 'spams' into code that will prevent the actor from repeatedly casting the same spell over and over (until they run out of that spell).

 

If you take the second script block (the one that contains the timer) and put that in your ai script then it should do the trick with regards to the mage armor spell.

 

Although I'd also put in a CheckStat for Armor Class level so that Bards who have the spell memorized don't cast the spell if they are wearing armor that sets their Armor Class at something better than what the spell would do. Reason: The spell sets the actors AC to a specific value even if their current value is better.

 

Here's an example from my IWD1 script:

IF
 ActionListEmpty()									 //not doing anything
 !See([ENEMY])										 //don't see any enemy
 HaveSpell(WIZARD_ARMOR)							   //have spell
 CheckStatGT(Myself,6,ARMORCLASS)					  //my armor class is greater than 6
 CheckStatLT(Myself,50,SPELLFAILUREMAGE)			   //have a good chance of casting the spell
 !StateCheck(Myself,STATE_NOT_VISIBLE)				 //not in hiding
 GlobalTimerExpired("ab_cast_a_spell","LOCALS")		//local timer for any spells
 GlobalTimerExpired("ab_armor","LOCALS")			   //spell wore off
THEN
 RESPONSE #100
SetGlobalTimer("ab_cast_a_spell","LOCALS",7)		//start personal timer
SetGlobalTimer("ab_armor","LOCALS",3780)			//spell length timer
Spell(Myself,WIZARD_ARMOR)						  //cast spell
END

I got my timer length by opening the spell file in DLTCEP and looking at the duration value for the opcode that adjusts the AC value. You'll want to check your game and see if it is different.

You can copy the above and replace the offending code in your script and it will do what you want, but please change the timer names to something specific to what you are doing. 'ab' is my registered prefix and that at least should be changed...

 

I've not installed IWD2 yet. I can it is sitting on my shelf. I'm sure I could help out a little here and there without spoiling the game too much. You'd have to do the testing though. I don't have that kind of time with all the other irons on the fire....

Link to comment
The script you just posted is not another script, but if I put it into my sorcerer script it will make him stop spamming mage armor over and over?
Yes and no.

 

The code he posted is an example of how to change from the code that 'spams' into code that will prevent the actor from repeatedly casting the same spell over and over (until they run out of that spell).

 

If you take the second script block (the one that contains the timer) and put that in your ai script then it should do the trick with regards to the mage armor spell.

 

Although I'd also put in a CheckStat for Armor Class level so that Bards who have the spell memorized don't cast the spell if they are wearing armor that sets their Armor Class at something better than what the spell would do. Reason: The spell sets the actors AC to a specific value even if their current value is better.

 

Here's an example from my IWD1 script:

IF
 ActionListEmpty()									 //not doing anything
 !See([ENEMY])										 //don't see any enemy
 HaveSpell(WIZARD_ARMOR)							   //have spell
 CheckStatGT(Myself,6,ARMORCLASS)					  //my armor class is greater than 6
 CheckStatLT(Myself,50,SPELLFAILUREMAGE)			   //have a good chance of casting the spell
 !StateCheck(Myself,STATE_NOT_VISIBLE)				 //not in hiding
 GlobalTimerExpired("ab_cast_a_spell","LOCALS")		//local timer for any spells
 GlobalTimerExpired("ab_armor","LOCALS")			   //spell wore off
THEN
 RESPONSE #100
SetGlobalTimer("ab_cast_a_spell","LOCALS",7)		//start personal timer
SetGlobalTimer("ab_armor","LOCALS",3780)			//spell length timer
Spell(Myself,WIZARD_ARMOR)						  //cast spell
END

I got my timer length by opening the spell file in DLTCEP and looking at the duration value for the opcode that adjusts the AC value. You'll want to check your game and see if it is different.

You can copy the above and replace the offending code in your script and it will do what you want, but please change the timer names to something specific to what you are doing. 'ab' is my registered prefix and that at least should be changed...

 

I've not installed IWD2 yet. I can it is sitting on my shelf. I'm sure I could help out a little here and there without spoiling the game too much. You'd have to do the testing though. I don't have that kind of time with all the other irons on the fire....

 

 

Ok, trying to learn this and be as productive as possible. So to replace the offending script with the one above, I need to open the script in the DLTCEP utility and then search for which line holds the code that adjusts AC value, and add a timer?

 

Also what do you mean by adding that little prefix "ab_"? I know that's your personal prefix but what is it for anyway? Is it needed? Is there something specific I need to change it to?

 

I'm sorry, Im a slow starter but once I get rolling I master things quickly. Once again I appreciate you all taking the time to help me write a basic non-handicapped sorcerer script. I really need to take a programming class some day soon. Thanks guys. Later Days.

Link to comment
Ok, trying to learn this and be as productive as possible. So to replace the offending script with the one above, I need to open the script in the DLTCEP utility and then search for which line holds the code that adjusts AC value, and add a timer?
I'd use NearInfinity because it's native ability to edit scripts works 'out of the box' so to speak. DLTCEP requires setting it up to communicate with weidu before it works. If you've already done that and have successfully opened/edited scripts in DLTCEP then you can go ahead and use it if you prefer.

 

What you'll want to look for in the script is the block that contains the action Spell(Myself,WIZARD_ARMOR). Then you can add the timer actions and trigger checks to that block. But before you do, make a backup copy...

 

Also what do you mean by adding that little prefix "ab_"? I know that's your personal prefix but what is it for anyway? Is it needed? Is there something specific I need to change it to?
You don't need it. I just was letting you know that you should not use it. You can use whatever you want as your global timer name. There is an upper limit to the number of characters allowed. I believe it is 32 most people keep it around 18 though. It is a good idea to use a prefix that is unique to you. If you didn't (it's rare but possible) then you could get into conflict with a mod somewhere that choose to use the same timer name.

 

I'm sorry, Im a slow starter but once I get rolling I master things quickly. Once again I appreciate you all taking the time to help me write a basic non-handicapped sorcerer script. I really need to take a programming class some day soon. Thanks guys. Later Days.
No problem. I'm glad to help. I'm still learning things myself and re-learning things too.

 

 

I just downloaded and looked at the beta iseries...

here is the script block that uses the spell in question

IF
 !TimerActive(201)
 Or(2)
ActionListEmpty()
TimerActive(200)
 GlobalGT("gh_ThreatLevel","LOCALS",0)
 See(NearestEnemyOf(Myself),0)
 Or(2)
NumCreatureGT([EVILCUTOFF],2)
Range(NearestEnemyOf(Myself),6,LESS_THAN)
 HaveSpell(WIZARD_ARMOR)
 IsSpellTargetValid(Myself,WIZARD_ARMOR,0)
THEN
 RESPONSE #100
FloatMessage(Myself,12031)  // ~Mage Armor~
StartTimer(201,7)
Spell(Myself,WIZARD_ARMOR)
WaitAnimation(Myself,WALK)
WaitAnimation(Myself,CONJURE)
WaitAnimation(Myself,CAST)
END

As you can see there is a timer, but it is only a simple one round timer to prevent casting the same spell within the same round. There is no armor check. You can modify this block as follows (and hopefully it will work for you):

IF
 !TimerActive(201)
 Or(2)
ActionListEmpty()
TimerActive(200)
 GlobalGT("gh_ThreatLevel","LOCALS",0)
 See(NearestEnemyOf(Myself),0)
 Or(2)
NumCreatureGT([EVILCUTOFF],2)
Range(NearestEnemyOf(Myself),6,LESS_THAN)
 Or(2)
CheckStatGT(Myself,6,ARMORCLASS)					  //my armor class is greater than 6
GlobalTimerExpired("ab_wizard_armor","LOCALS")		//spell wore off
 HaveSpell(WIZARD_ARMOR)
 IsSpellTargetValid(Myself,WIZARD_ARMOR,0)
THEN
 RESPONSE #100
SetGlobalTimer("ab_wizard_armor","LOCALS",3780)	 //spell length timer
FloatMessage(Myself,12031)  // ~Mage Armor~
StartTimer(201,7)
Spell(Myself,WIZARD_ARMOR)
END

What I did was (I hadn't thought of it before) put the timer check AND the armor class check inside an Or check which means that the spell will be cast whenever the actor's armor level is worse than the level that the spell sets it to OR whenever the timer runs out (i.e. the spell has worn off). This would take into account the possibility of the armor being dispelled by an enemy spell caster. But it still prevents the actor from repeatedly casting the spell until there are no more spells.

I'm not too sure why there are those WaitAnimation() actions. Doesn't make sense to me as the target of the spell is the same as the actor. There is no need to wait, just do it. I think it might be safe to remove those lines so I dropped them from my example.

 

It may be better for you if you started from scratch and built your own script rather than using another script as a base to start with. Certainly look at other scripts to see how they are setup, but write your own script. Why? If you write your own, then the actors will do only those things that you have scripted and nothing else. This means that you will know with certainty whether or not they are doing what you want them to do correctly or not. If you build on someone else's script, your changes may or may not work with how it was designed...

 

Making my own script was how I got started with modding and I learned right away that putting together piece by piece in a new script was best for me both in testing and in understanding what was going on...

 

Before you make this change, check your action.ids file and your trigger.ids file and see if the GlobalTimerExpired and SetGlobalTimer are in there. The SetGlobalTimer would be in the action.ids file and the GloablTimerExpired would be in the trigger.ids file. If they aren't that might be why the beta iseries uses the StartTimer action and TimerActive trigger. If you don't have the GlobalTimer actions and triggers, then replace them with a StartTimer(Identifying Timer #,Length of time) and !TimerActive(Identifying Timer #). If you need to use the simple timer method go with a high # to identify the timer with. I'd start with 5000 or something since I don't know what number the game uses.

 

Hope I'm not drowning you with too much information....

Link to comment

You are definitely NOT drowning me with info, if anything this is the best help I've ever had on a forum without having to pay someone for programming lessons. I want to write my own scripts! That's my first and foremost goal as a new modder. I guess I just need to read the scripting tutorials over and over again until it clicks for me.

 

Also I would like to thank you for taking the time to download the iseries beta scripts. I didn't even tell you that was the script I was working with and you knew right away which was the offending code. You are a very bright and intuitive person. I am going to go download Near Infinity and see if I can use your instructions to modify the script. As you said, first I will go check in the trigger and actions files for the correct timers. Gah, I probably sound like a moron. >_<

 

Anyway, I just wanted to say I greatly appreciate your effort and time you put into this. I didn't expect such a full response. I expected a bunch of little responses that I was going to have to piece together into the answer I was looking for. So thanks again. I'll be back to let you know if everything worked out.

 

 

PS: My online times have been kind of weird lately due to my life being a bit busier lately than it usually is so I'm sorry for the slow replies. Have a nice weekend! Later Days.

Link to comment
My online times have been kind of weird lately due to my life being a bit busier lately than it usually is so I'm sorry for the slow replies.
No worries. We all have personal lives. Just post if you have any more questions. I'll be glad to help if I can.

 

To help you out: Go here to download Near Infinity. It requires Java to run so make sure you're up to date on that as well (as up to date as your computer can run at least).

Link to comment

Archived

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

×
×
  • Create New...