Files
HeroesStone_PRC8/_module/nss/wi_bof.nss
Jaysyn904 1eefc84201 Initial Commit
Initial Commit.
2025-09-14 15:40:46 -04:00

151 lines
6.5 KiB
Plaintext

////
// Bead of Force
// Created by Solias (sorcerer@wnwn.net)
// http://www.wnwn.net/
//
// This script implements the unique power for the bead of force item.
// Include it into your item handler and call the functions below
//
//
// actions to be taken by the creature on a bounce
// loc is the location to bounce to.
void wi_bounce_creature(location loc);
// calculate where a creature should land after a blast
// creature - location of creature hit by blast
// blast - blast point
// blast_strength - maximum distance to throw creature
// max_range - if you want to use a linear fall-off function to determine how far to throw
// the creatures then set this value to the maximum blast radius, if you want to
// blast all creatures with the same force then set this value to 0.0 (the default).
// blast_strength should be less than max range or the effects may look strange.
location wi_calculate_blast(location creature, location blast, float blast_strength=3.0, float max_range=0.0);
// This function will apply the bead of force effect at the given location
// self is the location of the user, target is the target he chose.
void wi_bof_effect(object self, location target);
// actions to be taken by the creature on a bounce
void wi_bounce_creature(location loc) {
ClearAllActions();
JumpToLocation(loc);
ActionDoCommand(SetCommandable(TRUE));
SetCommandable(FALSE);
}
// calculate where a creature should land after a blast
location wi_calculate_blast(location creature, location blast, float blast_strength, float max_range=0.0) {
// Calculate the direction vector from blast through creature
vector vc = GetPositionFromLocation(creature);
vector vb = GetPositionFromLocation(blast);
vector dv = vc - vb;
float blast_distance = VectorMagnitude(dv);
// Calculate blast strength (linear fall-off):
if(max_range > 0.0) {
// Case 1: target out of blast range
if(blast_distance >= max_range) blast_strength = 0.0;
// Case 2: Target at blast point
// In this case just choose a random direction to blast the creature.
// Use maximum strength
else if(blast_distance <= 0.0) dv = AngleToVector(IntToFloat(Random(360)));
// Case 3: Target in range
else {
blast_distance = (max_range - blast_distance) / max_range;
blast_strength = blast_strength * blast_distance;
}
}
// Even if we are not using linear fall-off we still need to avoid degenerate vectors
else if(blast_distance <= 0.0) dv = AngleToVector(IntToFloat(Random(360)));
// Normalize the vector since all we want is direction
dv = VectorNormalize(dv);
// Calculate final displacement vector
dv = (dv * blast_strength);
// Return the new location
return Location(GetAreaFromLocation(creature), vc + dv, GetFacingFromLocation(creature));
}
// This function will apply the bead of force effect at the given location
void wi_bof_effect(object self, location target) {
location self_location = GetLocation(self);
effect bead = EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_MIND);
effect blast = EffectVisualEffect(VFX_FNF_SOUND_BURST);
effect shake = EffectVisualEffect(VFX_FNF_SCREEN_BUMP);
effect field = EffectVisualEffect(VFX_DUR_GLOBE_INVULNERABILITY);
effect impact = EffectVisualEffect(VFX_IMP_SUNSTRIKE);
effect strike = EffectVisualEffect(VFX_IMP_KNOCK);
effect damage = EffectDamage(d6(5),DAMAGE_TYPE_BLUDGEONING);
effect hold = EffectParalyze();
effect immune_blunt = EffectDamageResistance(DAMAGE_TYPE_BLUDGEONING, 60);
effect immune_pierce = EffectDamageResistance(DAMAGE_TYPE_PIERCING, 60);
effect immune_slash = EffectDamageResistance(DAMAGE_TYPE_SLASHING, 60);
float fDist = GetDistanceBetweenLocations(self_location, target);
float fDelay = fDist/(3.0 * log(fDist) + 2.0);
int object_filter = OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE;
float blast_radius = 6.0;
// Create moving bead visual
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, bead, target);
// Play area blast
DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, blast, target));
DelayCommand(fDelay, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, shake, target));
// Find who gets affected
object target_object = GetFirstObjectInShape(SHAPE_SPHERE, blast_radius, target, TRUE, object_filter);
while(target_object != OBJECT_INVALID) {
if(!GetIsReactionTypeFriendly(target_object, self)) {
// Damage them
DelayCommand(fDelay + 0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, damage, target_object));
DelayCommand(fDelay + 0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, impact, target_object));
// Creatures only
if(GetObjectType(target_object) == OBJECT_TYPE_CREATURE) {
// Blast them away from impact point
location landing_point = wi_calculate_blast(GetLocation(target_object), target, 7.0, 6.5);
DelayCommand(fDelay + 0.6, AssignCommand(target_object, wi_bounce_creature(landing_point)));
// Give them a reflex save and make sure they are not immune to paralysis
if(ReflexSave(target_object, 16) == 0 && GetIsImmune(target_object,IMMUNITY_TYPE_PARALYSIS) == 0) {
// Trap them in a force sphere
float duration = IntToFloat(d6(3)) * 10.0;
DelayCommand(fDelay + 0.9, ApplyEffectToObject(DURATION_TYPE_INSTANT, strike, target_object));
DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, field, target_object, duration));
DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, hold, target_object, duration));
DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, immune_blunt, target_object, duration));
DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, immune_pierce, target_object, duration));
DelayCommand(fDelay + 1.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, immune_slash, target_object, duration));
}
}
}
// Get next object
target_object = GetNextObjectInShape(SHAPE_SPHERE, blast_radius, target, TRUE, object_filter);
}
}