Note: LucasForums Archive Project
The content here was reconstructed by scraping the Wayback Machine in an effort to restore some of what was lost when LF went down. The LucasForums Archive Project claims no ownership over the content or assets that were archived on archive.org.

This project is meant for research purposes only.

Stance Effects

Page: 1 of 1
 GrimShadow
11-03-2006, 7:18 AM
#1
I have been looking through the scripts and 2da files to try and find where the effects of stances are actually shown. I noticed some stances aid in FP regen, FP duration, FP damage, + single opponent, etc. Where would I be able to find these, and any other place for power cost (besides forceadjust.2da)?
 GrimShadow
11-03-2006, 5:37 PM
#2
Don't mean to bump, but I feel I need to explain what I meant a little further, and I'd like other people who might have already read this to read it again with a little more clarity of my intentions.

I'm not looking for force power cost like that defined in spells.2da. I'm looking for ways to increase or decrease the base cost due to a stance or possibly even a feat or agressive force power (maybe a force power that increases the cost of force powers on the opponent and possibly has other negative effects on the caster as well, like lowering damage or regen). I've looked through the forms' effects in k_inc_force, but I can't seem to find anything about the effect on cost, regen, or damage. I also can't seem to find where the force points are actually taken from the caster. Does anyone have any idea where this information is actually stored (or even if I'm just reading the script wrong)?
 stoffe
11-03-2006, 6:26 PM
#3
I'm looking for ways to increase or decrease the base cost due to a stance or possibly even a feat or agressive force power

Force point usage, and modifiers to it from force forms, is hardcoded in the game engine as far as I know and not handled by scripts. The base FP costs can be edited in spells.2da and LS/DS adjustments in forceadjust.2da, but there is no way to my knowledge to modify the cost of powers in an efficient manner. Most of the effects of saber and force forms are hardcoded, with a few exceptions in the force power impact script.

You could make a somewhat poor workaround by modifying the impact scripts of all force powers and apply a "Damage FP" effect to drain more FP, or "Heal FP" effect to restore some of the used FPs when a certain force form is selected (or other condition is met). The problem with this is that the impact script fires after the force power has already been cast, i.e. the player couldn't use the power if they don't have enough FPs left to match the standard FP cost (and inversely could cast the power if they have enough FP to match the standard FP cost even if the extra modifier would make it too expensive).
 GrimShadow
11-03-2006, 6:52 PM
#4
I saw EffectDamageForcePoints in nwnscript.nss. Then I know some of the force powers have a certain duration to them, which seems to deal a certain amount of damage each round (i.e force kill). Is there any way to apply the EffectDamageForcePoints function into an effect like this? Which would remove a set amount of force points each round? Since I don't believe that would require you to have the amount of force points that the spell requires (once the spell is cast of course), though I could be wrong. I'm not really certain how effects are actually applied each round though.

I also noticed EffectHealForcePoints, which could possibly simulated regen in the same way mentioned above, though as a buff (though I don't know if buffs use rounds, or if they just use duration alone).
 stoffe
11-03-2006, 7:19 PM
#5
I saw EffectDamageForcePoints in nwnscript.nss. Then I know some of the force powers have a certain duration to them, which seems to deal a certain amount of damage each round (i.e force kill).


Duration-effects (like the Buff/Defend powers such as Energy Resistance, Armor, Speed etc) and "damage over time" are two different techniques. Some types of effects can be given a duration when they are applied, and will last for that duration unless cleared out by a script or area transition (if applied to the player). The script only does something once to apply the effects, then they handle themselves on their own.

As for "damage over time" powers like Choke/Kill those are not a single effect applied, but a separate damage effect applied each time by a script function running with a delay. It either queues up the damage effects with a delay, or puts a function recursively with a delay on the script queue.

In either of the cases the impact script still only fires once, when the force power strikes the targetted character. As this always happens after the power has already been cast the impact script can't be used to affect how a power is cast (where the FP use is done). You can only react afterwards when the power has already been cast and either give back some of the FPs already spent, or take away a few more.


Is there any way to apply the EffectDamageForcePoints function into an effect like this? Which would remove a set amount of force points each round?


Sure, you can make a script that drains force points over time. A simple example that drains a set amount of FP every round for a specified number of rounds may look something like:
// ST: Forward declaration of recursive function.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining);

// ST: Main function, runs when the script is run.
void main() {
// ST: Drain 20 force points every round for 8 rounds.
DrainForce(GetSpellTargetObject(), 20, 8);
}

// ST: Recursive function used to drain force points.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining) {
if (iRoundsRemaining > 0) {
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamageForcePoints(iAmount), oVictim);
DelayCommand(RoundsToSeconds(1), DrainForce(oVictim, iAmount, --iRoundsRemaining));
}
}


One thing to beware of if you do like this in a force power though is that the recursive effects will be disconnected from the Force Power. I.e. if you remove all effects applied by a force power you won't get rid of those created (not applied, created) delayed during its impact script, since the game doesn't know they originated from that power. This also means that GetSpellId() is unreliable if delayed when called. That doesn't matter much in this case though since no duration effects are used.



I also noticed EffectHealForcePoints, which could possibly simulated regen in the same way mentioned above, though as a buff.

While you could do the same, there is already a health regen effect, EffectRegenerate(), which grants the object it's applied to health over a specified duration, which is much more efficient to use than scripting it manually.
 GrimShadow
11-03-2006, 8:15 PM
#6
So main() will continue to take effect as long as the conditions are met? So if iRoundsRemaining is no longer greater than 0, the force power will end? Also, the DelayCommand function would be delayed 6 seconds when RoundsToSeconds is used, right?

Also, since the EffectDamageForcePoints effect is only an instant function, and does not continue to take effect, it would happen each time the force power is applied, correct? So if the force power is cast twice on an enemy, the damage to the force points would happen for each cast, right? Would I be able to create a boolean in globalcat.2da that is set to 1 if the power is already active, and set back to 0 when the power ends? Something like this


// ST: Forward declaration of recursive function.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining);

// ST: Main function, runs when the script is run.
void main()
{
if (GetGlobalBoolean(booleanname) = 0)
{
// ST: Drain 20 force points every round for 8 rounds.
DrainForce(GetSpellTargetObject(), 20, 8);
}
}

// ST: Recursive function used to drain force points.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining)
{
if (iRoundsRemaining > 1)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamageForcePoints(iAmount), oVictim);
DelayCommand(RoundsToSeconds(1), DrainForce(oVictim, iAmount, --iRoundsRemaining));
SetGlobalBoolean(booleanname, 1);
}

if (iRoundsRemaining = 1)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamageForcePoints(iAmount), oVictim);
DelayCommand(RoundsToSeconds(1), DrainForce(oVictim, iAmount, --iRoundsRemaining));
SetGlobalBoolean(booleanname, 0);
}
}


EDIT: Also, is there any way of creating passive powers, kind of like deflect and redirect? It seems that those are both hardcoded, as they do not have a script, so I'm thinking it wouldn't be possible without having something call the script for the power (like an armband maybe).
 stoffe
11-03-2006, 11:23 PM
#7
So main() will continue to take effect as long as the conditions are met?


No, main() finishes execution a few milliseconds after the script is called, usually (the game assumes the script is stuck in an infinite loop and kills it if execution takes longer than a second). Scripts in the game execute in "bursts". They run, do their thing and immediately terminate.

In this example the main() function calls the function called DrainForce() and returns as soon as that function returns. The DrainForce() function checks if the round counter is larger than 0 and if this is the case it applies the FP damage effect, decreases the counter and adds a call to the DrainForce() function (itself) with a 1 round delay to the game's script command queue and then immediately returns back to main(), which makes the script terminate since nothing more should be done. After 1 round the queued command will run the DrainForce() function with the specified parameter values (i.e. the script itself will not be executed again, just the function added to the queue) which applies another FP damage effect, decreases the round counter and puts another call to itself with a 1 round delay in the script command queue. At least that's how I understand it. :)


So if iRoundsRemaining is no longer greater than 0, the force power will end? Also, the DelayCommand function would be delayed 6 seconds when RoundsToSeconds is used, right?


Yes, that parameter is used as a counter to see how many rounds remain that it should run. When no rounds remain the function will do nothing, which breaks the recursive "loop". As far as I have been able to determine a round in-game is roughly 3 seconds of real time.



Also, since the EffectDamageForcePoints effect is only an instant function, and does not continue to take effect, it would happen each time the force power is applied, correct?


Damage effects cannot have a duration, they are always applied as INSTANT. I.e. the damage will occur whenever you apply the effect to a target object, the effect does not linger after that. Thus the need for a recursive loop like the one above if you want damage that is applied over time, since there is no "deal X damage over Y seconds" effect in the scripting language.


So if the force power is cast twice on an enemy, the damage to the force points would happen for each cast, right?


Anything you put in the impact script would take place whenever the impact script runs, unless you block it out with a condition. If you cast Force Kill on a victim they will suffer the effect of two casts (unless they make their save, of course). The same goes here.


Would I be able to create a boolean in globalcat.2da that is set to 1 if the power is already active, and set back to 0 when the power ends? Something like this


You could, but that would assume that the power could only be cast by one character in the entire game, since globals are unique game-wide. If this is for a character-specific power (like the Beast Trick / Force Confusion powers in TSL are) that no one else can use that might work. Otherwise I'd suggest using a LocalBoolean set on the caster instead. That way it would only be blocked out for that caster while the power is still in effect, not a game-wide block for everyone. Depends on the situation though, what you want to happen. :)

Like:

// ST: Forward declaration of recursive function.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining);

// ST: Main function, runs when the script is run.
void main() {
// ST: Drain 20 force points every round for 8 rounds.
if (!GetLocalBoolean(OBJECT_SELF, 120)) {
SetLocalBoolean(OBJECT_SELF, 120, TRUE);
DrainForce(GetSpellTargetObject(), 20, 8);
}
}

// ST: Recursive function used to drain force points.
void DrainForce(object oVictim, int iAmount, int iRoundsRemaining) {
if (iRoundsRemaining > 0) {
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamageForcePoints(iAmount), oVictim);
DelayCommand(RoundsToSeconds(1), DrainForce(oVictim, iAmount, --iRoundsRemaining));
}
else {
SetLocalBoolean(OBJECT_SELF, 120, FALSE);
}
}




EDIT: Also, is there any way of creating passive powers, kind of like deflect and redirect? It seems that those are both hardcoded, as they do not have a script, so I'm thinking it wouldn't be possible without having something call the script for the power (like an armband maybe).

Not that I know of, since they don't use the regular spell/force power system, but rather function like feats instead. They are never activated or cast, the game engine just checks if the character knows them as conditionals for if certain things should happen. Those things are handled internally in the game engine, AFAIK.
 GrimShadow
11-04-2006, 12:23 AM
#8
I noticed you mentioned heartbeat scripts in another thread. So would it be possible to fake a passive force power by checking if the character has the power (which you mentioned in Your Reply (http://www.lucasforums.com/showpost.php?p=1825117&postcount=4) to the topic Creating Lightsaber Forms (http://www.lucasforums.com/showthread.php?t=149535)) and having the force power's script activate if the character has it?
 stoffe
11-04-2006, 6:46 PM
#9
I noticed you mentioned heartbeat scripts in another thread. So would it be possible to fake a passive force power by checking if the character has the power (which you mentioned in Your Reply (http://www.lucasforums.com/showpost.php?p=1825117&postcount=4) to the topic Creating Lightsaber Forms (http://www.lucasforums.com/showthread.php?t=149535)) and having the force power's script activate if the character has it?

You could get a roughly similar effect, though it's a bit clumsier since you'll need to constantly check if the effects are already applied, and if not apply them again. This is since even PERMANENT duration effects get cleared when you transition to another module, or by the ClearAllEffects() script command that some cutscenes use.

In theory I think the easiest way is probably to make a normal "active" force power and have the heartbeat insta-cheatcast it on the character once, and then check continually if the character is affected by that spell with GetHasSpellEffect(), and if not insta-cast it again.

This will require you to edit the default and party AI scripts though to add support for maintaining the power if a character has it.

(An alternative, if the desired effects are available as item properties, is to make a creature hide with the desired properties and then have the power place that hide in th character's creature hide inventory slot. You'd still need to check for the presence of the passive power in order to activate it, but you wouldn't have the problem with potentially cleared out effects, or effects lost due to area transitions.)
Page: 1 of 1