Skip to content

Custom Character scripting

LorelLorel Member Posts: 9
1. I modified Mage4 script to cast different spells. It works great but after casting about 6 fireballs it stops casting all the magic missiles that my char has memorized and just starts meleeing. How do I get it to keep casting until all do the spells are exhausted? I tried removing the melee script and same thing happens...he stops casting even tho he has some spells left but instead of meleeing he just stands there.

2. What is the command for scripting innate abilities? Does anyone have an example of the full script (IF, THEN, END) so I can try out some things?

I just started messing around with scripts and slowly figuring it out. It's very fun tho...thanks!

Comments

  • karnagekarnage Member Posts: 92
    edited December 2013
    1. EDIT: I misread your question. Please post your IF statement for WIZARD_MAGIC_MISSILE so I can see what "conditions" you have set for MAGIC_MISSILE.

    2. For "Special Abilities", those are listed differently; here is a script that someone else wrote (I can't find the link for the download), but here, the character has the ALCHEMY ability. (This person's scripting is very well thought out, but I think he puts too much coding):

    // Alchemy
    IF
    ActionListEmpty()
    CombatCounter(0)
    Global("GBAlchemy","LOCALS",1)
    HaveSpellRES("spcl918")
    !GlobalTimerNotExpired("GBHalfAttack","LOCALS")
    THEN
    RESPONSE #100
    SetGlobalTimer("GBHalfAttack","LOCALS",6)
    SpellRES("spcl918",Myself)
    END
    IF
    ActionListEmpty()
    CombatCounter(0)
    Global("GBAlchemy","LOCALS",1)
    HaveSpellRES("gbalchpr")
    !GlobalTimerNotExpired("GBHalfAttack","LOCALS")
    THEN
    RESPONSE #100
    SetGlobalTimer("GBHalfAttack","LOCALS",6)
    SpellRES("gbalchpr",Myself)
    END

    Here is "scribe scroll":

    // Scribe Scrolls
    IF
    ActionListEmpty()
    CombatCounter(0)
    Global("GBAlchemy","LOCALS",1)
    HaveSpellRES("spcl919")
    !GlobalTimerNotExpired("GBHalfAttack","LOCALS")
    THEN
    RESPONSE #100
    SetGlobalTimer("GBHalfAttack","LOCALS",6)
    SpellRES("spcl919",Myself)
    END

    IF
    ActionListEmpty()
    CombatCounter(0)
    Global("GBAlchemy","LOCALS",1)
    HaveSpellRES("gbscrbpr")
    !GlobalTimerNotExpired("GBHalfAttack","LOCALS")
    THEN
    RESPONSE #100
    SetGlobalTimer("GBHalfAttack","LOCALS",6)
    SpellRES("gbscrbpr",Myself)
    END


    --------
    If you script it to cast a spell, it will continue casting that spell until it's exhausted, given that certain conditions are true. Possibly you could add a variable in the script.

    I don't have BG2:EE, but I'm assuming that the scripts are pretty much the same. Here is the script from Mage4 involving "Fireball":

    IF
    ActionListEmpty()
    See(NearestEnemyOf(Myself))
    HaveSpell(WIZARD_FIREBALL)
    !Range(LastSeenBy(Myself),20)
    THEN
    RESPONSE #100
    Spell(NearestEnemyOf(Myself),WIZARD_FIREBALL)
    END

    So, as long as the conditions are true (Action list is empty, there is an enemy, he has the Fireball spell, and the range is correct), the spell will be cast. In order to stop the casting of the spells until the spells are depleted, we need to create a condition that becomes false (as in, running out of the Fireball spell, thus HaveSpell(WIZARD_FIREBALL) becomes false).

    One possibility in doing this is to create a variable that limits the number of times "Fireball" is used:

    IF
    ActionListEmpty()
    See(NearestEnemyOf(Myself))
    HaveSpell(WIZARD_FIREBALL)
    !Range(LastSeenBy(Myself),20)
    GlobalLT("Fireball","LOCALS",1)
    THEN
    RESPONSE #100
    Spell(NearestEnemyOf(Myself),WIZARD_FIREBALL)
    SetGlobal("Fireball","LOCALS",1)
    END

    In the above revision, the wizard will cast fireball 1 time. One of the conditions is now that the variable "Fireball" is less than one. After the spell is cast, the value for "Fireball" now becomes one.

    If we do set this kind of a variable, however, you will need to add something to the bottom of the script that changes "Fireball" back to 0; or else the Wizard will cast Fireball only once in his entire career:

    IF
    !See(NearestEnemyOf(Myself))
    CombatCounter(0)
    GlobalGT("Fireball","LOCALS",0)
    THEN
    RESPONSE #100
    SetGlobal("Fireball","LOCALS",0)
    END

    --------------
    In short, before the wizard will stop casting FIREBALL, a condition has to become "false".
  • LorelLorel Member Posts: 9
    wow, thank you for the example. where did you find this? I searched on the web first before i posted here but couldnt find much. Below is my script for magic missile. Melfs acid arrow doesn't cast either for some reason.

    IF
    ActionListEmpty()
    See(NearestEnemyOf(Myself))
    HaveSpell(WIZARD_MAGIC_MISSILE)
    HPGT(LastSeenBy(Myself),20)
    !HasBounceEffects(LastSeenBy(Myself))
    THEN
    RESPONSE #100
    Spell(NearestEnemyOf(Myself),WIZARD_MAGIC_MISSILE)
    END

    IF
    ActionListEmpty()
    See(NearestEnemyOf(Myself))
    HaveSpell(WIZARD_MELF_ACID_ARROW)
    HPGT(LastSeenBy(Myself),20)
    !HasBounceEffects(LastSeenBy(Myself))
    THEN
    RESPONSE #100
    Spell(NearestEnemyOf(Myself),WIZARD_MELF_ACID_ARROW)
    END
  • LorelLorel Member Posts: 9
    i pretty much just copy pasted and changed the name of the spells. I think i have to do a little more research into the commands if i can just find a website that has a full list of the commands and what it does.
  • LorelLorel Member Posts: 9
    Ok, I've got my Mage doing what I'd like him to do. I got rid of the ranges and he uses all of his spells. Now I need to get my Thief to act like the shadow thieves.
  • karnagekarnage Member Posts: 92
    By looking at the script, I'd imagine you were probably fighting creatures who had less than 20 hit points to their name. Because they had less than 20 hit points, the HPGT condition became false.

    It's a bad idea to remove the !HasBounceEffect. That causes our characters to check to see if something like "Minor Spell Turning" is in effect.

    I did not have that in my Druid script; so, when Jaheira encountered the "escaped clone", she cast her "Summon Insects". It bounced off the escaped clone, so now here are Minsc, Boo, Imoen and Yoshimo taking on the clone while Jaheira has a cloud of insects around her head and she's going "Ah! Ah! Ah!" and my Bhaalspawn was busy standing behind her healing her and it was a real mess ....

    I can NOT find a link to that script. But this link has some more scripting downloads:
    http://www.sorcerers.net/Games/BG2/index_editors.php

    I'm interested in adding innate abilities to my AI scripts myself, but I just haven't gotten around to it. If you tell me which innate ability you want to script, I'm sure we can work together on it. Up to you ...
  • WispWisp Member Posts: 1,102
    karnage said:
    Pro tip: anything modding-related on sorcerers.net was already obsolete 10 years ago.

    @Lorel
    If you aren't already, you'll want to consult the IESDP, particularly the sections on actions and triggers.
  • LorelLorel Member Posts: 9
    Cool thanks man. I'll check it out
  • karnagekarnage Member Posts: 92
    We were talking about scripts. I worked on mine a bit today, and thought I'd pass some things along.

    ** I think scripts are somewhat of an "achille's heel"; while they reduce our workload while playing the game, they also have a tendency to take away control of the characters, sometimes causing them to do other than what we, at the moment, want them to do. It would be nice if we had the option to turn AI on/off for each character instead of as an entire group. **

    At the very (very) top of Bards or Clerics and Paladins, I put this script. If instructed to use Bard Song or Turn Undead, this causes all other actions to be bypassed. So, if we click "Turn Undead" action or "Bard Song" action, they don't decide by themselves to quit that action and do something else for us ....


    // ================================ BARD SONG ======================

    // (* This prevents the character from performing any actions other than bard song.*)
    // (* Player must initiate and stop bard song. *)

    IF

    ModalState(BARDSONG)

    THEN

    RESPONSE #100

    END

    // ================================ UNDEAD TURNING ===================

    // (* This prevents the character from performing any actions other than turning undead.*)
    // (* Player must initiate and stop undead turning. *)

    IF

    ModalState(TURNUNDEAD)

    THEN

    RESPONSE #100

    END


    Here is a script I put near the top of all of my scripts. It instructs the character to use healing potions and Antidotes. The script does not implement when they are currently engaged with an enemy.

    // =================== POTIONS ==========================

    // Antidote
    IF
    ActionListEmpty()
    HasItem("POTN20",Myself)
    StateCheck(Myself,STATE_POISONED)
    THEN
    RESPONSE #100
    UseItem("POTN20",Myself)
    END

    // Potion of Superior Healing
    IF
    ActionListEmpty()
    HasItem("POTN55",Myself)
    HPPercentLT(Myself,80)
    THEN
    RESPONSE #100
    UseItem("POTN55",Myself)
    END

    // Extra Healing
    IF
    ActionListEmpty()
    HasItem("POTN08",Myself)
    HPPercentLT(Myself,80)
    THEN
    RESPONSE #100
    UseItem("POTN08",Myself)
    END

    // Healing
    IF
    ActionListEmpty()
    HasItem("POTN52",Myself)
    HPPercentLT(Myself,50)
    THEN
    RESPONSE #100
    UseItem("POTN52",Myself)
    END


    You were talking about scripting special abilities. While I have not yet experimented with this, here are some codes I have ran accross:

    // Whirlwind Attack: SPCL900
    // Greater Whirlwind Attack: SPCL901
    // Deathbow: SPCL902
    // Greater Deathbow: SPCL903
    // CRITICAL STRIKE: SPCL905
    // Power Attack: SPCL906
    // War Cry: SPCL908
    // Smite: SPCL909
    // Shapeshifts Werewolf: SPCL643
    // Shapeshifts Greater Werewolf: SPCL644
    // Pocket Plane: SPIN649
    // Slayer Change: SPIN822

    --------------------------------------------------

    In revising, I broke my ClericMage script, LoL. Somewhere is an extra IF, THEN or END and I can't find it for the life of me! But, I have backups; just have to gather my last save and do today's revisions again.
  • LorelLorel Member Posts: 9
    Is there an easy way to cycle thru targets? You don't want to see how I do it cause it's long and I'm sure there's an easier way.
  • WispWisp Member Posts: 1,102
    @Lorel
    It depends on what you mean by "cycle", but no, there isn't. Multiple targets require one block per target and result in long scripts. Scripts with advanced targeting frequently clock in at thousands or tens of thousands of lines of BAF, and most of the length is targeting. If you want something comparatively brief, I would suggest you have a look at the AI scripts in aTweaks written by aVENGER, which is most of the fiend and all of the elemental and fey scripts. There are other ways of doing it, with different advantages and disadvantages, but one of the advantages of this particular method is that achieves advanced targeting with a comparatively low number of lines of BAF. (Caveat: some of the fiend scripts in aTweaks are written by me and are considerably longer [and you are much better off reading the SSL source instead of the BAF].)
  • LorelLorel Member Posts: 9
    edited January 2014
    I was afraid of that. I made a script that power word silences every enemy and starts At the furthest away. Then I was thinking of making it better by targeting only casters and using other disable spells and then my line of thinking eventually led me to a script that wnt on forever...ugh. I have a headache now just thinking of it
  • karnagekarnage Member Posts: 92
    Wisp, do you have a link?
  • WispWisp Member Posts: 1,102
    aTweaks can be downloaded here.
  • karnagekarnage Member Posts: 92
    Got it! Thank you!
Sign In or Register to comment.