Reverted to 4.56 to track down a bug that started in 4.57. Bugfixed back to 4.61. It's amazing the damage that one skipped case statement can do.
		
			
				
	
	
		
			120 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			120 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
//:://////////////////////////////////////////////
 | 
						|
//::	;-.  ,-.   ,-.  ,-. 
 | 
						|
//::	|  ) |  ) /    (   )
 | 
						|
//::	|-'  |-<  |     ;-: 
 | 
						|
//::	|    |  \ \    (   )
 | 
						|
//::	'    '  '  `-'  `-' 
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
//::
 | 
						|
/*
 | 
						|
	Control Plants
 | 
						|
	Transmutation
 | 
						|
	Level: 	Drd 8, Plant 8
 | 
						|
	Components: 	V, S, DF
 | 
						|
	Casting Time: 	1 standard action
 | 
						|
	Range: 	Close (25 ft. + 5 ft./2 levels)
 | 
						|
	Targets: 	Up to 2 HD/level of plant creatures, 
 | 
						|
				no two of which can be more than 30 ft. 
 | 
						|
				apart
 | 
						|
	Duration: 	1 min./level
 | 
						|
	Saving Throw: 	Will negates
 | 
						|
	Spell Resistance: 	No
 | 
						|
 | 
						|
	This spell enables you to control the actions of one 
 | 
						|
	or more plant creatures for a short period of time. You 
 | 
						|
	command the creatures by voice and they understand you, 
 | 
						|
	no matter what language you speak. Even if vocal 
 | 
						|
	communication is impossible the controlled plants do 
 | 
						|
	not attack you. At the end of the spell, the subjects 
 | 
						|
	revert to their normal behavior.
 | 
						|
 | 
						|
	Suicidal or self-destructive commands are simply ignored. 
 | 
						|
*/
 | 
						|
//::
 | 
						|
//::////////////////////////////////////////////// 
 | 
						|
//::	Script:     sp_ctrl_plants
 | 
						|
//::	Author:     Jaysyn
 | 
						|
//::	Created:    2025-08-11 22:28:40
 | 
						|
//:://////////////////////////////////////////////
 | 
						|
#include "prc_inc_spells"
 | 
						|
#include "prc_add_spell_dc"
 | 
						|
 | 
						|
void main()
 | 
						|
{
 | 
						|
    DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
 | 
						|
    SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_TRANSMUTATION);
 | 
						|
 | 
						|
    if (!X2PreSpellCastCode())
 | 
						|
        return;
 | 
						|
 | 
						|
    int nMetaMagic = PRCGetMetaMagicFeat();
 | 
						|
    int CasterLvl  = PRCGetCasterLevel(OBJECT_SELF);
 | 
						|
	
 | 
						|
	if (GetLevelByClass(CLASS_TYPE_VERDANT_LORD, OBJECT_SELF) >= 4)
 | 
						|
	{
 | 
						|
		CasterLvl = CasterLvl + 3;
 | 
						|
	} 
 | 
						|
	
 | 
						|
    int nDuration  = CasterLvl; // minutes
 | 
						|
    int nHDLimit   = CasterLvl * 2; // RAW
 | 
						|
 | 
						|
    if (nMetaMagic & METAMAGIC_EXTEND)
 | 
						|
        nDuration *= 2;
 | 
						|
 | 
						|
    int nPenetr = CasterLvl + SPGetPenetr();
 | 
						|
 | 
						|
    // Close range in NWN terms: 25 ft. + 5 ft./2 levels
 | 
						|
    float fMaxRange = 25.0 + (IntToFloat(CasterLvl / 2) * 5.0);
 | 
						|
 | 
						|
    object oTarget = PRCGetSpellTargetObject();
 | 
						|
    location lTarget = GetLocation(oTarget);
 | 
						|
    object oCreature = GetFirstObjectInShape(SHAPE_SPHERE, fMaxRange, lTarget, TRUE);
 | 
						|
 | 
						|
    while (GetIsObjectValid(oCreature) && nHDLimit > 0)
 | 
						|
    {
 | 
						|
        if (MyPRCGetRacialType(oCreature) == RACIAL_TYPE_PLANT
 | 
						|
            && !GetIsReactionTypeFriendly(oCreature)
 | 
						|
            && GetDistanceBetweenLocations(lTarget, GetLocation(oCreature)) <= 30.0
 | 
						|
            && GetHitDice(oCreature) <= nHDLimit)
 | 
						|
        {
 | 
						|
            // Fire cast spell at event for the specified target
 | 
						|
            SignalEvent(oCreature, EventSpellCastAt(OBJECT_SELF, SPELL_CONTROL_PLANTS));
 | 
						|
 | 
						|
            if (!PRCDoResistSpell(OBJECT_SELF, oCreature, nPenetr))
 | 
						|
            {
 | 
						|
                if (!PRCMySavingThrow(SAVING_THROW_WILL, oCreature, PRCGetSaveDC(oCreature, OBJECT_SELF),
 | 
						|
                                      SAVING_THROW_TYPE_NONE, OBJECT_SELF, 1.0))
 | 
						|
                {
 | 
						|
                    // Remove old domination if present
 | 
						|
                    effect eCheck = GetFirstEffect(oCreature);
 | 
						|
                    while (GetIsEffectValid(eCheck))
 | 
						|
                    {
 | 
						|
                        int nType = GetEffectType(eCheck);
 | 
						|
                        if (nType == EFFECT_TYPE_DOMINATED || nType == EFFECT_TYPE_CUTSCENE_DOMINATED)
 | 
						|
                            RemoveEffect(oCreature, eCheck);
 | 
						|
 | 
						|
                        eCheck = GetNextEffect(oCreature);
 | 
						|
                    }
 | 
						|
 | 
						|
                    // Apply domination
 | 
						|
                    effect eControl = EffectCutsceneDominated();
 | 
						|
                    effect eMind    = EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED);
 | 
						|
                    effect eDur     = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
 | 
						|
                    effect eVis     = EffectVisualEffect(VFX_IMP_DOMINATE_S);
 | 
						|
                    effect eLink    = EffectLinkEffects(eMind, eControl);
 | 
						|
                    eLink           = EffectLinkEffects(eLink, eDur);
 | 
						|
 | 
						|
                    SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oCreature);
 | 
						|
                    DelayCommand(1.0, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oCreature,
 | 
						|
                                                            MinutesToSeconds(nDuration), TRUE, -1, CasterLvl));
 | 
						|
 | 
						|
                    nHDLimit -= GetHitDice(oCreature);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        oCreature = GetNextObjectInShape(SHAPE_SPHERE, fMaxRange, lTarget, TRUE);
 | 
						|
    }
 | 
						|
 | 
						|
    DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
 | 
						|
}
 |