//// // 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); } }