**EDIT**
Looks like the way to do this is Spell-hooking... but the tutorial/nwnlexicon recently went down... so... how does one do this?
Modifié par EpicFetus, 19 juin 2013 - 07:48 .
Modifié par EpicFetus, 19 juin 2013 - 07:48 .
Modifié par EpicFetus, 19 juin 2013 - 07:28 .
#include "x2_inc_switches"
void Magestar(object oMagestar)
{
// !!TODO
}
// checks whether oTarget has a Magestar; if so, does the magestar stuff and returns TRUE.
int checkMagestar(object oTarget, int nSpellLevel)
{
if(GetLocalInt(oTarget,"nMagestar")==1)
{
//Block it, get the spell level, apply to Magestar
object oMagestar = GetLocalObject(oTarget,"oMagestar");
int nPool = GetLocalInt(oMagestar,"nPool");
SetLocalInt(oMagestar,"nPool",nPool+nSpellLevel);
Magestar(oMagestar);
return TRUE;
}
return FALSE;
}
int getSpellShape(int nSpell)
{
switch (nSpell)
{
// !!TODO: add all spell with a circular shape here
case SPELL_FIREBALL:
case SPELL_STINKING_CLOUD:
return SHAPE_SPHERE;
// !!TODO: add all spells with a cone shape here
case SPELL_CONE_OF_COLD:
return SHAPE_CONE;
default: return -1; // single target spell
}
return -1;
}
float getShapeSize(int nSpell)
{
switch (nSpell)
{
case SPELL_FIREBALL: return RADIUS_SIZE_HUGE;
// !!TODO: return for each spell which is not single targeted its shape size
default: return 0.0;
}
return 0.0;
}
void main()
{
object oTarget = GetSpellTargetObject();
location lTarget;
int nSpell = GetLastSpell();
int nHarm = StringToInt(Get2DAString("spells", "HostileSetting", nSpell));
int nSpellLevel = GetSpellLevel(nSpell); //L-E-V-E-L
int nShape = getSpellShape(nSpell);
float fShapeSize = getShapeSize(nSpell);
int bMagestarFound = FALSE;
//Magestar System
/*
Blocks the spell, gives the Magestar it's props
*/
if (nHarm)
{
if (nShape == -1) // single target
{
bMagestarFound = checkMagestar(oTarget, nSpellLevel);
}
else
{
if (GetIsObjectValid(oTarget)) // spell was cast on an object
{
lTarget = GetLocation(oTarget);
}
else // spell was cast at the ground
{
lTarget = GetSpellTargetLocation();
}
oTarget = GetFirstObjectInShape(nShape, fShapeSize, lTarget);
while (GetIsObjectValid(oTarget)) // loop over all creatures in spell shape
{
// if oTarget has a magestar, switch bMagestarFound to TRUE, otherwise let it unchanged
bMagestarFound |= checkMagestar(oTarget, nSpellLevel);
oTarget =GetNextObjectInShape(nShape, fShapeSize, lTarget);
}
}
if (bMagestarFound) // at least one creature had a magestar
{
SetModuleOverrideSpellScriptFinished();
return;
}
}
}
Modifié par diophant, 24 juin 2013 - 04:33 .
diophant wrote...
You can do everything in the spellhooking script. Unfortunately, I realized that the 2da file does not tell you whether a spell is an AoE spell or not; it's all coded in the spell scripts. Moreover, AoE spell is not the correct check, because also spells like fireball and cone of cold must be considered, which are not AoE spells. Thus, you must write two functions where you return for each spell the spell shape and the shape size. To get these values (especially the size), check the original spell scripts.
I implemented the main functions, but you still have to complete the functions for spell shape and size.
MasterChanger wrote...
Dio, you're overlooking something. While, yes, the true shape of the spell is defined in the script, the 2da does have a convenient way to figure out the target area. The field is called TargetingUI, which links to spelltarget.2da (an under-analyzed 2da that I have a bit of experience with). While there isn't anything to say that the targeting UI shape has to be the same as whatever is set in the script, it should really be good enough for these purposes.
int getSpellShape(int nSpell)
{
int nShape = StringToInt(Get2DAString("spells", "TargetingUI", nSpell));
string sShapeName = Get2DAString("spelltarget", "Shape", nShape);
if (sShapeName == "point")
return -1;
if (sShapeName == "circle")
return SHAPE_SPHERE;
if (sShapeName == "cone")
return SHAPE_CONE;
// what should we do in the following cases?
// if (sShapeName == "rectangle")
// return -2;
// if (sShapeName == "bolt")
// return -2;
return -1;
}
float getShapeSize(int nSpell)
{
int nShape = StringToInt(Get2DAString("spells", "TargetingUI", nSpell));
return StringToFloat(Get2DAString("spelltarget", "Width", nShape));
}
This may seem like necroposting, but I've been adding to my spellhooking script...and for some reason the nSpell is -1...no matter what I cast or who casts is.
void main()
{
object oTarget = GetSpellTargetObject();
int nSpell = GetLastSpell();
int nHarm = GetLastSpellHarmful();
int nSpellLevel = GetSpellLevel(nSpell); //L-E-V-E-L
SendMessageToPC(OBJECT_SELF,"Spell is "+IntToString(nSpell));
I get back "Spell is -1", for Light and Resistance.
okay, unless I aim the spell at an object covered in the hook, then it's 100, but only for the PC (for light)
Solved...don't use GetLastSpellCast(); Use GetSpellId().
Last gives weird results...sometimes what you want, sometimes not.
Id gives the spell being cast...so, if you're using if(nSpell==....) to determine what to run, use Id.
Hi All,
!!!!!!!!!! NEVER ADD SKINS TO PCS !!!!!!!!!!!!
I have not read every post in this thread yet, but NEVER add skins to PCs. Here's why:-
http://worldofalthea...k/search?q=skin :-
11 October 2010: A short while ago, I discovered that using a skin in a PC's creature armour slot caused problems when the PC later equipped or unequipped armour: The armour penalty figures would eventually start to miscalculate and give errors with skill scores. At the time, I thought I resolved the problem by using an adapted creature bite object instead. Unfortunately, only this week, I discovered that this adapted item also caused problems, but this time with unarmed combat: If a PC with the adapted bite item on them attacked an object with unarmed combat, then only bonus strength damage would be applied. This was obviously not going to work and I came to the conclusion that skin items did not work anymore with NWN2.
Cheers,
Lance.
EDIT: Spellhooking is the way to go ... It fires prior to a spell being cast as long as a spell has this line at the beginning:-
if (!X2PreSpellCastCode()){return;}
Here is the first few lines of my own alb_spellcast spell-hook script to give you some info, (which I use quite extensively in spells and crafting). I think the comments are still valid:-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SPELL HOOKING (THIS SCRIPT) DOES NOT APPEAR TO FIRE IF THE PLAYER IS NOT POSSESSING THE PC AT THE TIME THE
// SPELL IS BEING CAST. i.e. IF THE COMPANION CASTS A SPELL USING ITS AI THIS SCRIPT IS NOT CHECKED.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main()
{
// OBJECT_SELF is the PC in this script by default. (LB)
object oPC = OBJECT_SELF; //CASTER
// SendMessageToAllPCs("CASTER >> " + GetName(oPC));
object oItem = GetSpellCastItem();
object oTarget = GetSpellTargetObject();
location lLocation = GetSpellTargetLocation();
int SpellID = GetSpellId();
int iSpellLevel = GetSpellLevel(SpellID);
int nLevel = CIGetSpellInnateLevel(SpellID,TRUE);
string sTag = GetTag(oItem);
string sRes = GetResRef(oItem);
int Charges = GetItemCharges(oItem);
string sName = GetFirstName(oItem); // FOR RECOVERY
int CASTSET = GetLocalInt(oItem, "CASTLEVEL"); // FOR RECOVERY
int nCasterLvl = GetCasterLevel(OBJECT_SELF);
Would events on an equipped skin work? I don't know, just a thought.
So, equip a skin to the player...weird.
Yes, a skin seems to be the easiest solution (if they have an OnSpellCastAt slot - I'm not at my toolset to check that). How could I forget about it!
You can add an OnHit item property to the skin, and use a tag-based OnHit script. <SNIP>
See my last post ... Unless you guys can tell me it is possible in some way to get around these skin issues?
Cheers,
Lance.
The ability penalties applied to the player at the beginning of Mask of the Betrayer are achieved by equipping a 'creature hide' on the PC. That prevents resting or restoration spells from removing the penalties. It also has the side effect of causing an exported character to continue to have the penalties, unless you wait until the cutscene that destroys the 'creature hide'.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SPELL HOOKING (THIS SCRIPT) DOES NOT APPEAR TO FIRE IF THE PLAYER IS NOT POSSESSING THE PC AT THE TIME THE
// SPELL IS BEING CAST. i.e. IF THE COMPANION CASTS A SPELL USING ITS AI THIS SCRIPT IS NOT CHECKED.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
Lance,
to get spellhooking to work on non-player controlled characters, set
X2_L_WILD_MAGIC = TRUE
on the area-object.
ps. Here's some more goodies for spellhooks
GetSpellId(); // returns the SPELL_* constant of the spell cast GetSpellTargetObject(); // returns the targeted object of the spell, if valid GetSpellTargetLocation(); // returns the targeted location of the spell, if valid GetLastSpellCastClass(); // gets the class the PC cast the spell as GetSpellCastItem(); // if an item cast the spell, this function gets that item GetSpellSaveDC(); // gets the DC required to save against the effects of the spell GetCasterLevel(OBJECT_SELF); // gets the level the PC cast the spell as
re: Never add skins to PCs... erm, ooops. Oh well, i'm screwed then. I've used creature hides in a number of places for different effects over the years.
It certainly may explain some strange things that happen with our Lycanthrope playable races : https://github.com/A...rs-PW/issues/86