Sgqvur
FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
- Reaction score
- 62
Optic Blast is more or less [pretty much =)] a clone of the Starcraft 2's Colossus Thermal Lance attack.
The underlying struct requires feeding it some points and other data after that it caries the actions.
Required libraries:
TimerUtils
GroupUtils
LightningRecycle
TimedEffect
The underlying struct requires feeding it some points and other data after that it caries the actions.
Required libraries:
TimerUtils
GroupUtils
LightningRecycle
TimedEffect
JASS:
//! zinc
library opticblast requires TimerUtils, GroupUtils, LightningRecycle, TimedEffect
{
constant integer ENERGY_BEAM_COUNT = 4;
constant real BEAM_MOVEMENT_UPDATES_PER_SECOND = 32;
constant string DEFAULT_SOUND_LOCATION = "Abilities\\Spells\\Human\\AerialShackles\\MagicLariatLoop1.wav";
constant string DEFAULT_EFFECT_LOCATION = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl";
constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL;
constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL;
location loc = Location(0, 0);
unit tmpu = null;
boolexpr filter;
function targets_allowed() -> boolean
{
unit u = GetFilterUnit();
boolean b;
b = IsUnitEnemy(u, GetOwningPlayer(tmpu));
return b;
}
struct sounddata
{
sound s;
}
function StopLoopingSoundTimed()
{
timer t = GetExpiredTimer();
sounddata sd = GetTimerData(t);
StopSound(sd.s, false, false);
sd.destroy();
ReleaseTimer(t);
}
function PlayLoopingSoundTimed(string file_location, real x, real y, real z, real duration, integer volume)
{
timer t = NewTimer();
sounddata sd = sounddata.create();
sound s = CreateSound(file_location, true, true, true, 10, 10, "SpellsEAX");
SetSoundVolume(s, volume);
SetSoundDistances(s, 2000, 2000);
/*SetSoundDistanceCutoff(s, 2000);*/
SetSoundPosition(s, x, y, z);
StartSound(s);
sd.s = s;
SetTimerData(t, sd);
TimerStart(t, duration, false, function StopLoopingSoundTimed);
}
function dummy()
{
opticblast(GetTimerData(GetExpiredTimer())).exe();
}
public struct opticblast
{
private
{
lightning beam[ENERGY_BEAM_COUNT];
real beam_distance_from_hit_to_move_to[ENERGY_BEAM_COUNT];
real beam_traveled_distance[ENERGY_BEAM_COUNT];
real t[ENERGY_BEAM_COUNT];
real t_inc[ENERGY_BEAM_COUNT];
integer slowest_beam_index;
timer executefuncer;
group damaged_units;
}
unit caster;
widget target;
string beam_model[ENERGY_BEAM_COUNT];
real beam_start_x[ENERGY_BEAM_COUNT];
real beam_start_y[ENERGY_BEAM_COUNT];
real beam_start_z[ENERGY_BEAM_COUNT];
real beam_hit_x[ENERGY_BEAM_COUNT];
real beam_hit_y[ENERGY_BEAM_COUNT];
real beam_move_to_x[ENERGY_BEAM_COUNT];
real beam_move_to_y[ENERGY_BEAM_COUNT];
real beam_duration[ENERGY_BEAM_COUNT];
integer beam_count;
boolean play_sound;
string sound_location = "";
boolean beam_spawn_effect[ENERGY_BEAM_COUNT];
string beam_effect_location[ENERGY_BEAM_COUNT];
real beam_hit_radius = 0;
real damage = 0;
method setup()
{
integer i = 0;
real dx = 0;
real dy = 0;
real highest_duration = 0;
integer highest_duration_index = 0;
PauseUnit(caster, true);
for (0 <= i < beam_count)
{
t<i> = 0;
t_inc<i> = 1.0 / (beam_duration<i> * BEAM_MOVEMENT_UPDATES_PER_SECOND);
dx = beam_move_to_x<i> - beam_hit_x<i>;
dy = beam_move_to_y<i> - beam_hit_y<i>;
beam_distance_from_hit_to_move_to<i> = SquareRoot(dx * dx + dy * dy);
if (highest_duration < beam_duration<i>)
{
highest_duration = beam_duration<i>;
highest_duration_index = i;
}
beam<i> = GetLightning(GetLightningIdByCodeName(beam_model<i>));
MoveLightningEx(beam<i>, false, beam_start_x<i>, beam_start_y<i>, beam_start_z<i>, beam_hit_x<i>, beam_hit_y<i>, 0);
}
slowest_beam_index = highest_duration_index;
damaged_units = NewGroup();
executefuncer = NewTimer();
SetTimerData(executefuncer, this);
TimerStart(executefuncer, 1.0 / BEAM_MOVEMENT_UPDATES_PER_SECOND, true, function dummy);
if (play_sound)
{
dx = GetWidgetX(target);
dy = GetWidgetY(target);
MoveLocation(loc, dx, dy);
if (sound_location == "" || sound_location == null)
PlayLoopingSoundTimed(DEFAULT_SOUND_LOCATION, dx, dy, GetLocationZ(loc), beam_duration[slowest_beam_index], 100);
else
PlayLoopingSoundTimed(sound_location, dx, dy, GetLocationZ(loc), beam_duration[slowest_beam_index], 100);
}
}
method exe()
{
integer i = 0;
real x = 0;
real y = 0;
for (0 <= i < beam_count)
{
t<i> = t<i> + t_inc<i>;
if (t<i> > 1)
{
if (beam<i> != null)
{
RecycleLightning(beam<i>, GetLightningIdByCodeName(beam_model<i>));
beam<i> = null;
}
}
else
{
x = beam_hit_x<i> + t<i> * (beam_move_to_x<i> - beam_hit_x<i>);
y = beam_hit_y<i> + t<i> * (beam_move_to_y<i> - beam_hit_y<i>);
MoveLocation(loc, x, y);
MoveLightningEx(beam<i>, false, beam_start_x<i>, beam_start_y<i>, beam_start_z<i>, x, y, GetLocationZ(loc));
beam_traveled_distance<i> = beam_traveled_distance<i> + t_inc<i> * beam_distance_from_hit_to_move_to<i>;
// if (ModuloReal(beam_traveled_distance<i>, beam_hit_radius) <= 16)
// {
tmpu = caster;
GroupEnumUnitsInArea(ENUM_GROUP, x, y, beam_hit_radius, filter);
tmpu = FirstOfGroup(ENUM_GROUP);
while (tmpu != null)
{
if (!IsUnitInGroup(tmpu, damaged_units))
{
UnitDamageTarget(caster, tmpu, damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS);
GroupAddUnit(damaged_units, tmpu);
}
GroupRemoveUnit(ENUM_GROUP, tmpu);
tmpu = FirstOfGroup(ENUM_GROUP);
}
// }
// if (ModuloReal(beam_traveled_distance<i>, 32.0) <= 8)
// {
if (beam_spawn_effect<i>)
{
if (beam_effect_location<i> == "" || beam_effect_location<i> == null)
{
AddSpecialEffectTimed(DEFAULT_EFFECT_LOCATION, x, y, beam_duration[slowest_beam_index] * (1 - t[slowest_beam_index]));
}
else
{
AddSpecialEffectTimed(beam_effect_location<i>, x, y, beam_duration[slowest_beam_index] * (1 - t[slowest_beam_index]));
}
}
// }
}
if (t[slowest_beam_index] > 1)
{
stop();
i = beam_count; // break;
}
}
}
method stop()
{
destroy();
ReleaseTimer(executefuncer);
ReleaseGroup(damaged_units);
PauseUnit(caster, false);
}
}
function spell_optic_blast() -> boolean
{
opticblast ob;
unit caster;
real cx;
real cy;
unit target;
real tx;
real ty;
real dx;
real dy;
real dirx;
real diry;
real dist;
real line_length;
caster = GetEventDamageSource();
if (GetUnitName(caster) == "Colossus" && !IsUnitPaused(caster))
{
cx = GetUnitX(caster);
cy = GetUnitY(caster);
target = GetTriggerUnit();
tx = GetUnitX(target);
ty = GetUnitY(target);
dx = tx - cx;
dy = ty - cy;
dist = SquareRoot(dx * dx + dy * dy);
dirx = dx / dist;
diry = dy / dist;
line_length = 256;
ob = opticblast.create();
ob.caster = caster;
ob.target = target;
ob.beam_model[0] = LIGHTNING_DRAIN_MANA;
ob.beam_start_x[0] = dirx * 128 + cx - 24;
ob.beam_start_y[0] = diry * 128 + cy;
ob.beam_start_z[0] = 295;
ob.beam_hit_x[0] = -diry * line_length * 0.5 + tx;
ob.beam_hit_y[0] = dirx * line_length * 0.5 + ty;
ob.beam_move_to_x[0] = diry * line_length * 0.5 + tx;
ob.beam_move_to_y[0] = -dirx * line_length * 0.5 + ty;
ob.beam_duration[0] = 0.49;
ob.beam_spawn_effect[0] = true;
ob.beam_model[1] = LIGHTNING_DRAIN_MANA;
ob.beam_start_x[1] = dirx * 128 + cx + 24;
ob.beam_start_y[1] = diry * 128 + cy;
ob.beam_start_z[1] = 295;
ob.beam_hit_x[1] = diry * line_length * 0.5 + tx;
ob.beam_hit_y[1] = -dirx * line_length * 0.5 + ty;
ob.beam_move_to_x[1] = -diry * line_length * 0.5 + tx;
ob.beam_move_to_y[1] = dirx * line_length * 0.5 + ty;
ob.beam_duration[1] = 0.5;
ob.beam_spawn_effect[1] = true;
ob.beam_count = 2;
ob.play_sound = true;
ob.beam_hit_radius = 128;
ob.damage = 100;
ob.setup();
}
return false;
}
function onInit()
{
unit u;
trigger t = CreateTrigger();
GroupEnumUnitsInRect(ENUM_GROUP, GetPlayableMapRect(), null);
u = FirstOfGroup(ENUM_GROUP);
while (u != null)
{
TriggerRegisterUnitEvent(t, u, EVENT_UNIT_DAMAGED);
GroupRemoveUnit(ENUM_GROUP, u);
u = FirstOfGroup(ENUM_GROUP);
}
TriggerAddCondition(t, Condition(function spell_optic_blast));
filter = Filter(function targets_allowed);
}
}
//! endzinc
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>