Aller au contenu

Photo

Custom Weapon Property: Cast spell: Unique Power question


  • Veuillez vous connecter pour répondre
21 réponses à ce sujet

#1
mchotdog33

mchotdog33
  • Members
  • 31 messages
What happens right now like with the iron fist hammer and staff of the magi is that when you use the custom power, it seems that the it is being casted by a invisible person. This means that you have no way of knowing how much damage the cast actually did and if the enemies succeeded in the save or not since its not show in the combat log. You also don't get xp for the kills that the power did.

Is there some way to make the source of the cast be the user so the active of the weapon gives xp on kills and you know what it acutally did?

#2
Dann-J

Dann-J
  • Members
  • 3 161 messages
If the script uses something like the following:

ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamageEffect, oTarget);

...then the console will report that "someone" damaged / killed the target.

The script needs to assign all ApplyEffect functions to the character using the item in order for them to be responsible for the damage/death of the target. So it'd be more like:

object oItemUser = GetItemActivator();
AssignCommand(oItemUser, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamageEffect, oTarget));

Modifié par DannJ, 16 mars 2012 - 04:32 .


#3
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
Or it needs to assign the cheat command to the caster to fakecast the given spell with the staff of the magi.

Are you using a custom xp system or the default that comes with the game?

Modifié par painofdungeoneternal, 16 mars 2012 - 04:42 .


#4
mchotdog33

mchotdog33
  • Members
  • 31 messages
Using default, and Dannj got it on the nose, it either shows "someone" when it hits my party or nothing when it hits enemies. Gonna try out the assign command function.

Edit: Tried adding the assign command function to the staff of magi so it looks like:
DelayCommand(fDelay, AssignCommand(oPC,ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)));
but it still tells me that "someone" killed me.

2nd Edit: trying to think of a general solution to this since i'm thinking of making custom active powers on items. Would prefer not have to create a feat then add it to the weapon :)

Modifié par mchotdog33, 18 mars 2012 - 09:25 .


#5
Dann-J

Dann-J
  • Members
  • 3 161 messages
Nesting DelayCommand and AssignCommand can be tricky. I'm pretty sure you have to put the delay inside the AssignCommand, and not the other way around:

AssignCommand(oPC,DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget)));

#6
mchotdog33

mchotdog33
  • Members
  • 31 messages
I'll test it out and see how it goes. Thanks for helping out a noob like me.


Edit: That didn't work either. What's weird is that even if i take out the delay command, it still shows it as "someone" doing the damage.

Modifié par mchotdog33, 18 mars 2012 - 11:59 .


#7
Dann-J

Dann-J
  • Members
  • 3 161 messages
Are you using GetItemActivator() as the object to assign the command to (oPC)?

#8
mchotdog33

mchotdog33
  • Members
  • 31 messages
Yup i just used the script for staff of the magi and put in the assigncommand. The only part i changed is the bold part which is the assigncommand function. I even took out the delay in case it was screwing with the assigncommand. 

// OnActivate Script for Staff of the Magi
// Creates Retributive Strike.
// CGaw OEI 8/2/06

void main()
{
// * This code runs when the Unique Power property of the item is used
object oPC = GetItemActivator();
object oItem = GetItemActivated();
location lTarget = GetLocation(oPC);
int nCurrentCharges = GetItemCharges(oItem);

//Declare major variables
object oCaster = OBJECT_SELF;
int nDamage;
float fDelay;

/* Brock H. - OEI 03/03/06 -- Handled by the ImpactSEF column in the spells.2da
effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); */

effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M);
effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE);
effect eExplosion = EffectNWN2SpecialEffectFile("sp_mswarm_lrg_imp.sef");
effect eMagExplosion = EffectNWN2SpecialEffectFile("fx_magical_explosion.sef");
effect eDam;

ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eMagExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eShake, lTarget, 0.5f);

//Declare the spell shape, size and the location. Capture the first target object in the shape.
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);

//Cycle through the targets within the spell shape until an invalid object is captured.
while (GetIsObjectValid(oTarget))
{
//Get the distance between the explosion and the target to calculate delay
fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20;

// if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay))
// {
//Roll damage for each target
nDamage = 6 * nCurrentCharges;

//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
nDamage = GetReflexAdjustedDamage(nDamage, oTarget, 17, SAVING_THROW_TYPE_NONE);
//Set the damage effect
eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);

if(nDamage > 0)
{
// Apply effects to the currently selected target.
AssignCommand(oPC, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
//This visual effect is applied to the target object not the location as above. This visual effect
//represents the flame that erupts on the target not on the ground.
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
}
// }
//Select the next target within the spell shape.
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);
}

DestroyObject(oItem);
}

Modifié par mchotdog33, 19 mars 2012 - 10:33 .


#9
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
And you are testing this via a retributive strike ( when you break the staff ), or are you testing this with the various spells stored in that staff?

#10
mchotdog33

mchotdog33
  • Members
  • 31 messages
I am testing this by casting retributive strike. The spells stored in the staff works properly, giving me credit for the damage and kills and xp. Its the unique power thats being the problem.

Modifié par mchotdog33, 19 mars 2012 - 11:37 .


#11
Dann-J

Dann-J
  • Members
  • 3 161 messages
Perhaps the DestroyItem is clearing the item activator (since the item doesn't exist anymore)? You could try delaying the destruction of the item by a small amount:

DelayCommand(0.1, DestroyObject(oItem));

Modifié par DannJ, 20 mars 2012 - 12:43 .


#12
mchotdog33

mchotdog33
  • Members
  • 31 messages
I tried completely removing the destroy object and still nothing.

#13
Artemis Absinthe

Artemis Absinthe
  • Members
  • 59 messages
line 45, try this :

nDamage = GetReflexAdjustedDamage(nDamage, oTarget, 17, SAVING_THROW_TYPE_NONE, oPC);

#14
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
Another way is to use ExecuteScript to run a second script on the user of the item, and put the actual damage code in the second script. I think the last patch even added an ExecuteScript enhanced or something, so you could pass the target object on as a parameter.

#15
mchotdog33

mchotdog33
  • Members
  • 31 messages
Artemis: Nice thanks for that addition, now it shows all the save rolls but the damage is still from "someone"

Lugaid: Sorry but i don't understand what you mean by that? Could you elaborate? Sorta a noob at coding in nwn2. Would be great if you could give sample code.

#16
Dann-J

Dann-J
  • Members
  • 3 161 messages
This script is very similar to the dragon breath weapon scripts, with one exception - the breath weapon scripts tend to enclose the search-and-damage parts within their own 'wrapper' (really a custom function), then assign the entire wrapper to the caster in the 'Main' section, rather than just the ApplyEffect part. I don't know if that'd make any difference.

I modified the red dragon breath script to be run from an item (keeping the original wrapper function), and it works a treat using GetItemActivator rather than OBJECT_SELF. Substituting the cone spell shape for a sphere, and fire damage for magic, would result in pretty much what you want. You'll find my script mentioned here. There are great swathes of the script dedicated to getting the dragon's hit dice to determine the DC and damage which you can ignore though.

Modifié par DannJ, 20 mars 2012 - 09:48 .


#17
Lugaid of the Red Stripes

Lugaid of the Red Stripes
  • Members
  • 955 messages
The ExecuteScript function orders an object to run a script. You could write a second script that deals out damage to a designated target object, and use ExecuteScript to force your item user to run that script. Telling the script which creature to damage is trickier, and that's what requires the execute script enhanced functions. Those functions allow you to run a script with a parameter or two attached, just like you can run conversation scripts with parameters (variables passed on to the script from whoever is running it).

#18
The Fred

The Fred
  • Members
  • 2 516 messages
By default, the player *should* be the caster of the spell, just as if it were any other spell. I usually use Lugaid's trick to do the opposite (i.e. make it so that the PC doesn't anger NPCs by initiating a script), but it should work just fine here.

Basically, since the player will be executing this new script, they will be designated the initiator of any such hostile effect, which in this case is what you want.

#19
Artemis Absinthe

Artemis Absinthe
  • Members
  • 59 messages
 

mchotdog33 wrote...

Lugaid: Sorry but i don't understand what you mean by that? Could you elaborate? Sorta a noob at coding in nwn2. Would be great if you could give sample code.

 

this is the script, let's say, you called it "item_apply_damage" (the file will be item_apply_damage.nss)

void main()
{

location lTarget = GetLocalLocation(OBJECT_SELF, "target_loc");
object oItem = GetLocalObject(OBJECT_SELF, "item_ac");

int nCurrentCharges = GetItemCharges(oItem);

//Declare major variables
object oCaster = OBJECT_SELF;
int nDamage;
float fDelay;

/* Brock H. - OEI 03/03/06 -- Handled by the ImpactSEF column in the spells.2da
effect eExplode = EffectVisualEffect(VFX_FNF_FIREBALL); */

effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M);
effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE);
effect eExplosion = EffectNWN2SpecialEffectFile("sp_mswarm_lrg_imp.sef");
effect eMagExplosion = EffectNWN2SpecialEffectFile("fx_magical_explosion.sef");
effect eDam;

ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eMagExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eShake, lTarget, 0.5f);

//Declare the spell shape, size and the location. Capture the first target object in the shape.
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);

//Cycle through the targets within the spell shape until an invalid object is captured.
while (GetIsObjectValid(oTarget))
{
//Get the distance between the explosion and the target to calculate delay
fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20;

// if (!MyResistSpell(OBJECT_SELF, oTarget, fDelay))
// {
//Roll damage for each target
nDamage = 6 * nCurrentCharges;

//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
//back to the original, since the caller object is the player, so, it's back to OBJECT_SELF 
nDamage = GetReflexAdjustedDamage(nDamage, oTarget, 17, SAVING_THROW_TYPE_NONE);
//Set the damage effect
eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);

if(nDamage > 0)
{
// Apply effects to the currently selected target.
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
//This visual effect is applied to the target object not the location as above. This visual effect
//represents the flame that erupts on the target not on the ground.
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
}
// }
//Select the next target within the spell shape.
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);
}

DestroyObject(oItem);
}


this is the caller script, the item_ac :

void main()
{
object oPC = GetItemActivator();
object oItem = GetItemActivated();
location lTarget = GetLocation(oPC);

SetLocalLocation(OBJECT_SELF, "target_loc", lTarget);
SetLocalObject(OBJECT_SELF, "item_ac", oItem);

ExecuteScript("item_apply_damage",oPC);
}


This way you force the PC to execute the script, like a normal spell.



The Fred wrote...

By default, the player *should* be the caster of the spell, just as if it were any other spell.


The caster is the caller object, so, basically you're right since the caller object for spells is the spellcaster (PC), but in an item's unique power the caller is the item.

Modifié par Artemis Absinthe, 21 mars 2012 - 01:50 .


#20
mchotdog33

mchotdog33
  • Members
  • 31 messages
Ok thanks artemis. It almost worked like a charm except the local vars should have been set on oPC and not OBJECT_SELF on the _ac script. I'm assuming that OBJECT_SELF there woulda been the item.

Thanks for the help guys i think i got this down :)

#21
Artemis Absinthe

Artemis Absinthe
  • Members
  • 59 messages
yes, right, the local vars must be set on oPC, not OBJECT_SELF

I'm getting old ._.

#22
Dann-J

Dann-J
  • Members
  • 3 161 messages
The script below works (compiled and tested). I made a few enhancements of my own though:
- It now only damages enemies (previously it was damaging everyone)
- Instead of 6 x charges damage for all targets, it now does d6 per charge per target (and it's still devastating!)


// i_NW_WMGST003_ac
//
// OnActivate Script for Staff of the Magi
// Creates Retributive Strike.
// CGaw OEI 8/2/06
// Modified 22/3/2012 DannJ
#include "NW_I0_SPELLS"

void Kaboom(object oPC, object oItem);

void main()
{
object oPC = GetItemActivator();
object oItem = GetItemActivated();

AssignCommand(oPC, Kaboom(oPC, oItem));
DelayCommand(0.2, DestroyObject(oItem));

}

void Kaboom(object oPC, object oItem)
{
float fDelay;
int nDamage;
int nCurrentCharges = GetItemCharges(oItem);
location lTarget = GetLocation(oPC);
effect eDam;
effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE);
effect eExplosion = EffectNWN2SpecialEffectFile("sp_mswarm_lrg_imp.sef");
effect eMagExplosion = EffectNWN2SpecialEffectFile("fx_magical_explosion.sef");
effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M);

ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eMagExplosion, lTarget);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eShake, lTarget, 0.5f);

//Declare the spell shape, size and the location. Capture the first target object in the shape.
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);

//Cycle through the targets within the spell shape until an invalid object is captured.
while (GetIsObjectValid(oTarget))
{
if(oTarget != oPC && GetIsStandardHostileTarget(oTarget, oPC))
{
//Get the distance between the explosion and the target to calculate delay
fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oTarget))/20;

//Roll damage for each target
nDamage = d6(nCurrentCharges);

//Adjust the damage based on the Reflex Save, Evasion and Improved Evasion.
nDamage = GetReflexAdjustedDamage(nDamage, oTarget, 17, SAVING_THROW_TYPE_NONE);
//Set the damage effect
eDam = EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);

if(nDamage > 0)
{
// Apply effects to the currently selected target.
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
//This visual effect is applied to the target object not the location as above. This visual effect
//represents the flame that erupts on the target not on the ground.
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
}
}//end if enemy

//Select the next target within the spell shape.
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget);
}//end while

}

Modifié par DannJ, 22 mars 2012 - 06:04 .