Help with three scripts in Blackguard III

Hey, guys.

I’m still working on my remastered version of the Blackguard series, and while most of it is busywork that only requires time, the following scripts are beyond my ken. The first one used to work fine, but doesn’t anymore, so I think it clashes with NWN EE in some way. The second and third ones, however, I’ve never seen working, even in the old days (in fact, I only found out about them because I went through every script in each module). These are the biggest remaining obstacles I can think of, so hopefully I can quit bothering you guys after this :wink:

For context, the first script is meant to execute during a battle against three planetars. Whenever one of them dies, one of the remaining two would immediately try to resurrect his fallen comrade. Right now, they don’t do that, even if I kill one and then just draw out the fight. The full script is:

//::///////////////////////////////////////////////
//:: Default: End of Combat Round
//:: NW_C2_DEFAULT3
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Calls the end of combat script every round
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 16, 2001
//:://////////////////////////////////////////////
#include “NW_I0_GENERIC”
#include “nw_i0_spells”

string ReplyStr()
{
string sReturn;
switch(Random(10))
{
case 0: sReturn = “No! Do not worry, I’m here.”; break;
case 1: sReturn = “I won’t let you down, old friend.”; break;
case 2: sReturn = “This evil will not take you!”; break;
case 3: sReturn = “I will raise you back, my friend.”; break;
case 4: sReturn = “You won’t die before I do.”; break;
case 5: sReturn = “This won’t be that easy.”; break;
case 6: sReturn = “Death will not take you.”; break;
case 7: sReturn = “NO!!”; break;
case 8: sReturn = “Light shall prevail!”; break;
case 9: sReturn = “I’m coming, brother.”; break;
}

return sReturn;

}

void main()
{

if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
{
    DetermineSpecialBehavior();
}
else if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS))
{

//************************************************************
string sTag = GetTag(OBJECT_SELF);
object oPlanetarProtect;

/*
if (sTag == “Planetar1”)
oPlanetarProtect = GetObjectByTag(“Planetar2”);
else if (sTag == “Planetar2”)
oPlanetarProtect = GetObjectByTag(“Planetar3”);
else if (sTag == “Planetar3”)
oPlanetarProtect = GetObjectByTag(“Planetar1”);
*/

    // The tag of who the planetar will protect - (heal + ressurect)
    oPlanetarProtect = GetObjectByTag( GetLocalString(OBJECT_SELF, "PlanetarProtect"));



    int iAction = GetLocalInt(OBJECT_SELF, "OffensivePlanetar");

// object oDragon = GetObjectByTag(“SILVERDRAGON”);

    //Heal Self First
    if (TalentHealingSelf()) return;

    //Heal Dedicated Friend
    if (Random(2) == 0                      &&
        !GetIsDead(oPlanetarProtect)        &&
        TalentHeal(FALSE, oPlanetarProtect)) return;

    //Ressurect Dedicated Friend
    if (GetIsDead(oPlanetarProtect)     &&
        GetHasSpell(SPELL_RESURRECTION)  )
    {
        ClearAllActions();
        ActionMoveToObject(oPlanetarProtect, TRUE);
        SpeakString( ReplyStr() );
        ActionCastSpellAtObject(SPELL_RESURRECTION, oPlanetarProtect);
        ActionDoCommand( DetermineCombatRound() );
    }
    else if (iAction == 1)
    {
         if (Random(3) == 0)
            SetLocalInt(OBJECT_SELF, "OffensivePlanetar", 0);

         DetermineCombatRound();
    }
    else
    {
         if (Random(3) == 0)
            SetLocalInt(OBJECT_SELF, "OffensivePlanetar", 1);

        if (TalentMeleeAttack(bkAcquireTarget()))
            SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", 0); //remember
        else
            DetermineCombatRound();
    }

//************************************************************
}
if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT))
{
SignalEvent(OBJECT_SELF, EventUserDefined(1003));
}

}

The second and third scripts are also meant to happen during combat, specifically with the eponymous hero (well, protagonist) and Valshera against two Solars. As I mentioned above, I have never seen it actually happen. As best I can understand, the Solars are meant to resurrect each other (which also isn’t happening at the moment), so Valshera comments on it, summons her familiar to block their spells, a bit of dialog ensues, and then the Solars lose the ability to resurrect each other.

The first of these two scripts, chronoglogically (judging by Valshera’s dialog) is this one:

//::///////////////////////////////////////////////
//:: Default: End of Combat Round
//:: NW_C2_DEFAULT3
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Calls the end of combat script every round
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 16, 2001
//:://////////////////////////////////////////////
#include “NW_I0_GENERIC”
#include “nw_i0_spells”

void ValsheraReply( int iRessu)
{
object oValshera = GetObjectByTag(“Valshera”);

string sStr;

switch(iRessu)
{
    case 10: sStr = "These fools can heal and resurrect at will! We must prevent them!"; break;
    case 20: {
                sStr = "I cannot counter their magic, I'll summon someone who will...";
                SetLocalInt(oValshera, "SummonQuasit",1);
            }; break;
}


AssignCommand( oValshera, SpeakString(sStr));

}

string ReplyStr( string sTag)
{
string sReturn;

if (sTag == "Solar1") // Ilazikiel
    switch(Random(3))
    {
        case 0: sReturn = "Hang in there, Garlazriel."; break;
        case 1: sReturn = "Garlazriel!!"; break;
        case 2: sReturn = "By the justice of Tyr, I won't allow this to happen."; break;
    }
else
    switch(Random(3)) // Garlazriel
    {
        case 0: sReturn = "Ilazikiel!!"; break;
        case 1: sReturn = "Rise again, Ilazikiel."; break;
        case 2: sReturn = "The lady of Luck will not let you down."; break;
    }

return sReturn;

}

void main()
{

//************************************************************
string sTag = GetTag(OBJECT_SELF);
object oSolarProtect;
object oMod = GetModule();

    // The tag of who the solar will protect - (heal + ressurect)
    oSolarProtect = GetObjectByTag( GetLocalString(OBJECT_SELF, "SolarProtect"));

    int iAction = GetLocalInt(OBJECT_SELF, "OffensiveSolar");


    //Valshera Reply***
    int iRessuSolar = GetLocalInt(oMod, "RessuSolar") + 1;
    SetLocalInt(oMod, "RessuSolar", iRessuSolar);

    if (iRessuSolar == 10 || iRessuSolar == 20)
        ValsheraReply(iRessuSolar);
    //***

    //Heal Self First
    if (TalentHealingSelf()) return;

    //Heal Dedicated Friend
    if (Random(3) == 0                   &&
        !GetIsDead(oSolarProtect)        &&
        TalentHeal(FALSE, oSolarProtect)) return;

    //Ressurect Dedicated Friend
    if (GetIsDead(oSolarProtect)     &&
        GetHasSpell(SPELL_RESURRECTION)  )
    {
        ClearAllActions();
        ActionMoveToObject(oSolarProtect, TRUE);
        SpeakString( ReplyStr( GetTag(OBJECT_SELF) ) );
        ActionCastSpellAtObject(SPELL_RESURRECTION, oSolarProtect);
        ActionDoCommand( DetermineCombatRound() );
    }

    else if (iAction == 1)
    {
         if (Random(3) == 0)
            SetLocalInt(OBJECT_SELF, "OffensiveSolar", 0);

         DetermineCombatRound();
    }

    else
    {
         if (Random(3) == 0)
            SetLocalInt(OBJECT_SELF, "OffensiveSolar", 1);

        if (TalentMeleeAttack(bkAcquireTarget()))
            SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", 0); //remember
        else
            DetermineCombatRound();
    }

//************************************************************
}

Then the second script is this one:

//::///////////////////////////////////////////////
//:: Associate: End of Combat End
//:: NW_CH_AC3
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Calls the end of combat script every round
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 16, 2001
//:://////////////////////////////////////////////
#include “x0_inc_henai”

void SummonQuasit()
{
effect eSummon = EffectSummonCreature(“artgrek”, VFX_FNF_SUMMON_GATE, 3.0);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetLocation(OBJECT_SELF), 180.0);
}

void main()
{
if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS))
{
//SendMessageToPC(GetFirstPC(), "COMBAT: "+IntToString(GetCombatDifficulty(GetMaster(),TRUE)));

    if (GetCombatDifficulty(GetMaster(),TRUE) > 0)      //with magic
    {
        SetLocalInt(OBJECT_SELF, "SAVE_YOUR_SPELLS", FALSE);
    }
    else                                                //without magic
    {
        if (GetItemInSlot(INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID)
        {
            ActionEquipMostDamagingMelee();
            ActionSpeakString("I shall enjoy this.");
        }

        SetLocalInt(OBJECT_SELF, "SAVE_YOUR_SPELLS", TRUE);
    }

//“X2_L_BEH_MAGIC”
//“X2_L_BEH_OFFENSE”
//“X2_L_BEH_COMPASSION”

//SendMessageToPC(GetFirstPC(), "COMBAT: "+IntToString(GetLocalInt(OBJECT_SELF, “SAVE_YOUR_SPELLS”)));

   if (GetLocalInt(OBJECT_SELF, "SummonQuasit") == 1)
   {
        ClearAllActions();
        ActionCastFakeSpellAtObject(SPELL_GATE, OBJECT_SELF);
        DelayCommand(2.0, SummonQuasit());
        SetLocalInt(OBJECT_SELF, "SummonQuasit",0);

        DelayCommand(6.0,  SpeakString("Art'hgrek ! Counter the Solars' spells!"));
        DelayCommand(10.0, AssignCommand(GetObjectByTag("Arthgrek"), SpeakString("But mistress...Solars too powerful!")));
        DelayCommand(14.0, SpeakString("Art'hgrek ! You'd rather feel my wrath?"));
        DelayCommand(18.0, AssignCommand(GetObjectByTag("Arthgrek"), SpeakString("...no...Art'hgrek counter spells then...")));

        DelayCommand(18.0, SetLocalInt(GetObjectByTag("Arthgrek"), "CounterMagic", 1));
   }


   HenchmenCombatRound(OBJECT_INVALID);
}



if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT))
{
    SignalEvent(OBJECT_SELF, EventUserDefined(1003));
}

}

I know this is a big ask, but I am way out of my depth here, and this is pretty much the final hurdle. I’d hate to release Blackguard - Remastered with these issues unresolved, so I beseech you - please, lend me your (scripting) power.

And of course, thanks in advance.

Are you sure that the end of combat round script is the best choice for this type of event?
It seems like the OnDeath script of the planetars would be a better candidate to handle this type of events, no?

Also, both the scripts appear to be named as nw_c2_default3, but I assume they were actually renamed and slotted to the blueprints of the creatures, right?

Speaking of which, if you did it after you placed the creatures on the game world, you might have to delete them and re-place them from the changed blueprint (disregard this if you handle their appearence via spawning)

Thanks for the reply!

I should clarify: these aren’t my scripts. They were written by Steve B, author of the Blackguard series, which I am currently editing to make a remastered version.

The script names are indeed changed in the module itself; I just figured I should copy everything to be thorough. As for the creatures themselves, they spawn in both instances. Now, if converting the scripts to OnDeath would work, I’d be happy if you could teach me how to do that. With that in mind, is there no other issue you can find with these scripts? Nothing else that would cause them to malfunction?

Well, to be honest, I didn’t really take the time read them thoroughly nor to test them. coughs
Obviously just copying and pasting these as OnDeath scripts would not work, they would have to be changed significantly.

Anyways, I modified the first script somewhat, give it a shot, it’s still a EndofCombatround script.
Didn’t really test it, but try it and see how it behaves.

//::///////////////////////////////////////////////
//:: Modified End of Combat Round
//:: BLACKGUARD III - SCRIPT 1 (PLANETARS)
//:://////////////////////////////////////////////
/* Calls the end of combat script every round */

#include "NW_I0_GENERIC"

string ReplyStr()
{
    string sReturn;
    switch(Random(10))
    {
        case 0: sReturn = "No! Do not worry, I’m here."; break;
        case 1: sReturn = "I won’t let you down, old friend."; break;
        case 2: sReturn = "This evil will not take you!"; break;
        case 3: sReturn = "I will raise you back, my friend."; break;
        case 4: sReturn = "You won’t die before I do."; break;
        case 5: sReturn = "This won’t be that easy."; break;
        case 6: sReturn = "Death will not take you."; break;
        case 7: sReturn = "NO!!"; break;
        case 8: sReturn = "Light shall prevail!"; break;
        case 9: sReturn = "I’m coming, brother."; break;
    }

    return sReturn;
}

void main()
{
    object oSELF = OBJECT_SELF;
    string sTag = GetTag(oSELF);

    // The tag of who the planetar will protect - (heal + ressurect)
    object oPlanetarProtect = GetObjectByTag(GetLocalString(oSELF, "PlanetarProtect"));

    object oQUASIT = GetObjectByTag("Arthgrek");
    if (GetLocalInt(oQUASIT, "CounterMagic") != 1)
    {
        if (GetIsDead(oPlanetarProtect) == TRUE)
        {
            ClearAllActions();
            SpeakString(ReplyStr());
            ActionMoveToObject(oPlanetarProtect, TRUE);
            ActionCastSpellAtObject(SPELL_RESURRECTION, oPlanetarProtect, METAMAGIC_ANY, TRUE);
            object oVALSHERA = GetObjectByTag("Valshera");
            AssignCommand(oVALSHERA, SpeakString("These fools can heal and resurrect at will! We must prevent them! I cannot counter their magic, I'll summon someone who will..."));
            SetLocalInt(oVALSHERA, "SummonQuasit", 1);
            return;
        }
    }

    int iAction = GetLocalInt(oSELF, "OffensivePlanetar");

    //Heal Self First
    if (TalentHealingSelf()) return;

    //Heal Dedicated Friend
    if (Random(2) == 0 && TalentHeal(FALSE, oPlanetarProtect)) return;

    if (iAction == 1)
    {
         if (Random(3) == 0) SetLocalInt(oSELF, "OffensivePlanetar", 0);
    }
    else
    {
        if (Random(3) == 0) SetLocalInt(oSELF, "OffensivePlanetar", 1);
        if (TalentMeleeAttack(bkAcquireTarget())) SetLocalInt(oSELF, "NW_L_MEMORY", 0); //remember
    }

    DetermineCombatRound();
}

1 Like

Ack. I thought you were the actual author. Got to fix the module author permissions again. Sorry for the confusion :slight_smile:

Holy hell, you did it. I just tested the script and it worked like a charm, even when I killed a planetar multiple times, and killed different planetars, etc. It also made them spam a whole bunch of Blade Barriers, but I’ll take it lol. And besides, I can just edit them to have less Blade Barriers.

You’ve already solved half my problem, so I’m plenty grateful, but what are the odds you’d be willing to tackle the other two, now that you’re emboldened by your success and all that? Eh? Eh? :wink:

Ok, I modified the third script to make it work in conjunction with the first one. I also edited the first script in the post above to make the event of the blocked resurrection via quasit work (at least that’s what it’s supposed to do).

The second script I honestly don’t understand what is it for, at first sight it appears to be like the first one, but for the other planetar, it’s not a script associated to the hero or the henchman.
Anyways, for the time being give it a shot with these two scripts and ignore the second one, see if it works this way already, in theory it should, with at least one of the two planetars.

//::///////////////////////////////////////////////
//:: Modified Associate: End of Combat Round
//:: BLACKGUARD III - SCRIPT 3 (VALSHERA)
//:://////////////////////////////////////////////
/* Calls the end of combat script every round */

#include "x0_inc_henai"

void SummonQuasit()
{
    effect eSummon = EffectSummonCreature("artgrek", VFX_FNF_SUMMON_GATE, 3.0);
    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetLocation(OBJECT_SELF), 180.0);
}

void main()
{
    object oSELF = OBJECT_SELF;

    if(!GetSpawnInCondition(NW_FLAG_SET_WARNINGS))
    {
    //SendMessageToPC(GetFirstPC(), "COMBAT: "+IntToString(GetCombatDifficulty(GetMaster(),TRUE)));

        if (GetCombatDifficulty(GetMaster(),TRUE) > 0)      //with magic
        {
            SetLocalInt(oSELF, "SAVE_YOUR_SPELLS", FALSE);
        }
        else                                                //without magic
        {
            if (GetItemInSlot(INVENTORY_SLOT_RIGHTHAND) == OBJECT_INVALID)
            {
                ActionEquipMostDamagingMelee();
                ActionSpeakString("I shall enjoy this.");
            }

            SetLocalInt(oSELF, "SAVE_YOUR_SPELLS", TRUE);
        }
    }

    if (GetLocalInt(oSELF, "SummonQuasit") == 1)
    {
        ClearAllActions();
        ActionCastFakeSpellAtObject(SPELL_GATE, oSELF);
        DelayCommand(2.0, SummonQuasit());
        SetLocalInt(oSELF, "SummonQuasit",0);
        object oQUASIT = GetObjectByTag("Arthgrek");
        DelayCommand(6.0,  SpeakString("Art'hgrek ! Counter the Solars' spells!"));
        DelayCommand(8.0, AssignCommand(oQUASIT, SpeakString("But mistress...Solars too powerful!")));
        DelayCommand(10.0, SpeakString("Art'hgrek ! You'd rather feel my wrath?"));
        DelayCommand(12.0, AssignCommand(oQUASIT, SpeakString("...no...Art'hgrek counter spells then...")));
        DelayCommand(12.0, SetLocalInt(oQUASIT, "CounterMagic", 1));
    }
    else HenchmenCombatRound();

    if(GetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT))
    {
        SignalEvent(oSELF, EventUserDefined(1003));
    }

}
1 Like

Thanks for the assist!

I tested the script, and it works - kinda.

Valshera says her first line about how they keep healing each other, and then (much later, though) her second line about how she’ll summon someone who can counter their spells. This is still the second script; now we move to the third, which you’ve modified:

She then proceeds to summon her quasit. Problem is, she says her followup lines (“Counter their spells!” and “You’d rather feel my wrath?”), but the quasit doesn’t say his.

As for what the second script is for, I believe it’s so that the two Solars heal and resurrect each other ( which they don’t do at the moment), and for Valshera to point it out, leading to the third script where she summons her familiar to stop it. I’m afraid this one’s pretty important, since without their healing and resurrecting, the Solars don’t last very long, so it never actually gets to the point where Valshera summons her quasit.

I suppose I could just give both solars a massive HP increase and a bit more Strength to compensate, and we can scratch these scripts altogether, but I’d really like to stay true to Steve B’s vision and have this little sequence of events. Totally understandable if you’re done, though. I know I’m asking for a lot. And once again, thanks for all you’ve done so far. You’ve been a huge help :smiley: