I Could Of Been A Grenadier :(

I’m having a heck of a time activating an item and having it explode at the target location. Help please, it’s driving me nuts!

Code so far:

object oPC = GetItemActivator();
     object oFlask = GetItemActivated();
     location lLoc = GetSpellTargetLocation();

     if ( GetTag(oItem) == "SILVER_IO" )
     {
        DoGrenade(d6(1),1, VFX_IMP_FLAME_M, VFX_FNF_FIREBALL, DAMAGE_TYPE_FIRE, RADIUS_SIZE_MEDIUM, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
     }

All that happens is the inadvertant detonation of my PC’s head, and that’s no good!

Shouldn’t the spell target location be baked into the Cast Spell: Activate Item(Long Range) parameter?

Shouldn’t the spell target location be baked into the Cast Spell: Activate Item(Long Range) parameter?

No, it isn’t. What the hell is “DoGrenade”?

DoGrenade() (it’s in x0_i0_spells) uses GetSpellTargetObject() or in case it’ invalid GetSpellTargetLocation().
Have you checked these values?
My guess is that DoGrenade can only be used in spells.

Just guessing, but are you casting Unique Power Self Only? If so, try the regular Unique Power spell. That will produce a target cursor that sets the target object or location.

That’s wat I was looking for, the target cursor. I didn’t have one. I guess I was using the wrong one. I’m gonna try the regular Unique Power. Hmmm, it seems like I’ve tried it before. I’ll double check though.-

Produces a bouncing potion bottle with accompanying splash effect, and damage effect.

That I already guessed. But how shall I tell you what’s wrong with your code, if I don’t see it? Ah, and I don’t know all the hidden functions in some include files.

And yes, using the power on self is most probably somewhat painful.

1 Like

I’m not sure if and how to use GetSpellTargetObject();

*/
//:://////////////////////////////////////////////
//:: Created By: Georg Zoeller
//:: Created On: 2003-07-16
//:://////////////////////////////////////////////

#include "x0_i0_spells"
#include "x2_inc_switches"
void main()
{
     object oItem = GetItemActivated();

     // * Generic Item Script Execution Code
     // * If MODULE_SWITCH_EXECUTE_TAGBASED_SCRIPTS is set to TRUE on the module,
     // * it will execute a script that has the same name as the item's tag
     // * inside this script you can manage scripts for all events by checking against
     // * GetUserDefinedItemEventNumber(). See x2_it_example.nss
     if (GetModuleSwitchValue(MODULE_SWITCH_ENABLE_TAGBASED_SCRIPTS) == TRUE)
     {
        SetUserDefinedItemEventNumber(X2_ITEM_EVENT_ACTIVATE);
        int nRet =   ExecuteScriptAndReturnInt(GetUserDefinedItemEventScriptName(oItem),OBJECT_SELF);
        if (nRet == X2_EXECUTE_SCRIPT_END)
        {
           return;
        }

     }

     // My code.
     object oPC = GetItemActivator();
     object oFlask = GetItemActivated();
     object oSpellTarget = GetSpellTargetObject();

     if ( GetTag(oFlask) == "SILVER_IO" )
     {
        DoGrenade(d6(1),1, VFX_IMP_ACID_S, VFX_FNF_GAS_EXPLOSION_ACID, DAMAGE_TYPE_ACID, RADIUS_SIZE_SMALL, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);

     }
}

As of right now, the PC just goes through the throwing animation, but no bouncy potion bottle or acid explosion on impact. Nothing…?

I assume you are getting a target cursor now?

Based on what @Kamiryn said, I have a theory.

DoGrenade uses the spell target functions, so you don’t have to.

However, by activating an item, you are in a module event, not a spell event, so the spell target functions may be undefined.

Interesting, when you activate an item, the first thing that happens is the spell script NW_S3_ActItem01, which signals EventActivateItem, passing the spell target.

There are target functions which ARE defined for the module event, namely, GetItemActivatedTarget() and GetItemActivatedTargetLocation().

If I’m right, you have at least two options:

  • Modify NW_S3_ActItem01 to call DoGrenade and exit if the item is SILVER_IO. This should work because it’s a spell event.
  • In the Item Activated event script, copy the DoGrenade code from x0_i0_spells to a function with a new name. Change the references to the spell target functions to the item activated target functions.

There might be a better way - maybe someone who’s made custom grenades can comment.

1 Like

P.S. I recall a comment from Jasperre that new grenades can be added to spells.2da with their own spell script. I guess you would use e.g. Grenade_FireBomb as a template.

IIRC that would also require a new item property linked to the spell.

Maybe that’s the right way to do it - though potentially more effort.

1 Like

Ah yes, as it happens I already stumbled over this problem in the last few days:

DoGrenade checks for “GetSpellTargetObject” automatically, but this doesn’t help. The best you can get from an activated item is “GetItemActivatedTarget” and
“GetItemActivatedTargetLocation”. Both values are not compatible with “GetSpellTargetObject”.

Well, creating a new grenade type and use one of the existing grende scripts as template, sounds good in my eyes. Or you just use Prolerics Grenade script, which works pretty well and can be found in “Dark Energy”.

Alright guys I’m going to try either Proleric’s script from his Dark Energy mod (is in my mod folder already) :slight_smile: or an existing grenade script and see what happens. I’ll post back the results.

You’re welcome, but it’s probably not ideal.

If I were doing it again, I’d check out DoGrenade first.

@Nizidramaniit

Grenades use the CAST SPELL property… so you must create/define any new spell in the spells.2da, which can then make use of the DoGrenade function.

Alternatively, edit one of the existing grenade scripts to intercept the TAG of your item and pass any new DoGrenade properties you need.

E.g. An example of one I have edited (x0_s3_alchem) for my own use …

IMPORTANT: This will NOT compile for anyone as it stands, as it uses my own include, but I hope you get the picture.

//::///////////////////////////////////////////////
//:: Alchemists fire // Rewritten by Lance Botelle for the Althéa Campaign.
//:: x0_s3_alchem
//:: Copyright (c) 2002 Bioware Corp. 
//:://////////////////////////////////////////////
/*
    Grenade.
    Fires at a target. If hit, the target takes
    direct damage. If missed, all enemies within
    an area of effect take splash damage.

    HOWTO:
    - If target is valid attempt a hit
       - If miss then MISS
       - If hit then direct damage
    - If target is invalid or MISS
       - have area of effect near target
       - everyone in area takes splash damage
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: September 10, 2002
//:://////////////////////////////////////////////
//:: GZ: Can now be used to coat a weapon with fire.
//:: JSH-OEI 12/4/08: Fixed bug where damage bonus wasn't applying to weapon.

#include "X2_I0_SPELLS"
#include "x2_inc_spellhook"
#include "alb_functions_unique"

void AddFlamingEffectToWeapon(object oTarget, float fDuration, int DamageBonus)
{   
   IPSafeAddItemProperty(oTarget, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_FIRE, DamageBonus), fDuration, X2_IP_ADDPROP_POLICY_KEEP_EXISTING);
   IPSafeAddItemProperty(oTarget, ItemPropertyVisualEffect(ITEM_VISUAL_FIRE), fDuration,X2_IP_ADDPROP_POLICY_KEEP_EXISTING,FALSE,TRUE);      
   
   	// ALLOW DESCRIPTION UPDATE
	DeleteLocalString(oTarget, "ITEMDECS");			
}

void main()
{
    
	if (!X2PreSpellCastCode())
    {
	    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }

	int nDmg; int nSplashDmg; int nDuration; int DamageBonus;
		
	object oItem = GetSpellCastItem();
		
	object oSource = OBJECT_SELF;	
	
	string sTag = GetTag(oItem);
	
	//SendMessageToAllPCs(" 1 >>>> " + sTag);
	//SendMessageToAllPCs(" 2 >>>> " + GetFirstName(oSource));
		
	//////////////////////////////////////////////////////////////////////////
	// SOURCE CREATED (SCREAT BONUS MODULE2)
	//////////////////////////////////////////////////////////////////////////
	
	int iSOURCE = GetLocalInt(oItem, "SCREATWEAPONBONUS");
	
	// ELSE STORED INSIDE ALB_AI_GRENADETHROW SCRIPT FROM NPC THROW		
	sTag = GetStringLowerCase(sTag);
	
	// FOR TRAPS (RECALL LEVEL FOR OBSIDIAN KLUDGE)
	if(sTag == "")
	{
		int nLevel = GetLocalInt(oSource, "NWN2_PROJECTILE_TRAP_CASTER_LEVEL");
		
		if(nLevel < 6){sTag = "x1_wmgrenade002";}
		else if(nLevel < 10){sTag = "n2_it_alch_2";}
		else if(nLevel < 15){sTag = "n2_it_alch_3";}
		else if(nLevel < 20){sTag = "n2_it_alch_4";}
						
		//SendMessageToAllPCs(" 3 >>>> " + sTag);
	}
	
	//SendMessageToAllPCs(" FINAL >>>> " + sTag);
		
	if (sTag == "x1_wmgrenade002"){nDmg = d6(1); nSplashDmg = 1; nDuration = d4(4); DamageBonus = IP_CONST_DAMAGEBONUS_1d4;}		
	else if (sTag == "n2_it_alch_2"){nDmg = d8(1); nSplashDmg = 2; nDuration = d4(6); DamageBonus = IP_CONST_DAMAGEBONUS_1d6;}
	else if (sTag == "n2_it_alch_3"){nDmg = d10(1); nSplashDmg = d4(1); nDuration = d6(6); DamageBonus = IP_CONST_DAMAGEBONUS_1d8;}
	else if (sTag == "n2_it_alch_4"){nDmg = d6(2); nSplashDmg = d4(1) + 1; nDuration = d6(8); DamageBonus = IP_CONST_DAMAGEBONUS_1d10;}

	effect eVis = EffectVisualEffect(VFX_COM_HIT_FIRE);
    // effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);    
	object oTarget = GetSpellTargetObject();
    
	int nTarget = GetObjectType(oTarget);
    
    if(nTarget == OBJECT_TYPE_ITEM)
    {        
		if(IPGetIsMeleeWeapon(oTarget) && (GetItemInSlot(INVENTORY_SLOT_RIGHTHAND) == oTarget || GetItemInSlot(INVENTORY_SLOT_LEFTHAND) == oTarget))
        {            
            SignalEvent(OBJECT_SELF, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE));            
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, GetItemPossessor(oTarget));
            // ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, GetItemPossessor(oTarget), RoundsToSeconds(nDuration));
            AddFlamingEffectToWeapon(oTarget, RoundsToSeconds(nDuration), DamageBonus);
			return;            
        }
        
		else if(GetItemPossessor(oTarget)!= OBJECT_INVALID)
        {
            // FloatingTextStrRefOnCreature(100944,OBJECT_SELF); // *  Only melee weapons can be coated with alchemist's fire! *
			SetNoticeTextAll(CRED + "<<< Only equipped melee weapons can be coated >>>", 1, 1, OBJECT_SELF);
        }
    }				    
	
	// ELSE JUST DO GRENADE	
	else
	{
		SendMessageToAllPCs(CWHITE + GetFirstName(OBJECT_SELF) + CORCHID + " throws a grenade: Alchemist's fire!");
		LBDoGrenade(nDmg, nSplashDmg, VFX_HIT_SPELL_FIRE, VFX_HIT_AOE_FIRE, DAMAGE_TYPE_FIRE, RADIUS_SIZE_MEDIUM, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, RACIAL_TYPE_ALL, iSOURCE);    
	}
}

I’m going to try that.

It comes back to me now that a Unique Power item only works as a ranged spell if you target a location, otherwise the caster runs up to the target object first. In Dark Energy I made a feature of that - you can blow yourself up by sandbagging targets with the Black Powder - but really that was lazy on my part.

1 Like

@Proleric

Yes, I also found an issue using any of the “Unique” type properties. It has to be the CAST SPELL property. I do all grenades like this now … simply intercept a TAG. I also updated/rewrote my own version of the DoGrenade function to accommodate some changes. :+1:

EDIT: In NWN2, we can also use “CAST SPELL: At Target”. (*)
( * ) In my own notes, this can be a Touch, Short Range or Long Range version.

Tried this out by giving the new grenade the Acid Bomb property, adding tag-based lines to x2_s3_bomb:

// Custom
    object oItem   = GetSpellCastItem();
    int    nDamage = d4(40);

    if (GetTag(oItem) == "BlackPowder2")
      {
         DoGrenade(nDamage, nDamage, VFX_IMP_FLAME_M, VFX_FNF_FIREBALL, DAMAGE_TYPE_BLUDGEONING, RADIUS_SIZE_LARGE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
         PlaySound("as_wt_thundercl3");
         return;
      }
// End custom

This is very satisfactory - even the sound effect plays at exactly the right time.

The only downside is that the item description etc says Acid Bomb. I’ll have a look at creating a custom spell so that I can add my own texts.

1 Like

Make a copy of the original item and change the description (which I would have thought you to have done anyway) … You have to delete the original text and remove any original text embedded in the item (although that may not be the case with NWN1 :thinking:. Then when it references the description, it should be correct. i.e. CLEAR the stringref. (Or do you mean somewhere else in its usage?)

I haven’t checked this out fully, but I think the item description in game includes a generated reference to the Acid Bomb property, as does the combat log.

Ok guys. I haven’t yet had a chance to try any of this. Proleric, your custom function looks promising.
Lance, thanks for chiming in and will look into.