Help with custom OnHitCastSpell property

Hi, i’m creating some abilities that can simulate attack rolls and damage rolls. I have managed to simulate almost everything. Right now i’m going to simulate the OnHit properties. I started with the OnHitCastSpell. Here is the code:

void CastIPPOnHitSpell(object oWeapon, object oDefender,object oAttacker)
{
	location lTarget = GetLocation(oDefender);
	object oDummy = CreateObject(OBJECT_TYPE_CREATURE, "c_attachspellnode" , lTarget);
	SetScriptHidden(oDummy, TRUE,FALSE);
	
	itemproperty ipLoop=GetFirstItemProperty(oWeapon);
	int nPropertyType;
	while (GetIsItemPropertyValid(ipLoop))
	{
		nPropertyType = GetItemPropertyType(ipLoop);	
		if (nPropertyType == ITEM_PROPERTY_ONHITCASTSPELL)
		{
			int nOnHitRow = GetItemPropertySubType(ipLoop);//iprp_onhitspell.2DA Row No.
			
			int nSpellID = StringToInt(Get2DAString(sIPRP_OnHit2DA, "SpellIndex", nOnHitRow));
			int nLvL= GetItemPropertyCostTableValue(ipLoop);//iprp_onhitspell.2DA Cost(Spell LvL)

			AssignCommand(oDummy,ActionCastSpellAtObject(nSpellID,oDefender,METAMAGIC_ANY,TRUE,nLvL,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
		}
		ipLoop=GetNextItemProperty(oWeapon);
	}
	
	DestroyObject(oDummy, 3.0);
}

What i want to do here is to cast the spell from the position of the Defender(target that you hitted), i’m using a temporal invisible creature to cast the spell from there but for some reason, it doesn’t cast it.

Also, i have been testing it by using the Arrow of Detonation as oWeapon which haves OnHit: Fireball level 10 but the CostValue is returning 9 instead of 10, i want to know why is that.

well, first off

nDomainLevel of ActionCastSpellAtObject() doesn’t work, as far as i’m aware. When bCheat is set TRUE, the cast is at level 10.

 
but offhand i couldn’t say why it isn’t working … eg, can ScriptHidden creatures cast spells? Instead of “c_attachspellnode” try a creature with AppearanceType #611 InvisibleMan perhaps.

because the row# in Iprp_SpellCstr.2da for Level10 is “9” …

I changed “c_attachspellnode” for “c_human” and removed the ScriptHidden() function and still doesn’t cast the spell.

try plenty of debug

const string sIPRP_OnHitSpell2DA = "iprp_onhitspell";

// note: 'oAttacker' is not used.
void CastIPPOnHitSpell(object oWeapon, object oDefender)
{
	SendMessageToPC(GetFirstPC(FALSE), "CastIPPOnHitSpell - " + GetName(OBJECT_SELF) + " ( " + GetTag(OBJECT_SELF) + " )");
	SendMessageToPC(GetFirstPC(FALSE), ". oWeapon valid= "   + IntToString(GetIsObjectValid(oWeapon)));
	SendMessageToPC(GetFirstPC(FALSE), ". oDefender valid= " + IntToString(GetIsObjectValid(oDefender)));

	object o = CreateObject(OBJECT_TYPE_CREATURE, "c_human", GetLocation(oDefender));
//	SetScriptHidden(o, TRUE, FALSE);

	SendMessageToPC(GetFirstPC(FALSE), ". creature valid= " + IntToString(GetIsObjectValid(o)));


	itemproperty ipScan = GetFirstItemProperty(oWeapon);
	while (GetIsItemPropertyValid(ipScan))
	{
		if (GetItemPropertyType(ipScan) == ITEM_PROPERTY_ONHITCASTSPELL) // id into ItemPropDef
		{
			SendMessageToPC(GetFirstPC(FALSE), ". . OnHitCastSpell FOUND");

			int iSubtype = GetItemPropertySubType(ipScan); // spelltype -> id into Iprp_OnHitSpell
			int iSpellId = StringToInt(Get2DAString(sIPRP_OnHitSpell2DA, "SpellIndex", iSubtype));

			int iCost = GetItemPropertyCostTableValue(ipScan); // spelllevel -> id into Iprp_SpellCstr

			AssignCommand(o, ActionCastSpellAtObject(iSpellId, oDefender, METAMAGIC_ANY, TRUE, iCost, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
//			break; // check for multiple OnHitCastSpell ips
		}
		ipScan = GetNextItemProperty(oWeapon);
	}

	DestroyObject(o, 3.0);
}

Still doesn’t work correctly, sometimes it cast the spell also, it doesn’t show how much damage it did in the chat log. I think that i’m going to go with this:

void CastIPPOnHitSpell(object oWeapon, object oDefender,object oAttacker)
{
	itemproperty ipLoop=GetFirstItemProperty(oWeapon);
	int nPropertyType;
	while (GetIsItemPropertyValid(ipLoop))
	{
		nPropertyType = GetItemPropertyType(ipLoop);	
		if (nPropertyType == ITEM_PROPERTY_ONHITCASTSPELL)
		{
			int nOnHitRow = GetItemPropertySubType(ipLoop);//iprp_onhitspell.2DA Row No.
			
			int nSpellID = StringToInt(Get2DAString(sIPRP_OnHit2DA, "SpellIndex", nOnHitRow));
			int nLvL = GetItemPropertyCostTableValue(ipLoop)+1;//iprp_spellcstr.2da
			SetLocalInt(OBJECT_SELF,"CUSTOM_CASTER_LVL",nLvL);
			AssignCommand(oAttacker,ActionCastSpellAtObject(nSpellID,oDefender,METAMAGIC_ANY,TRUE,nLvL,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
		}
		ipLoop=GetNextItemProperty(oWeapon);
	}
	DelayCommand(2.0,DeleteLocalInt(OBJECT_SELF,"CUSTOM_CASTER_LVL"));
}

The spell will be casted from the Attacker but i will going to create a custom version for the spells that use projectiles and i’m going to remove it so they are casted instantly on the target. Also, i need to edit them anyway to add the proper caster spell since as you said, the Cheat parameter make the caster spell 10. Thanks anyway for the code.

1 Like

consider placing

AssignCommand(oAttacker, ClearAllActions(TRUE));

just before ActionCastSpell …

(note that would clear all but the last OnHitCast in the loop though)

/just a thought

if you’re going to do that, i’d consider making a lineup of scripts that are specifically geared to doing this damage by projectiles, and bypassing ActionCastSpell altogether