Heya!
For those of you who bothered with the few threads I started in the past few weeks, you're well aware that I'm a noob with modding. So, now that I'm done with new items and placed them within the game, I moved on to FPs about three days, but then it was the 4th and then France won, and...
*cough* *cough*
Anyway... I'm still new to this, but, so far, buffs are a stroll through the park. Same goes for simple offensive force powers on a single enemy or a mob.
Scripts are so far rather simple and tacky, but the FPs work in-game.
Now, for some reason, I just can't the damage to work on this one infuriating FP...
The spell is basically a cold blast which freezes the target, deals damage to it and slows the nearby enemies (not allies) if they fail their saves.
Now, I basically started with the same scripts than the previous version of the spell (dmg & freeze effect on single target and that's it). Damage and freeze worked just fine then, but I just can't get it to work on this one. Most likely because of all the lines for the effect area... Hell, it's probably because of ONE line...
Oh, btw, the entries for effect (I know I can link them!) may seem weird, but that was just for testing purposes and *see* a difference between oTarget and the mob during testing, lol.
So here it is: can just one of the FP scripting experts look at it and tell me what's wrong?
Spell decompiles just fine. No problem with the .2da either. ALL effects but the cold dmg work just fine. grrr....
#include "k_inc_force"
//Cold Blast II
void main()
{
float FREEZE_DURATION = 12.0;
SWFP_HARMFUL = TRUE;
SWFP_PRIVATE_SAVE_TYPE = SAVING_THROW_REFLEX;
SWFP_PRIVATE_SAVE_VERSUS_TYPE = SAVING_THROW_TYPE_COLD;
object oTarget = GetSpellTargetObject();
int nDice = GetHitDice(OBJECT_SELF);
SWFP_DAMAGE = Sp_CalcDamage( oTarget, nDice, 5, 0);
SWFP_DAMAGE_TYPE = DAMAGE_TYPE_COLD;
int nSpellID = GetSpellId();
effect eInvalid;
location lLoc = GetLocation(oTarget);
effect eBeam = EffectBeam(2051, OBJECT_SELF, BODY_NODE_HAND); //Cold Ray/Blast
effect eIce = EffectVisualEffect(2055); //Ice Spikes
effect eSolid = EffectVisualEffect(2054); //Ice-Frozen
effect eStuck;
if(GetRacialType(oTarget) != RACIAL_TYPE_DROID)
{
eStuck = EffectParalyze();
}
else
{
eStuck = EffectDroidStun();
}
eStuck = SetEffectIcon(eStuck, 102);
effect eSlow = EffectMovementSpeedDecrease(50);
eSlow = SetEffectIcon(eSlow, 15);
effect eDam = EffectDamage(SWFP_DAMAGE, SWFP_DAMAGE_TYPE);
effect eDam2 = EffectDamage(SWFP_DAMAGE/2, SWFP_DAMAGE_TYPE);
int nSaves = Sp_MySavingThrows(oTarget);
int nResist = Sp_BlockingChecks(oTarget, eDam, eInvalid, eInvalid);
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), SWFP_HARMFUL));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam, oTarget, 1.0);
if(nResist == 0)
{
if(nSaves != 0)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSlow, oTarget, 3.0);
}
else {
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eIce, oTarget, FREEZE_DURATION + 3.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSlow, oTarget, FREEZE_DURATION + 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStuck, oTarget, FREEZE_DURATION);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSolid, oTarget, FREEZE_DURATION);
}
}
object oNear = GetFirstObjectInShape(SHAPE_SPHERE, 10.0, lLoc);
while (GetIsObjectValid(oNear)) {
if ((oNear != oTarget) && GetIsEnemy(oNear) && !GetIsDead(oNear))
{
if(nResist == 0)
{
if(nSaves != 0)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStuck, oNear, 3.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSolid, oNear, 3.0);
}
else {
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStuck, oNear, 9.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSolid, oNear, 9.0);
}
}
}
oNear = GetNextObjectInShape(SHAPE_SPHERE, 10.0, lLoc);
}
}
Yeah, so, as was said earlier, I KNOW the script is no expert's feat. First time I went for a "unique effect on oTarget" and "different effect on mob" kind of thing...
Well?
Now, for some reason, I just can't the damage to work on this one infuriating FP...
The problem is on this line:
SWFP_DAMAGE = Sp_CalcDamage( oTarget, nDice, 5, 0);
SWFP_DAMAGE will always have the value 0 after this line. You are using 5 as value for the dice size parameter when calling the Sp_CalcDamage() function, which is not a valid dice size, which will cause the function to return 0 as value to signal an error. If you use that function the Dice Size parameter value must be one of 0, 2, 3, 4, 6, 8, 10, 12, 20 or 100.
ROTFLMAO.
1 - Oh.
I had "4" for the first tier and didn't want to jumpt to "6" right away, lol.
Huh.
Turns out I *WAS* right when I said it was about a single line. And one of the simplest at that, lol.
Thanks a bunch!
2 - Mmm... You wrote "use THAT fonction". What other dice-like function is there?
3 - BUT, Let's say I would want "fixed" damage based on PC's level, just like Force Wave.
The line for FWave is...
SWFP_DAMAGE = Sp_CalcDamage( oTarget, 0, 0, GetHitDice(OBJECT_SELF) + GetHitDice(OBJECT_SELF)/2 );
So, what, if I wanted 2.5 the PC's level, I'd just type in:
(GetHitDice(OBJECT_SELF)*2.5) ???
But then again, wouldn't they had used the *1.5 for FWave if it was possible? Saw dividers (force Whirlwind), but no multipliers...
Or (we're still talking about the 2.5) would I have to add another "+GetHitDice(Object_SELF)" ???
Seriously, I just wouldn't want to type in 3 times "+GetHitDice(Object_SELF)" just to get 3 times a PC's lvl worth of dmg...
Can't remember any FP with fixed dmg like this (over 1x the lvl) and the "+ GetHitDice(OBJECT_SELF)/2" part just seems... huh, tacky.
4 - I was gonna look at Lightsaber throw in k_inc_force.ncs for another example of fixed/capped dmg, but, huh... is the LSbr throw damage hardcoded?
Just so we're clear, I don't want to upgrade it (10-60 dmg at lvl 20 for a weapon with a 2-12/24 base dmg is pretty damn strong - especially for a KOTOR1 ltsbr...). I'm just curious.
2 - Mmm... You wrote "use THAT fonction". What other dice-like function is there?
Well you could make your own custom function instead of using the one in k_inc_force.nss. I don't use that include file for any custom powers I've made since I think it's a bit bloated and oddly organized. I've made my own include file with functions tweaked to my liking instead. In this particular case, for example, I'd use the function ST_CalcDamage():
int ST_CalcDamage(object oTarget, int nNumDice, int nSizeDice, int nNonRandom = 0) {
int nDamage = 0;
if (nNonRandom == 0) {
switch(nSizeDice) {
case 2: nDamage = d2(nNumDice); break;
case 3: nDamage = d3(nNumDice); break;
case 4: nDamage = d4(nNumDice); break;
case 6: nDamage = d6(nNumDice); break;
case 8: nDamage = d8(nNumDice); break;
case 10: nDamage = d10(nNumDice); break;
case 12: nDamage = d12(nNumDice); break;
case 20: nDamage = d20(nNumDice); break;
case 100: nDamage = d100(nNumDice); break;
default:
nDamage = Random(nNumDice * nSizeDice) + 1;
if (nDamage < nNumDice)
nDamage = nNumDice;
break;
}
}
else {
nDamage = nNonRandom;
}
if(IsFormActive(OBJECT_SELF, FORM_FORCE_I_FOCUS)) {
nDamage += 3;
}
else if(IsFormActive(OBJECT_SELF, FORM_FORCE_II_POTENCY)) {
nDamage += (nDamage * 30) / 100;
}
return nDamage;
}
...which does more or less the same thing, but accepts any number as dice size.
3 - BUT, Let's say I would want "fixed" damage based on PC's level, just like Force Wave.
Sp_CalcDamage( oTarget, 0, 0, GetHitDice(OBJECT_SELF) + GetHitDice(OBJECT_SELF)/2 );
So, what, if I wanted 2.5 the PC's level, I'd just type in:
(GetHitDice(OBJECT_SELF)*2.5) ???
But then again, wouldn't they had used the *1.5 for FWave if it was possible?
Some script and programming languages don't like when you mix integer and floating point operations in the same expression. I don't remember if NWScript works this way. If that's the case you can work around it by converting the values, like:
int iDmg = FloatToInt(IntToFloat(GetHitDice(OBJECT_SELF)) * 2.5);
int iDice = Sp_CalcDamage( oTarget, 0, 0, iDmg);
Which would be the same as:
int iHD = GetHitDice(OBJECT_SELF);
int iDice = Sp_CalcDamage( oTarget, 0, 0, (iHD*2) + (iHD/2));
4 - I was gonna look at Lightsaber throw in k_inc_force.ncs for another example of fixed/capped dmg, but, huh... is the LSbr throw damage hardcoded?
The Saber throw effect that can be applied with a script unfortunately has the damage hardcoded within the effect. Nothing to do about that I'm afraid.
aight.
Here's another question...
How the hell do you script the hand up animation WITHOUT a beam? Like, let's say Force Wave.
Force Wave entry in k_inc_force.ncs is most unhelpful...
Tried early this morning to mimic some of the Force Wave line (FNF and IMP effects on ObjectSelf was pretty much all there was if I remember correctly - can't remember exactly, I'm not at home...)...
But I just can't find any having to do with the "head" casting animation. That, and I always would end up with the default animation anyway...
Sadly enough, I don't really remember any modded/released force power pack with said animation either...
So... how do I get rid of that default hand animation and replace it?
P.S. And YES, once again, I'm aware of how much this is merely that blasted cherry on top of the sundae, lol
How the hell do you script the hand up animation WITHOUT a beam? Like, let's say Force Wave.
Force Wave entry in k_inc_force.ncs is most unhelpful...
The cast animations are not handled by the impact script (which usually runs when the animation is already halfway through playing). This is set on the line of the power in spells.2da. Set the value in the castanim column to up, and that animation will be used.
Meh.
Put the "up" value in CONJanim instead...
Sigh. My bad, lol.
The joys of over-worrying with the more "complicated" stuff only to forget something insanely simple... :D
Ah, hell.
Something else is wrong. Only the TARGET's saves are taken into account...
What went wrong?
#include "k_inc_force"
//Cold Bomb II
void main()
{
SWFP_HARMFUL = TRUE;
SWFP_PRIVATE_SAVE_TYPE = SAVING_THROW_FORT;
SWFP_PRIVATE_SAVE_VERSUS_TYPE = SAVING_THROW_TYPE_COLD;
object oTarget = GetSpellTargetObject();
int nDice = GetHitDice(OBJECT_SELF);
SWFP_DAMAGE = Sp_CalcDamage( oTarget, 0, 0, (nDice*2));
SWFP_DAMAGE_TYPE = DAMAGE_TYPE_COLD;
int nSpellID = GetSpellId();
effect eInvalid;
location lLoc = GetLocation(oTarget);
object oNear = GetFirstObjectInShape(SHAPE_SPHERE, 6.67);
effect eBeam = EffectBeam(1017, OBJECT_SELF, BODY_NODE_HEAD);
effect eBomb = EffectVisualEffect(3009); //cryoban grenade
effect eIce = EffectVisualEffect(2055); //Ice chunks
effect eSolid = EffectVisualEffect(2054); //Ice Bumpout
effect eStuck;
if(GetRacialType(oTarget) != RACIAL_TYPE_DROID)
{
eStuck = EffectParalyze();
}
else
{
eStuck = EffectDroidStun();
}
eStuck = SetEffectIcon(eStuck, 102);
effect eSlow = EffectMovementSpeedDecrease(50);
eSlow = SetEffectIcon(eSlow, 15);
effect eFort = EffectSavingThrowDecrease(SAVING_THROW_FORT, 2);
effect eRflx = EffectSavingThrowDecrease(SAVING_THROW_REFLEX, 2);
effect eDam = EffectDamage(SWFP_DAMAGE, SWFP_DAMAGE_TYPE);
effect eDam2 = EffectDamage(SWFP_DAMAGE/2, SWFP_DAMAGE_TYPE);
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), SWFP_HARMFUL));
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eBomb, lLoc);
int nResist = Sp_BlockingChecks(oNear, eDam, eInvalid, eInvalid);
int nSaves = Sp_MySavingThrows(oNear);
while (GetIsObjectValid(oNear)) {
if (GetIsEnemy(oNear) && !GetIsDead(oNear))
{
if(nResist == 0)
{
if(nSaves != 0)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam2, oNear);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eIce, oNear, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSlow, oNear, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRflx, oNear, 6.0);
}
else {
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oNear);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStuck, oNear, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSolid, oNear, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eIce, oNear, 6.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eSlow, oNear, 9.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRflx, oNear, 9.0);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFort, oNear, 9.0);
}
}
}
oNear = GetNextObjectInShape(SHAPE_SPHERE, 6.67, lLoc);
}
}
Something else is wrong. Only the TARGET's saves are taken into account...
You are checking the resists/immunity and saving throws with the Sp_BlockingChecks() and Sp_MySavingThrows() functions outside the while-loop that iterates through nearby targets. Thus the checks are only performed for the first creature to be assigned to the oNear-variable and keep those same values for all subsequent iterations.
I.e. if the first creature makes their save, they have made their save for everyone else as well. :)
Oh. Works just fine now, lol.
Just in case there's another noob reading, all I had to do was to bump down
int nResist = Sp_BlockingChecks(oNear, eDam, eInvalid, eInvalid);
int nSaves = Sp_MySavingThrows(oNear);
right after
while (GetIsObjectValid(oNear)) {
P.S. Eh, now I know why that one simply went right over my head. I used the script of a similar customized script meant for a single-target FP...