- Joined
- Jul 17, 2013
- Messages
- 544
Hey! its first time i copied jass trigger to my map. i didnt brother with jass triggers before because they seemed too hard for me.i am editing in gui. this is the knockback i used Spell - Max Bash 2.1c
i coppied all jass triggers to my map + max bash abbility, and buff + dummy unit + chest item. after i openned map i made sure for dummy and max bash ability id to be same like in my map. and thats all
i tested spell in game it worked perfectly. the problem is always after EXCATLY 20 minuts of game triggers from my map starts randomly running while they arent supossed to. and some of ai units also walks very strange just like they would be knocked back.i am sure knockback is reason of this
this system is cool but sometimes it damages my gui triggers.or maybe i didnt install it correctly? insturction said about importing dummy model but i couldnot see it in that map with max bash spell
btw i noticed that there are lines like
// Change me from */ to // and then back to */ after saving and reopening the map
// i gotta admit i didnt do that because i didnt notice it maybe it caused this problem?
ALSO I REALISED SOMETHING IMPORTANT! it enables many triggers which have event a units enters region.but i checked replay and no unit entered regions and still trigger enabled.
there are jass triggers of this spell from my map!
i coppied all jass triggers to my map + max bash abbility, and buff + dummy unit + chest item. after i openned map i made sure for dummy and max bash ability id to be same like in my map. and thats all
i tested spell in game it worked perfectly. the problem is always after EXCATLY 20 minuts of game triggers from my map starts randomly running while they arent supossed to. and some of ai units also walks very strange just like they would be knocked back.i am sure knockback is reason of this
btw i noticed that there are lines like
// Change me from */ to // and then back to */ after saving and reopening the map
// i gotta admit i didnt do that because i didnt notice it maybe it caused this problem?
ALSO I REALISED SOMETHING IMPORTANT! it enables many triggers which have event a units enters region.but i checked replay and no unit entered regions and still trigger enabled.
there are jass triggers of this spell from my map!
JASS:
//TESH.scrollpos=0
//TESH.alwaysfold=0
// *******************************************************************************
// Spell: Max Bash by Dark Dragon
//
// Credits: IceFrog -> Used in Dota! Idea is by someone...
// Venom -> Icon
// nerovesper -> Request
//
//
// Installation:
//
// 1. Copy 'DD Library' and this trigger to your map
// 2. Copy abilitie and buff 'Max Bash' to your map
// 3. Export and import "DDSpells\MaxBashHit.mdx" and icons with same path to your map if you are going to use them
// 4. Modifie data below to mach your map and other constants
//
// * Enjoy!
// *******************************************************************************
//! zinc
// *** This is the max bash spell library ***
library MaxBash requires DDLib
{
// ======================================================================
// *** Editable constants ***
// ======================================================================
// -------------------------------------------------------
// This is the raw code of max bash ability
// Default: 'MBsh'
constant integer MAX_BASH_ID = 'MBsh';
// -------------------------------------------------------
// This is the raw code of max bash buff
// Default: 'MBed'
constant integer MAX_BASH_BUFF_ID = 'MBed';
// ----------------------------------------------------------
// Push model file effect
// Default: Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl
constant string PUSH_MODEL_FILE = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl";
// ----------------------------------------------------------
// Push model file effect of sliding unit, attach point
// Default: foot
constant string PUSH_EFFECT_ATT_POINT = "foot";
// ----------------------------------------------------------
// If custom water effect is wanted set this to true
// Default: true
constant boolean USE_WATER_FILE = true;
// ----------------------------------------------------------
// Push model file effect on water
// Default: Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl
constant string PUSH_MODEL_WATER_FILE = "Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl";
// -------------------------------------------------------
// On push file (when ability is triggerd) applay this effect
// Default: DDSpells\\MaxBashHit.mdx
constant string ON_PUSH_FILE = "DDSpells\\MaxBashHit.mdx";
// -------------------------------------------------------
// How often to create "PUSH_MODEL_FILE" effect
// Default: .1
constant real PUSH_EFFECT_INTERVAL = .15;
// -------------------------------------------------------
// On which point of attacker "ON_PUSH_FILE" is added?
// Default: weapon
constant string ATTACH_POINT = "weapon";
// -------------------------------------------------------
// Effect generated on target unit when its hit
// Default: none
constant string BASH_HIT_EFFECT_FILE = "";
constant string BASH_HIT_EFFECT_FILE_ATT_POINT = "origin";
// -------------------------------------------------------
// Effect generated when unit hits the ground
// Default: Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl
constant string BASH_HIT_GROUND_EFFECT_FILE = "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl";
// -------------------------------------------------------
// Effect generated when unit hits/impacts the water, requires USE_WATER_FILE to be true
// Default: Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl
constant string BASH_IMPACT_WATER_EFFECT_FILE = "Objects\\Spawnmodels\\Naga\\NagaDeath\\NagaDeath.mdl";
// -------------------------------------------------------
// While unit is sliding, what will be its animation speed in percentage
// Default: 65.
constant real UNIT_ANIM_SPEED = 65.;
// -------------------------------------------------------
// While unit is sliding, what will be its animation
// Default: attack
constant string UNIT_ANIM_NAME = "death";
// -------------------------------------------------------
// Extra damage that bash deals seted up by level "function BashDamage" will
// be treated as extra/bonus damage or as percentage of dealt damage,
// if true percent damage will be dealt
// Default: true
constant boolean BASH_DAMAGE_AS_PERCENTAGE = true;
// -------------------------------------------------------
// This is speed in game coordinates, of how fast unit is pushed away
// defined start and end speeds of pushed unit
// start speed = initial speed, end speed = speed before stopping
// Default: 350 / 50
constant real PUSH_SPEED_START = 200.;
constant real PUSH_SPEED_END = 50.;
// -------------------------------------------------------
// Enemy units that collide with sliding unit will be slightly pushed too?
// Default: true
constant boolean ENABLE_SPLASH_BASH = false;
// -------------------------------------------------------
// Damage splashed on extra colliding units in percentage
// Default: 30%
constant real SPLASH_DAMAGE_PERCENTAGE = 30.;
// -------------------------------------------------------
// The min speed at which sliding unit has to be to cause pushing other unit
// Default: 175.
constant real SPLASH_BASH_NEED_SPEED = 100.;
// -------------------------------------------------------
// The area/radius around sliding unit to check for splash damage
// Default: 120.
constant real SPLASH_BASH_SCAN_R = 120.;
// -------------------------------------------------------
// How often to check for splash bash damage
// Default: .2
constant real SPLASH_BASH_INTERVAL = .2;
// -------------------------------------------------------
// Some units have default ground offset height, what is that max height
// so that bash does treat this units as grounded
// Default: 50.
constant real SPLASH_BASH_MAX_HEIGHT = 50.;
// -------------------------------------------------------
// Should trees be destroyed?
// Default: true
constant boolean DESTROY_TREES = false;
// -------------------------------------------------------
// How often to clear trees
// Default: .2
constant real CLEAR_TREES_INTERVAL = .2;
// -------------------------------------------------------
// Range in which to clear trees
// Default: 160.
constant real CLEAR_TREES_RADIUS = 160.;
// -------------------------------------------------------
// Range at which to check if pathing is unpathable, for bounce code to be triggerd
// Default: 60.
constant real BOUNCE_DETECT_RANGE = 60.;
// -------------------------------------------------------
// Should floating text be created?
// Default: true
constant boolean ALLOW_FLOATING_TEXT = false;
// -------------------------------------------------------
// When units are killed by bash display KO or damage dealt
// Default: true
constant boolean USE_KO_TEXT = true;
// -------------------------------------------------------
// The duration of floating text in seconds
// Default: 4.25
constant real FLOATING_TEXT_DURATION = 3.;
// -------------------------------------------------------
// The color of text rgb transparency in percentage
// Default: 100. / 100. / 100. / 20.
constant real FLOATING_TEXT_RED = 100.;
constant real FLOATING_TEXT_GREEN = 100.;
constant real FLOATING_TEXT_BLUE = 100.;
constant real FLOATING_TEXT_TRANS = 20.;
// -------------------------------------------------------------
constant key UNIT_BASH_KEY;
// -------------------------------------------------------------
// *** Level data setup here ***
// -------------------------------------------
// *** The bash damage per level ***
// Default: 2.6 / 3.4 / 4.5
function BashDamage(integer level) -> real {
real bash_damage[];
bash_damage[1] = 0.0;
bash_damage[2] = 0.0;
bash_damage[3] = 0.0;
return bash_damage[level];
}
// -------------------------------------------
// *** The bash push distance per level ***
// Default: 300. / 300. / 300.
function BashPushDistance(integer level) -> real {
real bash_range[];
bash_range[1] = 230.;
bash_range[2] = 350.;
bash_range[3] = 200.;
return bash_range[level];
}
// -------------------------------------------
// *** The bash push height per level ***
// Default: 150. / 150. / 150.
function BashPushHeight(integer level) -> real {
real bash_height[];
bash_height[1] = 150.;
bash_height[2] = 150.;
bash_height[3] = 150.;
return bash_height[level];
}
// -------------------------------------------
// *** The bash push height travel percentage per level ***
// This setting says at which percentage of path will unit land
// Default: 40. / 40. / 40.
function BashPushHeightTravelPerc(integer level) -> real {
real bash_height_travel_perc[];
bash_height_travel_perc[1] = 40.;
bash_height_travel_perc[2] = 40.;
bash_height_travel_perc[3] = 40.;
return bash_height_travel_perc[level];
}
// -------------------------------------------
// *** The damaged dealt by impact
// Default: 50. / 50. / 50.
function BashPushGroundImpactDamage(integer level) -> real {
real bash_ground_impact_damage[];
bash_ground_impact_damage[1] = 120.;
bash_ground_impact_damage[2] = 300.;
bash_ground_impact_damage[3] = 120.;
return bash_ground_impact_damage[level];
}
// -------------------------------------------
// *** If splash bash is activated, this will filter which are proper units to be pushed.
function SplashBashFilter(unit filter_unit, player bashPlayer) -> boolean {
return !IsUnitType(filter_unit, UNIT_TYPE_DEAD) &&
IsUnitEnemy(filter_unit, bashPlayer) &&
IsUnitType(filter_unit, UNIT_TYPE_GROUND) &&
!BlzIsUnitInvulnerable(filter_unit) &&
!IsUnitType(filter_unit, UNIT_TYPE_STRUCTURE) &&
!DDIsUnitWard(filter_unit);
}
// ==================================================================================
// *** End spell modification ***
// ==================================================================================
// ---------------------------------------------------------
// *** Bash data structure
struct bash {
private {
unit b, s;
real dist, mxdist, impdist;
real dx, dy, initZ;
p_real z_parab;
real dmg;
p_real vec;
integer p, lvl;
boolean hit_ground;
}
/// ----------------------------------------------------------------
// ***
static method create(integer castplayer, unit bashingUnit, unit whichUnit, integer lvl, real distance, real radians, real damage) -> bash {
bash this = allocate();
s = bashingUnit;
b = whichUnit;
dist = distance;
mxdist = SquareRoot(distance);
dx = Cos(radians);
dy = Sin(radians);
vec = pVector(GetUnitX(b), GetUnitY(b), GetUnitFlyHeight(b));
p = castplayer;
dmg = damage;
hit_ground = BashPushGroundImpactDamage(lvl) < 1.;
// -------------------------
// a(x-x0)^2 + y0 = a(x^2 - 2x*x0 + x0^2) + y0 = a*(x)^2 - 2*a*x0*(x) + a*x0^2+y0
// -------------------------
// x0 = mxDist(100-perc/2)/100
// y0 = vec[2] + h
// a = -h / (mtd/2)^2
// b = -2*a*x0
// c = y0+a*x0^2
z_parab = p_real.create();
z_parab[0] = -BashPushHeight(lvl) / Pw_2(BashPushHeightTravelPerc(lvl)*distance/200.); // a = -h / (mtd/2)^2
z_parab[1] = -2. * z_parab[0] * ((100.-BashPushHeightTravelPerc(lvl)/2.)*distance/100.); // b = -2*a*x0
z_parab[2] = (BashPushHeight(lvl) + vec[2]) + z_parab[0]*Pw_2((100.-BashPushHeightTravelPerc(lvl)/2.)*distance/100.); // c = a*x0^2+y0
this.lvl = lvl;
impdist = (100.-BashPushHeightTravelPerc(lvl))*distance/100.;
initZ = vec[2];
DDSet(b, UNIT_BASH_KEY, this);
UnitAddAbility(b, 'Amrf');
UnitRemoveAbility(b, 'Amrf');
SetUnitTimeScale(b, UNIT_ANIM_SPEED*.01);
if (!IsUnitType(b, UNIT_TYPE_DEAD)) {
SetUnitAnimation(b, UNIT_ANIM_NAME);
QueueUnitAnimation(b, "stand");
}
return this;
}
// ***
method destroy() {
DDSet(b, UNIT_BASH_KEY, p_null);
SetUnitTimeScale(b, 1.);
vec.destroy();
z_parab.destroy();
s = null;
b = null;
deallocate();
}
method operator IsAirborn() -> boolean { return !hit_ground; }
/// ----------------------------------------------------------------
//* splash code
private method TryDoSplashBash() {
integer i;
unit u;
// *** Skip splash if unit is in air ***
if (vec[2] > SPLASH_BASH_MAX_HEIGHT)
return;
// --------------------------------------
// *** pick units to be splash bashed
DDGroupFillMemArea(vec[0], vec[1], SPLASH_BASH_SCAN_R, p, function() -> boolean {
return SplashBashFilter(GetFilterUnit(), Player(DDMemUnitData())) && DDGet(GetFilterUnit(), UNIT_BASH_KEY) == p_null;
});
// --------------------------------------------------------------
// *** Now launch them in there respective directions and speeds
for(i=0; i < DDMemUnitN(); i+=1) {
u = DDMemUnit(i);
// *** Do damage and bash the target ***
UnitDamageTarget(s, u, dmg*SPLASH_DAMAGE_PERCENTAGE*.01, true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
BashExecute.evaluate(p, s, u, lvl, dist, Atan2(GetUnitY(u)-vec[1], GetUnitX(u)-vec[0]), dmg);
// *** Floating text add? ***
static if (ALLOW_FLOATING_TEXT)
static if (USE_KO_TEXT)
if (IsUnitType(u, UNIT_TYPE_DEAD))
DDNewTextTagUnit(u, "|cffff0000KO!!!|r", FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(u, "+"+I2S(R2I(dmg*SPLASH_DAMAGE_PERCENTAGE*.01)), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(u, "+"+I2S(R2I(dmg*SPLASH_DAMAGE_PERCENTAGE*.01)), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
}
}
// -------------------------------------------------------------------------
// * checks and performs ground impact as well as dealing damage and displaying floating text
method CheckGroundHit() {
if (impdist > dist) {
vec[2] = initZ;
if (!hit_ground) {
hit_ground = true;
static if (USE_WATER_FILE)
if (IsTerrainPathable(vec[0], vec[1], PATHING_TYPE_FLOATABILITY))
DestroyEffect(AddSpecialEffect(BASH_HIT_GROUND_EFFECT_FILE, vec[0], vec[1]));
else
DestroyEffect(AddSpecialEffect(BASH_IMPACT_WATER_EFFECT_FILE, vec[0], vec[1]));
else
DestroyEffect(AddSpecialEffect(BASH_HIT_GROUND_EFFECT_FILE, vec[0], vec[1]));
if (!IsUnitType(b, UNIT_TYPE_DEAD)) {
UnitDamageTarget(s, b, BashPushGroundImpactDamage(lvl), true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
// *** Floating text add? ***
static if (ALLOW_FLOATING_TEXT)
static if (USE_KO_TEXT)
if (IsUnitType(b, UNIT_TYPE_DEAD))
DDNewTextTagUnit(b, "|cffff0000KO!!!|r", FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(b, "+"+I2S(R2I(BashPushGroundImpactDamage(lvl))), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(b, "+"+I2S(R2I(BashPushGroundImpactDamage(lvl))), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
}
}
}
}
/// ----------------------------------------------------------------
//* primary push code
method Launch() {
DDStartTim(DD_INTERVAL, true, this, static method() {
bash this = bash( DDTimData() );
integer tick = DDTimTick();
real speed = DD_INTERVAL * (PUSH_SPEED_END + ( (PUSH_SPEED_START-PUSH_SPEED_END)/mxdist )*SquareRoot(dist));
// basic formula for speed: y = a*sqrt(x) + b
// ----------------------------------
// *** Position calcs
dist -= speed;
vec[0] += speed * dx;
vec[1] += speed * dy;
vec[2] = (z_parab[0]*Pw_2(dist)) + (z_parab[1]*dist) + (z_parab[2]);
// ------------------------------------
// *** Check if hit ground ***
CheckGroundHit();
// ----------------------------------
// *** Motion
SetUnitX(b, vec[0]);
SetUnitY(b, vec[1]);
SetUnitFlyHeight(b, vec[2], 0.);
// ----------------------------------
// *** Push Effects
if (ModuloReal(tick*DD_INTERVAL, PUSH_EFFECT_INTERVAL) < DD_INTERVAL)
static if (USE_WATER_FILE)
if (IsTerrainPathable(vec[0], vec[1], PATHING_TYPE_FLOATABILITY) || vec[2] > SPLASH_BASH_MAX_HEIGHT)
DestroyEffect(AddSpecialEffectTarget(PUSH_MODEL_FILE, b, PUSH_EFFECT_ATT_POINT));
else
DestroyEffect(AddSpecialEffectTarget(PUSH_MODEL_WATER_FILE, b, PUSH_EFFECT_ATT_POINT));
else
DestroyEffect(AddSpecialEffectTarget(PUSH_MODEL_FILE, b, PUSH_EFFECT_ATT_POINT));
// ----------------------------------------
// *** Check if trees are in the way
static if (DESTROY_TREES)
if (ModuloReal(tick*DD_INTERVAL, CLEAR_TREES_INTERVAL) < DD_INTERVAL) {
DDEnumDestsInRange(vec, CLEAR_TREES_RADIUS, null, function() {
if (DDIsDestructableTree(GetEnumDestructable()))
KillDestructable(GetEnumDestructable());
});
}
// ---------------------------------------------------------
// *** Check for bounce/collision with unpathable points
if (ModuloReal(tick*DD_INTERVAL, CLEAR_TREES_INTERVAL) < DD_INTERVAL) {
if (IsTerrainPathable(vec[0]+BOUNCE_DETECT_RANGE*dx, vec[1], PATHING_TYPE_WALKABILITY))
dx = -dx;
else if (IsTerrainPathable(vec[0], vec[1]+BOUNCE_DETECT_RANGE*dy, PATHING_TYPE_WALKABILITY))
dy = -dy;
}
// ----------------------------------------
// *** Check if there are any units to be splash bashed
static if (ENABLE_SPLASH_BASH)
if (speed > SPLASH_BASH_NEED_SPEED*DD_INTERVAL && ModuloReal(tick*DD_INTERVAL, SPLASH_BASH_INTERVAL) < DD_INTERVAL)
TryDoSplashBash();
// ----------------------------------
// *** Check to quit push
if (dist <= 0.) {
PauseUnit(b, false);
destroy();
DDQuitTim();
}
});
}
}
// *** Bash function that will be called from above and below
function BashExecute(integer p, unit basher, unit u, integer lvl, real dist, real radians, real dmg) {
// *** Now pause the victim ***
PauseUnit(u, true);
DestroyEffect(AddSpecialEffectTarget(BASH_HIT_EFFECT_FILE, u, BASH_HIT_EFFECT_FILE_ATT_POINT));
bash.create(p, basher, u, lvl, dist, radians, dmg).Launch(); /// *** Will be auto destroyed
}
// ==================================================================================
// *** Initialization ***
function onInit() {
trigger t = CreateTrigger();
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED);
DDTriggerRegisterAnyUnitDamaged(t);
TriggerAddCondition(t, function() -> boolean {
unit u;
unit v;
integer lvl;
real dmg = 0.;
bash b;
// *** Attac
if (GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED) {
u = GetAttacker();
v = GetTriggerUnit();
b = DDGet(v, UNIT_BASH_KEY);
if (b != p_null)
if (IsUnitType(u, UNIT_TYPE_MELEE_ATTACKER) && b.IsAirborn)
IssueImmediateOrder(u, "stop");
u = null;
v = null;
return false;
}
u = GetEventDamageSource(); // Damages source unit
v = GetTriggerUnit(); // Victim unit
lvl = GetUnitAbilityLevel(u, MAX_BASH_ID); // Spell level
// --------------------------------------
// *** Condition
if (GetUnitAbilityLevel(v, MAX_BASH_BUFF_ID) == 0 || DDGet(v, UNIT_BASH_KEY) != p_null) {
UnitRemoveAbility(v, MAX_BASH_BUFF_ID);
u = null;
v = null;
return false;
}
// *** No future exec, prevent exec this trigger when we call "UnitDamageTarget" below ***
DisableTrigger(GetTriggeringTrigger());
// *** Clear the buff ***
UnitRemoveAbility(v, MAX_BASH_BUFF_ID);
// *** Primary damage ***
static if (BASH_DAMAGE_AS_PERCENTAGE)
dmg = GetEventDamage()*BashDamage(lvl);
else
dmg = BashDamage(lvl);
BlzSetEventDamage(GetEventDamage() + dmg);
//UnitDamageTarget(u, v, dmg, true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
// *** Apply custom effect ***
DestroyEffect(AddSpecialEffectTarget(ON_PUSH_FILE, u, ATTACH_POINT));
// *** Floating text add? ***
static if (ALLOW_FLOATING_TEXT)
static if (USE_KO_TEXT)
if (IsUnitType(v, UNIT_TYPE_DEAD))
DDNewTextTagUnit(v, "|cffff0000KO!!!|r", FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(v, "+"+I2S(R2I(dmg)), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
else
DDNewTextTagUnit(v, "+"+I2S(R2I(dmg)), FLOATING_TEXT_DURATION, FLOATING_TEXT_RED, FLOATING_TEXT_GREEN, FLOATING_TEXT_BLUE, FLOATING_TEXT_TRANS);
// *** Load main bash struct ***
BashExecute(GetPlayerId(GetOwningPlayer(u)), u, v, lvl, BashPushDistance(lvl), Atan2(GetUnitY(v)-GetUnitY(u), GetUnitX(v)-GetUnitX(u)), dmg);
// *** Allow next exec ***
EnableTrigger(GetTriggeringTrigger());
// *** Null locals ***
u = null;
v = null;
return false;
});
}
}
//! endzinc
// ============================================================================================
// Change me from /* to // and then back to /* after saving and reopening the map
// |
// ˇ
/*
// Credits: PurgeandFire for lua tutorial
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i -- =================================================================
//! i MAX_BASH_ABIL_ID = "MBsh"
//! i MAX_BASH_BUFF_ID = "MBed"
//! i -- =================================================================
//! i setobjecttype("buffs")
//! i createobject("BSTN", MAX_BASH_BUFF_ID)
//! i makechange(current, "fart", "ReplaceableTextures\\CommandButtons\\PASBash.blp")
//! i makechange(current, "ftat", "")
//! i makechange(current, "fta0", "")
//! i makechange(current, "fnam", "Max Bash")
//! i makechange(current, "ftip", "Max Bash")
//! i setobjecttype("abilities")
//! i createobject("AHbh", MAX_BASH_ABIL_ID)
//! i makechange(current,"anam", "Max Bash")
//! i makechange(current,"aart", "ReplaceableTextures\\CommandButtons\\PASBash.blp")
//! i makechange(current,"arar", "ReplaceableTextures\\CommandButtons\\PASBash.blp")
//! i makechange(current,"abpx", "3")
//! i makechange(current,"arpx", "3")
//! i -- makechange(current,"alev", "3")
//! i -- makechange(current,"arlv", "1")
//! i -- makechange(current,"ahky", "H")
//! i makechange(current,"arhk", "X")
//! i makechange(current,"aret", "Learn Ma|cff109da9x|r Bash - [|cffffcc00Level ".. string.char(37) .."d|r]")
//! i makechange(current,"arut", "|cffc0c0c0Gives a percent chance to deal extra damage and push target. Sliding unit deals splash bash that slightly pushes units and deals 30% damage from original bash. |r|n|n|cffffcc00Level 1|r - 15% chance, 2.6x damage, 200 distance push. |n|cffffcc00Level 2|r - 17% chance, 3.4x damage, 230 distance push. |n|cffffcc00Level 3|r - 20% chance, 4.5x damage, 270 distance push.")
//! i makechange(current,"aub1","1","|cffc0c0c0Gives a 15% chance to deal extra 2.6x damage, push target 200 offset distance and deal 30% splash bash.|r")
//! i makechange(current,"aub1","2","|cffc0c0c0Gives a 17% chance to deal extra 3.4x damage, push target 230 offset distance and deal 30% splash bash.|r")
//! i makechange(current,"aub1","3","|cffc0c0c0Gives a 20% chance to deal extra 4.5x damage, push target 270 offset distance and deal 30% splash bash.|r")
//! i local i = 0
//! i for i=1, 3 do
//! i local si = tostring(i)
//! i makechange(current,"atar",si,"Enemy,Ground,Organic")
//! i -- makechange(current,"aran",si,"99999.")
//! i makechange(current,"Hbh1",si,tostring(13+(2*i)))
//! i makechange(current,"abuf",si,"MBed")
//! i makechange(current,"Hbh5",si,"1")
//! i makechange(current,"Hbh3",si,"0.")
//! i makechange(current,"atp1",si,"Max Bash - [|cffffcc00Level ".. si .."|r]")
//! i end
//! i makechange(current,"Hbh1","3","20.")
//! endexternalblock
*/
// ^
// |
// Change me from */ to // and then back to */ after saving and reopening the map
// ============================================================================================
JASS:
//==========================================================================
// Dark Dragon Library Code v1.3
//
// * Made on Warcraft III v1.30.4
//
// Installation:
//
// 1) Export instantdummy.mdx from this map and import it to your map, leave path at "war3mapImported/instantdummy.mdx"
// 2) Copy this trigger to your map, save your map and then change below line "// external ... " or copy "DD Dummy" and paste it in your map
// 3) Copy and paste "Unit Chill" ability from this map to your map
// 4) Match the rawcodes below to your map or use same ones as below
//
// Credits:
// ('Vexorian' - dummy.mdx)
//============================================================================
// *** Change "// external" to "//! external", save your map, close map, change back from "//!" to "//" and save map again.
// *** This will create dummy in your map
//
// ==================================
// external ObjectMerger w3u ushd dumy uabi "Aloc,Amrf" uble 0 ucbs 0 ucpt 0 umxp 0 umxr 0 umdl "war3mapImported\instantdummy.mdx" ushu "None" umvh 0 umvs 1 umas 1 umis 1 ucol 0 ufoo 0 uhom 1 umpi 10000 umpm 10000 usid 1 usin 1 unam "DD Dummy"
// ==================================
//! zinc
library DDLib requires optional TimerUtils, optional GroupUtils
{
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// *** Lib constants ***
public {
// ----------------------------------------------------------------------
// * Start modify/match rawcodes to your map
constant integer DD_DUMMYCODE = 'dumy';
constant integer DD_ABILITY_CROWN_FORM = 'Amrf';
constant integer DD_CHILL = 'Achl';
constant integer DD_CHILL_BUFF = 'Bfro';
// * End modify
// ----------------------------------------------------------------------
constant integer p_null = (0x0);
constant real DD_INTERVAL = .017;
// map min and max coords
real DDMinX = 0.;
real DDMinY = 0.;
real DDMaxX = 0.;
real DDMaxY = 0.;
}
private {
constant integer HARVEST_ID = 'Ahrl';
constant real TRIGGER_REFRESH_RATE = (60.)*3.; /// damage detection trigger
unit TreeChecker = null;
trigger TempTrig = null;
integer NTrig = 0;
trigger DmgTrig[];
p_real EnumVec = p_null;
boolexpr EnumFilter = null;
sound ErrorSound = null;
timer GameElapsedTimer = null;
constant integer RND_INT_MAX_ARRAY_N = 100;
integer RndInt[], RndIntWriteN = 00, RndIntReadN = 00;
trigger TrigMouseEvent = null;
force RndGenForce = null;
real RndElapsedTime = 0.;
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// * types
public {
// *** pointer to list of data ***
type p_integer extends integer[8];
type p_real extends real[8];
type p_unit extends unit[8];
function H2ID(handle h) -> integer {
return GetHandleId(h) - 0x100000;
}
function New_pInteger(integer i) -> p_integer
{ p_integer p = p_integer.create(); p[0] = i; return p; }
function New_pReal(real r) -> p_real
{ p_real p = p_real.create(); p[0] = r; return p; }
function New_pUnit(unit u) -> p_unit
{ p_unit p = p_unit.create(); p[0] = u; return p; }
function pVector(real x, real y, real z) -> p_real {
p_real v = p_real.create();
v[0] = x; v[1] = y; v[2] = z;
return v;
}
// --------------------------------------------------------------------------------------
function DDMsg(string str) {
DisplayTimedTextFromPlayer(GetLocalPlayer(), 0., 0., 30., str);
}
// --------------------------------------------------------------------------------------
function DisplayErrorMsgPlayer(player p, real dur, string msg) {
if (GetLocalPlayer() == p) {
StartSound(ErrorSound);
DisplayTimedTextFromPlayer(p, 0., 0., dur, "|cffffcc00"+ msg +"|r");
}
}
}
// -----------------------------------------------------------------------
// -> ***** private globals *****
// -----------------------------------------------------------------------
private {
location TempLoc = Location(0., 0.);
timer TimerStack[];
integer TimN = 0;
group GroupStack[];
integer GrpN = 0;
unit DummyStack[];
integer DumN = 0;
integer TimTicks[];
integer TimData[];
timer TimTim1[];
timer TimTim2[];
integer UnitStackData = 0;
unit UnitStack[];
integer US_N = 0;
public hashtable DDHT = InitHashtable();
}
// -----------------------------------------------------------------------
public {
// *** Global funcs
function Pw_2(real x) -> real {
return x*x;
}
function DDHypot(real x, real y) -> real {
return (x*x) + (y*y);
}
function DDTerrZ(real x, real y) -> real {
MoveLocation(TempLoc, x, y);
return GetLocationZ(TempLoc);
}
function DDWidgetTerrZ(widget w) -> real {
MoveLocation(TempLoc, GetWidgetX(w), GetWidgetY(w));
return GetLocationZ(TempLoc);
}
function DDEffectTerrZ(effect e) -> real {
MoveLocation(TempLoc, BlzGetLocalSpecialEffectX(e), BlzGetLocalSpecialEffectY(e));
return GetLocationZ(TempLoc);
}
function DDGetUnitZ(unit u) -> real {
return BlzGetUnitZ(u) + GetUnitFlyHeight(u);
}
// =================================================================
// *** Save Handle data ****
// =================================================================
function DDSet(handle h, integer id, integer val) {
SaveInteger(DDHT, id+1, GetHandleId(h), val);
}
function DDGet(handle h, integer id) -> integer {
return LoadInteger(DDHT, id+1, GetHandleId(h));
}
function DDHas(handle h, integer id) -> boolean {
return HaveSavedInteger(DDHT, id+1, GetHandleId(h));
}
function DDFlush(integer id) {
FlushChildHashtable(DDHT, id+1);
}
// =================================================================
// *** Timer Handling ****
// =================================================================
// -> check if timer is recycled
function DDIsTimRecycled(timer t) -> boolean {
integer i;
for(i=TimN-01; i >= 00; i-=01)
if (TimerStack[i] == t)
return true;
return false;
}
// -> Load timer for recycling
function DDLoadTim() -> timer {
static if (LIBRARY_TimerUtils) { return NewTimer(); }
else {
if (TimN > 0) {
TimN -= 1;
return TimerStack[TimN];
}
return CreateTimer();
}
}
// -> recycle loaded timer
function DDRecycleTim(timer t) {
static if (LIBRARY_TimerUtils) { ReleaseTimer(t); }
else {
static if (DEBUG_MODE)
if (DDIsTimRecycled(t)) {
DDMsg("Multiple recycle of timer!");
return;
}
TimerStack[TimN] = t;
TimN += 1;
}
}
// ** Get data stored on expired timer
function DDTimData() -> integer {
return TimData[H2ID(GetExpiredTimer())];
}
// *** Custom timer tick
function DDCTimTick(timer t) -> integer {
return TimTicks[H2ID(t)];
}
// *** Gets current tick and adds next one ***
function DDTimTick() -> integer {
integer id = H2ID(GetExpiredTimer());
TimTicks[id] += 01;
return TimTicks[id];
}
// ** start timer with data storage
function DDStartTim(real secs, boolean looping, integer pdata, code func) -> timer {
timer t = DDLoadTim();
TimData[H2ID(t)] = pdata;
TimerStart(t, secs, looping, func);
return t;
}
// ** start timer with data storage, and launches it instantly
function DDStartTimInst(real secs, boolean looping, integer pdata, code func) -> timer {
timer t1 = DDLoadTim(), t2 = DDLoadTim(), t3 = DDLoadTim();
TimData[H2ID(t2)] = pdata;
TimerStart(t2, 0., false, func);
TimTim1[H2ID(t3)] = t1;
TimTim2[H2ID(t3)] = t2;
TimerStart(t3, .005, false, function() {
timer t = GetExpiredTimer();
integer id = H2ID(t);
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
t = TimTim2[id];
if (DDIsTimRecycled(t))
t = TimTim1[id];
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
});
TimData[H2ID(t1)] = pdata;
TimerStart(t1, secs, looping, func);
return t1;
}
// *** Quit expired timer ***
function DDQuitTim() {
timer t = GetExpiredTimer();
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
}
function DDQuitTimEx(timer t) {
TimTicks[H2ID(t)] = 00;
PauseTimer(t);
static if (LIBRARY_TimerUtils)
ReleaseTimer(t);
else {
TimerStack[TimN] = t;
TimN += 1;
}
}
// =================================================================
// *** Group Handling ****
// =================================================================
// -> Load timer for recycling
function DDLoadGroup() -> group {
static if (LIBRARY_GroupUtils) { return NewGroup(); }
else {
if (GrpN > 0) {
GrpN -= 1;
return GroupStack[GrpN];
}
return CreateGroup();
}
}
// -> Recycle group
function DDRecycleGroup(group g) {
static if (LIBRARY_GroupUtils) { ReleaseGroup(g); }
else {
GroupClear(g);
GroupStack[GrpN] = g;
GrpN += 1;
}
}
// --------------------------------------------------------
// -- Quick filter area
private integer GroupFilterData = 00;
function DDGroupFilterArea(real x, real y, real radius, integer data, code func) {
group g = DDLoadGroup();
GroupFilterData = data;
GroupEnumUnitsInRange(g, x, y, radius, Filter(func));
DDRecycleGroup(g);
}
// --------------------------------------------------------
// -- Quick filter rect
function DDGroupFilterRect(rect r, integer data, code func) {
group g = DDLoadGroup();
GroupFilterData = data;
GroupEnumUnitsInRect(g, r, Filter(func));
DDRecycleGroup(g);
}
function DDGFilterData() -> integer {
return GroupFilterData;
}
function DDGFilterDataSet(integer data) {
GroupFilterData = data;
}
// --------------------------------------------------------
// *** Filtrates and fills units in to memory
function DDGroupFillMemArea(real x, real y, real radius, integer data, code filter) {
group g = DDLoadGroup();
boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
UnitStack[US_N] = GetFilterUnit();
US_N += 1;
return false;
}));
US_N = 0;
UnitStack[0] = null;
UnitStackData = data;
GroupEnumUnitsInRange(g, x, y, radius, exp);
DDRecycleGroup(g);
DestroyBoolExpr(exp);
exp = null;
}
function DDGroupFillMemRect(rect r, integer data, code filter) {
group g = DDLoadGroup();
boolexpr exp = And(Filter(filter), Filter(function() -> boolean {
UnitStack[US_N] = GetFilterUnit();
US_N += 1;
return false;
}));
US_N = 0;
UnitStack[0] = null;
UnitStackData = data;
GroupEnumUnitsInRect(g, r, exp);
DDRecycleGroup(g);
DestroyBoolExpr(exp);
exp = null;
}
function DDMemUnitN() -> integer { return US_N; }
function DDMemUnitData() -> integer { return UnitStackData; }
function DDMemUnit(integer index) -> unit {
if (US_N == 0) return null;
debug {
if (index < 0) {
BJDebugMsg("DDMemUnit: index less than 0");
index = 0;
} else if (index >= US_N) {
BJDebugMsg("DDMemUnit: index greater than units alloc size");
index = 0;
}
}
return UnitStack[index];
}
// --------------------------------------------------------
// --------------------------------------------------------
// ***
// =================================================================
// *** Dummy Handling ****
// =================================================================
// -> Load dummy for recycling
function DDLoadDummy() -> unit {
if (DumN > 0) {
DumN -= 1;
PauseUnit(DummyStack[DumN], false);
return DummyStack[DumN];
}
return CreateUnit(Player(0xF), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
}
// *** prepares/setups dummy for spell casting
function DDLoadSpellDummy(player owner, real x, real y, integer abil, integer abilLevel) -> unit {
unit dummy = DDLoadDummy();
SetUnitOwner(dummy, owner, false);
SetUnitX(dummy, x);
SetUnitY(dummy, y);
if (abil != p_null) {
UnitAddAbility(dummy, abil);
SetUnitAbilityLevel(dummy, abil, abilLevel);
}
return dummy;
}
// -> Recycle dummy
function DDRecycleDummy(unit u) {
PauseUnit(u, true);
DummyStack[DumN] = u;
DumN += 1;
}
// -> Recycle dummy timed
function DDRecycleDummyTimed(unit u, real secs) {
DDStartTim(secs, false, New_pUnit(u), function() {
DDRecycleDummy(p_unit(DDTimData())[0]);
p_unit(DDTimData()).destroy();
DDQuitTim();
});
}
// *** shares vision for timed amount, usually for dummy casting
function DDUnitShareVisionTimed(unit u, player toP, real secs) {
p_integer pi = p_integer.create();
pi[0] = New_pUnit(u);
pi[1] = GetPlayerId(toP);
UnitShareVision(u, toP, true);
DDStartTim(secs, false, pi, function() {
p_integer pi = DDTimData();
UnitShareVision(p_unit(pi[0])[0], Player(pi[1]), false);
p_unit(pi[0])[0] = null;
p_unit(pi[0]).destroy();
pi.destroy();
DDQuitTim();
});
}
// *** Remove ability timed ***
private struct uratimed {
private {
unit u;
integer abil;
}
static method create(unit whichUnit, integer id, real time) -> uratimed {
thistype this = allocate();
u = whichUnit;
abil = id;
DDStartTim(time, false, this, function() {
thistype this = DDTimData();
UnitRemoveAbility(u, abil);
DDQuitTim();
deallocate();
});
return 0;
}
}
function DDRemoveAbilityTimed(unit u, integer abil, real secs) { uratimed.create(u, abil, secs); }
function DDSpellDamage(unit u, unit v, real dmg) {
real life = GetWidgetLife(v);
real dmgfactor = 1.;
if (IsUnitType(v, UNIT_TYPE_HERO)) {
if (UnitHasItemOfTypeBJ(v, 'brac'))
dmgfactor = .5;
else
dmgfactor = .75;
}
if (life > dmg*dmgfactor) {
SetWidgetLife(v, life-(dmg*dmgfactor));
} else
UnitDamageTarget(u, v, 99999., false, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
}
// -------------------------------------------------------------------------------------
// *** Chills target unit
private struct chill {
unit u, dmy;
real dur;
static chill Data[];
//static key CHILL_KEY;
}
function DDUnitChill(player p, unit u, real dur) -> boolean {
//chill c = DDGet(u, chill.CHILL_KEY);
chill c = chill.Data[H2ID(u)];
unit d;
real rad;
if (c == p_null) {
c = chill.create();
c.u = u; c.dur = dur;
chill.Data[H2ID(u)] = c;
//DDSet(u, chill.CHILL_KEY, c);
d = DDLoadDummy();
c.dmy = d;
rad = GetUnitFacing(d) * bj_DEGTORAD;
SetUnitOwner(d, p, false);
UnitAddAbility(d, DD_CHILL);
SetUnitX(d, GetUnitX(u) - 20.*Cos(rad));
SetUnitY(d, GetUnitY(u) - 20.*Sin(rad));
if (IssueTargetOrder(d, "frostnova", u)) {
DDStartTim(.1, true, c, function() {
chill c = DDTimData();
c.dur -= .1;
if (c.dur <= 0. || GetUnitAbilityLevel(c.u, DD_CHILL_BUFF) == 00) {
UnitRemoveAbility(c.u, DD_CHILL_BUFF);
UnitRemoveAbility(c.dmy, DD_CHILL);
DDRecycleDummy(c.dmy);
chill.Data[H2ID(c.u)] = p_null;
//DDSet(c.u, chill.CHILL_KEY, p_null);
c.u = null;
c.destroy();
DDQuitTim();
}
});
return true;
}
return false;
}
c.dur = dur;
return true;
}
// ------------------------------------------------------------------------------------------------
struct fade {
unit u;
real trans;
real rate, e_trans, dur;
static constant real INTERVAL = .1;
static method create(unit u, real dur, real s_trans, real e_trans) -> fade {
fade this = allocate();
this.u = u;
this.trans = s_trans;
this.rate = ((e_trans-s_trans)/dur)*fade.INTERVAL;
this.e_trans = e_trans;
this.dur = dur;
return this;
}
}
// *** Fades unit over time ***
public function DDFadeUnit(unit u, integer from_alpha, integer to_alpha, real duration) {
fade f = fade.create(u,
duration,
from_alpha/2.55,
to_alpha/2.55);
SetUnitVertexColor(u, 255, 255, 255, from_alpha);
// --- Start thread ---
DDStartTim(fade.INTERVAL, true, f, function() {
fade f = DDTimData();
f.trans += f.rate;
f.dur -= fade.INTERVAL;
SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.trans*2.55));
if (f.dur < 0.) {
SetUnitVertexColor(f.u, 255, 255, 255, R2I(f.e_trans*2.55));
f.u = null;
f.destroy();
DDQuitTim();
}
});
}
// ------------------------------------------------------------------------------------------------
// Check if unit is invulnerable
function DDIsUnitInvulnerable(unit u) -> boolean {
unit d = DDLoadDummy();
real hp = GetWidgetLife(u);
boolean flag;
UnitDamageTarget(d, u, 1., true, false, null, null, null);
flag = GetWidgetLife(u) == hp;
SetWidgetLife(u, hp);
DDRecycleDummy(d);
return flag;
}
// *** check if unit is ward
function DDIsUnitWard(unit whichUnit) -> boolean {
return GetUnitDefaultMoveSpeed(whichUnit) == 0.;
}
// =================================================================
// *** Effect Handling ****
// =================================================================
// -----------------------------------------------
// *** Define movable effect
struct ddeffect {
private {
effect e;
real fac; // facing angle in radians
real effZ; // pitch in radians
real decay;
real stepTrans, cTrans, eTrans;
static constant real EFFECT_DECAY = 5.;
}
// =========================================================================================
// =========================================================================================
static method create(string mdl, real x, real y, real facRad, real size) -> ddeffect {
ddeffect this = allocate();
this.e = AddSpecialEffect(mdl, x, y);
this.fac = facRad;
this.effZ = 0.;
BlzSetSpecialEffectRoll(this.e, facRad);
BlzSetSpecialEffectScale(this.e, size);
return this;
}
static method createZ(string mdl, real x, real y, real z, real facRad, real size) -> ddeffect {
ddeffect this = allocate();
this.e = AddSpecialEffect(mdl, x, y);
this.fac = facRad;
this.effZ = z-DDTerrZ(x, y);
BlzSetSpecialEffectRoll(this.e, facRad);
BlzSetSpecialEffectScale(this.e, size);
BlzSetSpecialEffectZ(this.e, z);
return this;
}
// -----------------
method destroy() {
DestroyEffect(this.e);
this.e = null;
deallocate();
}
// *** destroys effect timed
method destroyx(real decayTime) {
DDStartTim(decayTime, false, this, function() {
ddeffect se = DDTimData();
BlzSetSpecialEffectPosition(se.e, DDMaxX, DDMaxY, 0.);
DestroyEffect(se.e);
se.e = null;
se.deallocate();
DDQuitTim();
});
}
// =========================================================================================
// =========================================================================================
method operator Z=(real z) { BlzSetSpecialEffectZ(this.e, z); }
method operator X() -> real { return BlzGetLocalSpecialEffectX(this.e); }
method operator Y() -> real { return BlzGetLocalSpecialEffectY(this.e); }
method operator Z() -> real { return BlzGetLocalSpecialEffectZ(this.e); }
method operator WZ() -> real { return DDEffectTerrZ(this.e); }
method operator Height() -> real { return this.Z-this.WZ; }
method operator Facing=(real facRad) { BlzSetSpecialEffectRoll(this.e, facRad); this.fac = facRad; }
method operator Facing() -> real { return this.fac; }
method Position(real x, real y) { BlzSetSpecialEffectPosition(this.e, x, y, this.effZ+this.WZ); }
method PositionZ(real x, real y, real z) { BlzSetSpecialEffectPosition(this.e, x, y, z); }
method Animation(animtype at) { BlzPlaySpecialEffect(this.e, at); }
method AnimationSpeed(real animSpeed) { BlzSetSpecialEffectTimeScale(this.e, animSpeed/100.); }
//method operator Pitch=(integer pitch) { SetUnitAnimationByIndex(u, pitch); }
//method Face(widget w) { Facing = Atan2(GetWidgetY(w)-Y, GetWidgetX(w)-X)*bj_RADTODEG; }
method Fade(real startTransparency, real endTransparency, real duration) {
this.cTrans = startTransparency;
this.eTrans = endTransparency;
this.stepTrans = .1*(endTransparency-startTransparency) / duration;
BlzSetSpecialEffectAlpha(this.e, R2I(startTransparency*2.55));
DDStartTim(.1, true, this, function() {
ddeffect dde = DDTimData();
dde.cTrans += dde.stepTrans;
if (dde.stepTrans > 0.)
if (dde.cTrans >= dde.eTrans) {
BlzSetSpecialEffectAlpha(dde.e, R2I(dde.eTrans*2.55));
DDQuitTim();
return;
}
else
if (dde.cTrans <= dde.eTrans) {
BlzSetSpecialEffectAlpha(dde.e, R2I(dde.eTrans*2.55));
DDQuitTim();
return;
}
BlzSetSpecialEffectAlpha(dde.e, R2I(dde.cTrans*2.55));
});
}
}
private type timedeffect extends effect[01];
function DDDestroyEffectTimed(effect e, real secs) {
timedeffect te = timedeffect.create();
te[00] = e;
DDStartTim(secs, true, te, function() {
timedeffect te = DDTimData();
DestroyEffect(te[00]);
te.destroy();
DDQuitTim();
});
}
}
// ----------------------------------------------------------------------------
// *** Main damage detection function, registers any damage dealt to units ***
public function DDTriggerRegisterAnyUnitDamaged(trigger t) {
DmgTrig[NTrig] = t;
NTrig += 1;
}
function InitDamageDetection() {
code c = function() {
if (TempTrig != null)
DestroyTrigger(TempTrig);
TempTrig = CreateTrigger();
TriggerRegisterEnterRectSimple(TempTrig, bj_mapInitialPlayableArea);
TriggerAddCondition(TempTrig, function() -> boolean {
integer i;
// *** Check if we need to exec triggers or register an unit ***
if (GetTriggerEventId() == EVENT_UNIT_DAMAGED) {
for(i=0; i < NTrig; i+=1)
if (IsTriggerEnabled(DmgTrig[i]))
if (TriggerEvaluate(DmgTrig[i]))
TriggerExecute(DmgTrig[i]);
}
else
// *** Register new unit ***
TriggerRegisterUnitEvent(GetTriggeringTrigger(),
GetTriggerUnit(),
EVENT_UNIT_DAMAGED);
return false;
});
DDGroupFilterRect(bj_mapInitialPlayableArea, 00, function() -> boolean {
TriggerRegisterUnitEvent(TempTrig, GetFilterUnit(), EVENT_UNIT_DAMAGED);
return false;
});
};
trigger t = CreateTrigger();
TriggerAddAction(t, c);
TriggerExecute(t);
DestroyTrigger(t);
TimerStart(CreateTimer(), TRIGGER_REFRESH_RATE, true, c);
t = null;
}
// ---------------------------------------------------------------------------------
// *** Main enum dests in range function ***
public function DDEnumDestsInRange(p_real vec, real radius, boolexpr filter, code pfunc) {
rect r = Rect(vec[0]-radius, vec[1]-radius, vec[0]+radius, vec[1]+radius);
EnumVec[0] = vec[0];
EnumVec[1] = vec[1];
EnumVec[2] = radius;
if (filter != null) filter = And(EnumFilter, filter);
else filter = EnumFilter;
EnumDestructablesInRect(r, filter, pfunc);
if (filter != EnumFilter) { DestroyBoolExpr(filter); filter = null; }
RemoveRect(r);
r = null;
}
function InitEnumDests() {
EnumVec = p_real.create();
EnumFilter = Filter(function() -> boolean {
return Pw_2(EnumVec[0]-GetDestructableX(GetFilterDestructable())) + Pw_2(EnumVec[1]-GetDestructableY(GetFilterDestructable())) < Pw_2(EnumVec[2]);
});
}
// --------------------------------------------------------------------------------------
// *** checks is destruct tree ***
public function DDIsDestructableTree(destructable d) -> boolean {
if (d != null) {
PauseUnit(TreeChecker, false);
if (IssueTargetOrder(TreeChecker, "harvest", d)) {
PauseUnit(TreeChecker, true);
return true;
}
PauseUnit(TreeChecker, true);
}
return false;
}
function InitDestTreeCheck() {
TreeChecker = CreateUnit(Player(bj_PLAYER_NEUTRAL_EXTRA), DD_DUMMYCODE, DDMaxX, DDMaxY, 0.);
UnitAddAbility(TreeChecker, HARVEST_ID);
PauseUnit(TreeChecker, true);
}
// --------------------------------------------------------------------------------------
public function DDNewTextTagUnit(unit whichUnit, string text, real dur, real red, real green, real blue, real transparency) {
CreateTextTagUnitBJ( text, whichUnit, 0., 11.00, red, green, blue, transparency );
SetTextTagPermanentBJ( bj_lastCreatedTextTag, false );
SetTextTagVelocityBJ( bj_lastCreatedTextTag, 48.00, 90 );
SetTextTagFadepointBJ( bj_lastCreatedTextTag, dur-1.25 );
SetTextTagLifespanBJ( bj_lastCreatedTextTag, dur );
}
// --------------------------------------------------------------------------------------
struct cameranoisedata {
player p[12];
integer n=00;
}
public function DDCameraSetSourceNoiseForPlayers(real x, real y, real mag, real vel, real maxDist, real duration) {
integer i;
real d;
cameranoisedata cnd = cameranoisedata.create();
for (i=00; i < bj_MAX_PLAYERS; i+=01) {
if (GetLocalPlayer() == Player(i)) {
d = SquareRoot( Pw_2(GetCameraTargetPositionX()-x) + Pw_2(GetCameraTargetPositionY()-y) );
if (d < maxDist) {
cnd.p[cnd.n] = Player(i);
CameraSetSourceNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
CameraSetTargetNoise(mag-(d*(mag/maxDist)), vel-(d*(vel/maxDist)));
cnd.n += 01;
}
}
}
DDStartTim(duration, false, cnd, function() {
cameranoisedata cnd = DDTimData();
while(cnd.n != 00) {
cnd.n -= 01;
if (GetLocalPlayer() == cnd.p[cnd.n])
CameraSetSourceNoise(0., 0.);
CameraSetTargetNoise(0., 0.);
}
cnd.destroy();
DDQuitTim();
});
}
// --------------------------------------------------------------------------------------
hashtable GenSndTable = null;
public function DDGenericSound(string file, real vol, real x, real y, real mxDist, real pitch) {
sound s;
real d;
integer i;
integer snd_n, sh;
// Play sound and shake camera for players within spell cast range
for (i=00; i < bj_MAX_PLAYERS; i+=01) {
if (GetLocalPlayer() == Player(i)) {
d = SquareRoot( Pw_2(GetCameraTargetPositionX()-x) + Pw_2(GetCameraTargetPositionY()-y) );
if (d < mxDist) {
sh = StringHash(file);
snd_n = LoadInteger(GenSndTable, sh, 04);
s = LoadSoundHandle(GenSndTable, sh, snd_n);
if (s == null) {
s = CreateSound(file, false, false, false, 10, 10, "");
SaveSoundHandle(GenSndTable, sh, snd_n, s);
} else if (GetSoundIsPlaying(s)) {
StopSound(s, false, false);
}
SetSoundPitch(s, pitch);
SetSoundVolume(s, R2I((vol-d*(vol/mxDist))*1.27));
StartSound(s);
snd_n += 01;
if (snd_n == 04)
snd_n = 00;
SaveInteger(GenSndTable, sh, 04, snd_n);
}
}
}
}
public function DDGetGameElapsedTime() -> real {
return TimerGetElapsed(GameElapsedTimer);
}
public function DDGetRndReal(real min, real max) -> real {
real rnd = ((max-min)/1000000.)*I2R(RndInt[RndIntReadN]);
debug if (max > 1000000.)
DDMsg("ERROR: \"DDGetRndNumber\" - 'max' variable is greater than 1000000!");
RndIntReadN += 01; if (RndIntReadN == RND_INT_MAX_ARRAY_N) RndIntReadN = 00;
return min + rnd;
}
public function DDGetRndInt(integer min, integer max) -> integer {
return R2I( DDGetRndReal(I2R(min), I2R(max)) );
}
// ====================================================================
function onInit() {
InitDamageDetection();
InitDestTreeCheck();
InitEnumDests();
DDMinX = GetRectMinX(bj_mapInitialPlayableArea);
DDMinY = GetRectMinY(bj_mapInitialPlayableArea);
DDMaxX = GetRectMaxX(bj_mapInitialPlayableArea);
DDMaxY = GetRectMaxY(bj_mapInitialPlayableArea);
GenSndTable = InitHashtable();
ErrorSound = CreateSound( "Sound\\Interface\\Error.wav", false, false, false, 10, 10, "" );
SetSoundParamsFromLabel( ErrorSound, "InterfaceError" );
SetSoundDuration( ErrorSound, 614 );
SetSoundVolume(ErrorSound, 127);
GameElapsedTimer = CreateTimer();
TimerStart(GameElapsedTimer, 10800., false, null);
for(RndIntWriteN=00; RndIntWriteN < RND_INT_MAX_ARRAY_N; RndIntWriteN+=01)
RndInt[RndIntWriteN] = GetRandomInt(00, 1000000);
RndIntWriteN = 00;
RndGenForce = CreateForce();
TrigMouseEvent = CreateTrigger();
ForForce(bj_FORCE_ALL_PLAYERS, function() {
if (GetPlayerController(GetEnumPlayer()) == MAP_CONTROL_USER)
TriggerRegisterPlayerEvent(TrigMouseEvent, GetEnumPlayer(), EVENT_PLAYER_MOUSE_MOVE);
});
TriggerAddCondition(TrigMouseEvent, Condition(function() -> boolean {
real mouseN;
boolean xFirst = GetRandomInt(00, 01) == 01;
if (!IsPlayerInForce(GetTriggerPlayer(), RndGenForce)) {
// example: input x = 578.4571496
// output rnd n = 4571498
if (xFirst)
mouseN = RAbsBJ(BlzGetTriggerPlayerMouseX()) * 100.;
else
mouseN = RAbsBJ(BlzGetTriggerPlayerMouseY()) * 100.;
if (mouseN == 0.)
return false;
//mouseN *= 100.;
RndInt[RndIntWriteN] = R2I((mouseN - I2R(R2I(mouseN))) * 1000.);
//DDMsg(I2S(RndInt[RndIntWriteN]));
//RndIntWriteN += 01; if (RndIntWriteN == RND_INT_MAX_ARRAY_N) RndIntWriteN = 00;
if (xFirst)
mouseN = RAbsBJ(BlzGetTriggerPlayerMouseY()) * 100.;
else
mouseN = RAbsBJ(BlzGetTriggerPlayerMouseX()) * 100.;
RndInt[RndIntWriteN] += R2I((mouseN - I2R(R2I(mouseN))) * 1000.)*1000;
//DDMsg(I2S(RndInt[RndIntWriteN]));
RndIntWriteN += 01; if (RndIntWriteN == RND_INT_MAX_ARRAY_N) RndIntWriteN = 00;
ForceAddPlayer(RndGenForce, GetTriggerPlayer());
}
if (DDGetGameElapsedTime()-RndElapsedTime > .125) {
ForceClear(RndGenForce);
RndElapsedTime = DDGetGameElapsedTime();
}
return false;
}));
}
}
//! endzinc
Last edited: