I am currently rebuilding my mage scripts with Spell Revision in mind.
I have many scripts, for each class and eventually for some kits if necessary. On top of that, for spellcasters, I do a script for each new spell level.
It is easier to select spell order this way, and depending on level, spell order can change. For example, magic missile is rather weak at level 1, but become great later on.
I have added doom to detectable spells. Priest will now cast doom before casting another spell.
For example, he want to cast hold spell. He checks a valid target (not disabled), then he checks a valid target affected by either Doom or Greater Malison.
If he found a target affected by doom, he cast hold. If not and if he has doom, he will cast it before hold.
This way, he makes a good use of doom spell. In fact, he will try to focus all spells after that. Doom can be seen as "focus on him". Althrough, target must be fill other criteria (like not beeing disable, ...)
By now, I have only done a few scripts : fighter (only one script) and druid level 1, 3, 5, 7.
I am testing druid script with Seniyad and Amarande and I am satisfied with current results.
I have tested SCS for these foes and don't like it at all. Yes, they are powerful and it is well done but there are several things I don't like:
- spellbooks are generated. It reminds me my old generator
It is a good way to quickly do all casters but it is a lot better to make a custom spellbook for each caster.
- scripts still cheat in some ways. Some spells are cast even if not memorized (Detect invisibility for example)
- scripts do many check for each spell : resistances, immunity... some may like it, some don't. I have added all checks in my mod, but they all depend on a parameter, it can be enable or disable.
It will take me some time to do all scripts. Cleric will be very closed to druid so it will be quick.
But mages are huge ! mage, bard, wild mage on one set, then all others on separate set.
Sorcerer will be the hardest and I don't know yet if I will put on them in game. My editor can build a sorcerer spellbook but I need a script dedicated and efficient.
Initially, I will do script to spell level 6 as it covers most spell casters. Then, I will add others when needed.
Below an example of a script before baf generation.
Java program uses an ini file for a few parameters and IMMUNITY_CHECK is one of them.
Globally, it is quite simple but the job is done.
CODE
// Druid
[CASTER=PRIEST]
[include=init_npc]
[include=tracking]
[include=potions]
[include=disable_spellcasting]
//[include=shapeshift_druid]
// Improved Invisibility
[action=SPELL(SPDR401,,75,notarget);require=*visible]
// Gust of Wind
[action=SPELL(SPPR318,,75,notarget,hit);require=range(6,attacker)]
// Cloak of Fear
[action=SPELL(CLERIC_CLOAK_OF_FEAR,,75);target=NearestEnemy(num:6);require=range(6),!disable,!fearImmunity]
// Neutralize poison
[action=SPELL(CLERIC_NEUTRALIZE_POISON,,,notarget);require=*state(STATE_POISONED)]
// Slow Poison
[action=SPELL(CLERIC_SLOW_POISON,,,notarget);require=*state(STATE_POISONED)]
// Cure Critical Wounds
[action=SPELL(CLERIC_CURE_SERIOUS_WOUNDS,,,notarget);require=*hp%lt(70),OR(*sanctuary,!seeEnemy,!hit)]
// Cure Moderate Wounds
[action=SPELL(SPPR215,,,notarget);require=*hp%lt(80),OR(*sanctuary,!seeEnemy,!hit)]
// Cure Light Wounds
[action=SPELL(CLERIC_CURE_LIGHT_WOUNDS,,,notarget);require=*hp%lt(90),OR(*sanctuary,!seeEnemy,!hit)]
// Strength of One
[action=SPELL(CLERIC_STRENGTH_OF_ONE,,75,notarget)]
// Death Ward
[action=SPELL(CLERIC_DEATH_WARD,,75,notarget)]
// Free action
[action=SPELL(CLERIC_FREE_ACTION,,75,notarget)]
// Woodland beings
[action=SPELL(CLERIC_CALL_WOODLAND_BEINGS,,75,notarget)]
// Animal Summoning 1
[action=SPELL(CLERIC_ANIMAL_SUMMONING_1,,75,notarget)]
// Totemic animals
[action=TIMER(ja#totemic,30),SPELL(SPCL621,,50,notarget)]
// Web
[action=SPELL(SPDR201,,75);require=!disable,!magicImmunity,!globe,!holdImmunity]
// Entangle
[action=SPELL(CLERIC_ENTANGLE,,75);target=NearestEnemy(num:5);require=!disable,!magicImmunity,!globe]
// Ice Storm
[target=Summon(num:5);require=valid,!magicImmunity,!coldImmunity]
[action=SPELL(SPPR418,,75);target=Player;require=*resistCold,!magicImmunity,!coldImmunity]
// Fire Trap
[target=Summon(num:5);require=valid,!magicImmunity,!fireImmunity,!globe]
[action=SPELL(SPPR216,,75);target=Player;require=!magicImmunity,!fireImmunity,!globe]
// Dispel Magic
[action=SPELL(CLERIC_DISPEL_MAGIC,,75),RUN(30);target=Player;require=enchanted,!range(15)]
// Storm shield
[action=SPELL(SPPR322,,75,notarget)]
// Charm Person or Animal
[target=Fighter;require=valid,!disable,!magicImmunity,!globe,!charmImmunity]
[target=Fighter;require=valid,!disable,!magicImmunity,!globe,!charmImmunity,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!disable,!magicImmunity,!globe,!charmImmunity]
[action=SPELL(CLERIC_CHARM_PERSON,,75,fighter);require=!disable,!magicImmunity,!globe,!charmImmunity]
// Hold Person or Animal
[target=Player;require=!disable,!magicImmunity,!globe,!holdImmunity]
[target=Player;require=!disable,!magicImmunity,!globe,!holdImmunity,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!disable,!magicImmunity,!globe,!holdImmunity]
[action=SPELL(SPPR305,,75);require=!disable,!magicImmunity,!globe,!holdImmunity]
// Summon Insects
[target=Caster;require=valid,!disable,!silence,!failure,!magicImmunity,!globe]
[target=Caster;require=valid,!disable,!silence,!failure,!magicImmunity,!globe,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!disable,!silence,!failure,!magicImmunity,!globe]
[action=SPELL(CLERIC_SUMMON_INSECTS,,75,caster);require=!disable,!silence,!failure,!magicImmunity,!globe]
// Mistcast Magic
[action=SPELL(CLERIC_MISCAST_MAGIC,,75,caster);require=!disable,!silence,!failure,!magicImmunity,!globe]
// Contagion
[target=Fighter;require=valid,!disable,!magicImmunity,!globe]
[target=Fighter;require=valid,!disable,!magicImmunity,!globe,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!disable,!magicImmunity,!globe]
[action=SPELL(SPPR311,,75,fighter);target=Fighter;require=!disable,!magicImmunity,!globe]
// Select random target or doomed target
[target=Player;require=valid,!magicImmunity,!globe]
[target=Player;require=valid,!magicImmunity,!globe,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!magicImmunity,!globe]
// Poison
[action=SPELL(CLERIC_POISON,,75);require=!magicImmunity,!poisonImmunity]
// Call Lightning
[action=SPELL(CLERIC_CALL_LIGHTNING,,75);require=!magicImmunity,!globe,!electricityImmunity]
// Lightning Bolt
[action=SPELL(SPDR301,,75);require=!magicImmunity,!globe,!electricityImmunity]
// Bless
[action=SPELL(CLERIC_BLESS,,75,notarget)]
// Neutralize poison
[action=SPELL(CLERIC_NEUTRALIZE_POISON,,75,notarget)]
// Barkskin
[action=SPELL(CLERIC_BARKSKIN,,75,notarget)]
// Resist Fire and Cold
[action=SPELL(CLERIC_RESIST_FIRE,,75,notarget)]
// Armor of faith
[action=SPELL(CLERIC_ARMOR_OF_FAITH,,75,notarget);require=*stat(0,CLERIC_ARMOR_OF_FAITH)]
// Flame Blade
[action=SPELL(CLERIC_FLAME_BLADE,,75,notarget);require=!*magicalWeaponItem]
// Shillelagh
[action=SPELL(CLERIC_SHILLELAGH,,75,notarget);require=!*magicalWeaponItem]
// Strength of Stone
[action=SPELL(SPPR115,,75,notarget)]
// Know Opponent
[action=SPELL(SPPR209,,75);require=!magicImmunity,!globe]
// Faerie Fire
[action=SPELL(SPPR114,,75);require=!magicImmunity,!globe]
// Chromatic Orb
[action=SPELL(SPDR101,,75);require=!magicImmunity,!globe]
// Sunscorch
[action=SPELL(SPPR116,,75);require=!magicImmunity,!globe,!fireImmunity]
[action=WALK;require=*invisible]
[include=combat_smart_both]
A few explanations of code:
CODE
// Hold Person or Animal
[target=Player;require=!disable,!magicImmunity,!globe,!holdImmunity]
[target=Player;require=!disable,!magicImmunity,!globe,!holdImmunity,stat(1,WIZARD_GREATER_MALISON)]
[action=SPELL(CLERIC_DOOM,,75);require=!stat(1,WIZARD_GREATER_MALISON),!disable,!magicImmunity,!globe,!holdImmunity]
[action=SPELL(SPPR305,,75);require=!disable,!magicImmunity,!globe,!holdImmunity]
It randomly selects a valid target (no sanctuary or improved invisibility), not disable (charm, stun, fear, hold, fear...)
It randomly selects a valid target (no sanctuary or improved invisibility), not disable (charm, stun, fear, hold, fear...), and affected by doom or greater malison
If selected target is not affect by doom or greater malison and I have doom, 75% to cast doom
75% to cast Hold Person or Animal
Other attributes are used if IMMUNITY_CHECK is set to true.
It generates:
CODE
// Hold Person or Animal
IF
OR(6)
StateCheck(Player6,STATE_CHARMED)
CheckStatGT(Player6,0,HELD)
StateCheck(Player6,STATE_HARMLESS)
StateCheck(Player6,STATE_CONFUSED)
StateCheck(Player6,STATE_PANIC)
RandomNumGT(1000,167)
OR(6)
StateCheck(Player5,STATE_CHARMED)
CheckStatGT(Player5,0,HELD)
StateCheck(Player5,STATE_HARMLESS)
StateCheck(Player5,STATE_CONFUSED)
StateCheck(Player5,STATE_PANIC)
RandomNumGT(1000,200)
OR(6)
StateCheck(Player4,STATE_CHARMED)
CheckStatGT(Player4,0,HELD)
StateCheck(Player4,STATE_HARMLESS)
StateCheck(Player4,STATE_CONFUSED)
StateCheck(Player4,STATE_PANIC)
RandomNumGT(1000,250)
OR(6)
StateCheck(Player3,STATE_CHARMED)
CheckStatGT(Player3,0,HELD)
StateCheck(Player3,STATE_HARMLESS)
StateCheck(Player3,STATE_CONFUSED)
StateCheck(Player3,STATE_PANIC)
RandomNumGT(1000,333)
OR(6)
StateCheck(Player2,STATE_CHARMED)
CheckStatGT(Player2,0,HELD)
StateCheck(Player2,STATE_HARMLESS)
StateCheck(Player2,STATE_CONFUSED)
StateCheck(Player2,STATE_PANIC)
RandomNumGT(1000,500)
OR(5)
StateCheck(Player1,STATE_CHARMED)
CheckStatGT(Player1,0,HELD)
StateCheck(Player1,STATE_HARMLESS)
StateCheck(Player1,STATE_CONFUSED)
StateCheck(Player1,STATE_PANIC)
THEN
RESPONSE #100
Continue()
END
IF
OR(7)
StateCheck(Player6,STATE_CHARMED)
CheckStatGT(Player6,0,HELD)
StateCheck(Player6,STATE_HARMLESS)
StateCheck(Player6,STATE_CONFUSED)
StateCheck(Player6,STATE_PANIC)
!CheckStat(Player6,1,WIZARD_GREATER_MALISON)
RandomNumGT(1000,167)
OR(7)
StateCheck(Player5,STATE_CHARMED)
CheckStatGT(Player5,0,HELD)
StateCheck(Player5,STATE_HARMLESS)
StateCheck(Player5,STATE_CONFUSED)
StateCheck(Player5,STATE_PANIC)
!CheckStat(Player5,1,WIZARD_GREATER_MALISON)
RandomNumGT(1000,200)
OR(7)
StateCheck(Player4,STATE_CHARMED)
CheckStatGT(Player4,0,HELD)
StateCheck(Player4,STATE_HARMLESS)
StateCheck(Player4,STATE_CONFUSED)
StateCheck(Player4,STATE_PANIC)
!CheckStat(Player4,1,WIZARD_GREATER_MALISON)
RandomNumGT(1000,250)
OR(7)
StateCheck(Player3,STATE_CHARMED)
CheckStatGT(Player3,0,HELD)
StateCheck(Player3,STATE_HARMLESS)
StateCheck(Player3,STATE_CONFUSED)
StateCheck(Player3,STATE_PANIC)
!CheckStat(Player3,1,WIZARD_GREATER_MALISON)
RandomNumGT(1000,333)
OR(7)
StateCheck(Player2,STATE_CHARMED)
CheckStatGT(Player2,0,HELD)
StateCheck(Player2,STATE_HARMLESS)
StateCheck(Player2,STATE_CONFUSED)
StateCheck(Player2,STATE_PANIC)
!CheckStat(Player2,1,WIZARD_GREATER_MALISON)
RandomNumGT(1000,500)
OR(6)
StateCheck(Player1,STATE_CHARMED)
CheckStatGT(Player1,0,HELD)
StateCheck(Player1,STATE_HARMLESS)
StateCheck(Player1,STATE_CONFUSED)
StateCheck(Player1,STATE_PANIC)
!CheckStat(Player1,1,WIZARD_GREATER_MALISON)
THEN
RESPONSE #100
Continue()
END
IF
HaveSpell(CLERIC_DOOM)
Global("ja#disable_spellcasting","LOCALS",0)
!GlobalTimerNotExpired("ja#round","LOCALS")
!CheckStatGT(LastSeenBy(Myself),0,SANCTUARY)
!StateCheck(LastSeenBy(Myself),STATE_IMPROVEDINVISIBILITY)
!General(LastSeenBy(Myself),WEAPON)
See(LastSeenBy(Myself))
!CheckStat(LastSeenBy(Myself),1,WIZARD_GREATER_MALISON)
!CheckStatGT(LastSeenBy(Myself),0,HELD)
!StateCheck(LastSeenBy(Myself),STATE_HARMLESS)
!StateCheck(LastSeenBy(Myself),STATE_CONFUSED)
!StateCheck(LastSeenBy(Myself),STATE_PANIC)
RandomNumGT(100,25)
THEN
RESPONSE #100
SetGlobalTimer("ja#round","LOCALS",6)
Spell(LastSeenBy(Myself),CLERIC_DOOM)
END
IF
HaveSpellRES("SPPR305")
Global("ja#disable_spellcasting","LOCALS",0)
!GlobalTimerNotExpired("ja#round","LOCALS")
!CheckStatGT(LastSeenBy(Myself),0,SANCTUARY)
!StateCheck(LastSeenBy(Myself),STATE_IMPROVEDINVISIBILITY)
!General(LastSeenBy(Myself),WEAPON)
See(LastSeenBy(Myself))
!CheckStatGT(LastSeenBy(Myself),0,HELD)
!StateCheck(LastSeenBy(Myself),STATE_HARMLESS)
!StateCheck(LastSeenBy(Myself),STATE_CONFUSED)
!StateCheck(LastSeenBy(Myself),STATE_PANIC)
RandomNumGT(100,25)
THEN
RESPONSE #100
SetGlobalTimer("ja#round","LOCALS",6)
SpellRES("SPPR305",LastSeenBy(Myself))
END