//TESH.scrollpos=0
//TESH.alwaysfold=0
function CodeGen_Init takes nothing returns nothing
local integer i = 1
local integer b = udg_SaveLoad_Base
local integer m = udg_SaveLoad_MaxValue
loop
exitwhen i >= udg_SaveLoad_MaxValue
set udg_SaveLoad_Char[i] = SubString(udg_SaveLoad_Alphabet, i, i+1)
set i = i + 1
endloop
set udg_SaveLoad_Alphabet = SubString(udg_SaveLoad_Alphabet, 0, 1) + SubString(udg_SaveLoad_Alphabet, m + 1, b)
set udg_SaveLoad_Base = b - m
endfunction
function CodeGen_ConvertItem takes integer id returns integer
local integer i = 1
loop
exitwhen i > udg_SaveLoad_ItemCount
if (id == udg_SaveLoad_Item[i]) then
return i
endif
set i = i + 1
endloop
return 0
endfunction
function CodeGen_ConvertUnit takes integer id returns integer
local integer i = 1
loop
exitwhen i > udg_SaveLoad_HeroCount
if (id == udg_SaveLoad_Hero[i]) then
return i
endif
set i = i + 1
endloop
return 0
endfunction
function CodeGen_Encode takes integer i returns string
local integer b
local string s = ""
if i <= udg_SaveLoad_Base then
return SubString(udg_SaveLoad_Alphabet, i, i + 1)
endif
loop
exitwhen i <= 0
set b = i - (i / udg_SaveLoad_Base) * udg_SaveLoad_Base
set s = SubString(udg_SaveLoad_Alphabet, b, b + 1) + s
set i = i / udg_SaveLoad_Base
endloop
return s
endfunction
function CodeGen_StrPos takes string s returns integer
local integer i = 0
loop
exitwhen i > udg_SaveLoad_Base
if s == SubString(udg_SaveLoad_Alphabet, i, i + 1) then
return i
endif
set i = i + 1
endloop
return -1
endfunction
function CodeGen_Decode takes string s returns integer
local integer a = 0
loop
exitwhen StringLength(s) == 1
set a = a * udg_SaveLoad_Base + udg_SaveLoad_Base * CodeGen_StrPos(SubString(s, 0, 1))
set s = SubString(s, 1, 99)
endloop
return a+CodeGen_StrPos(s)
endfunction
function CodeGen_StringChecksum takes string in returns integer
local integer i = 0
local integer l = StringLength(in)
local integer t = 0
local integer o = 0
loop
exitwhen i >= l
set t = CodeGen_Decode(SubString(in, i, i + 1))
set o = o + t
set i = i + 1
endloop
return o
endfunction
function CodeGen_Color takes string char returns string
local integer i = 0
local integer l = StringLength(udg_SaveLoad_Full)
local string x = ""
loop
exitwhen i > l
set x = SubString(udg_SaveLoad_Full, i, i + 1)
if char == x then
if (x=="0" or S2I(x) > 0) then
return udg_SaveLoad_Number + char + "|r"
elseif StringCase(x, false) == x then
return udg_SaveLoad_Lower + char + "|r"
elseif StringCase(x, true) == x then
return udg_SaveLoad_Upper + char + "|r"
endif
endif
set i = i + 1
endloop
return char
endfunction
function CodeGen_Format takes string s returns string
local integer i = 0
local integer x = StringLength(s)
local integer j = 1
local string s2 = ""
loop
exitwhen i >= x
set s2 = s2 + CodeGen_Color(SubString(s, i, i + 1))
if (j >= udg_SaveLoad_HyphenSpace and i != (x-1)) then
set j = 0
set s2 = s2 + udg_SaveLoad_SeperationChar
endif
set j = j + 1
set i = i + 1
endloop
return s2
endfunction
function CodeGen_Strip takes string s returns string
local integer i = 0
local integer x = StringLength(s)
local string out = ""
local string a = ""
loop
exitwhen i > x
set a = SubString(s, i, i + 1)
if (a != udg_SaveLoad_SeperationChar) then
set out = out + a
endif
set i = i + 1
endloop
return out
endfunction
// yeeahh descriptive variables
function CodeGen_Load takes string s returns nothing
local string str = CodeGen_Strip(s)
local string tmp = ""
local string c = ""
local integer x = 0
local integer i = 1
local integer l = 0
local integer j = 1
local integer f = 0
local boolean b = true
set udg_SaveLoad_Valid = false
if (udg_SaveLoad_Security) then
loop
exitwhen i > 3
if (CodeGen_Decode(SubString(str, 0, i)) == CodeGen_StringChecksum(SubString(str, i, 999))) then
set udg_SaveLoad_Valid = true
set str = SubString(str, i, 999)
set i = 4
endif
set i = i + 1
endloop
endif
if (not udg_SaveLoad_Valid) then
set udg_SaveLoad_Error = "Ivalid code"
return
endif
set i = 0
set l = StringLength(str)
if (udg_SaveLoad_CheckName) then
set c = CodeGen_Encode(CodeGen_StringChecksum(GetPlayerName(GetTriggerPlayer())))
set i = StringLength(c)
if (c != SubString(str, l - i, i)) then
set udg_SaveLoad_Valid = false
set udg_SaveLoad_Error = "Wrong username"
return
endif
set l = l - i
endif
set i = 0
loop
exitwhen i >= l
set tmp = SubString(str, i, i + 1)
set b = true
set f = 0
set j = 1
loop
exitwhen f >= (udg_SaveLoad_MaxValue)
if (tmp == udg_SaveLoad_Char[f]) then
set j = f + 2
set udg_Load[x] = CodeGen_Decode(SubString(str, i + 1, i + (j)))
set b = false
set f = udg_SaveLoad_MaxValue
endif
set f = f + 1
endloop
if (b) then
set udg_Load[x] = CodeGen_Decode(tmp)
endif
set i = i + j
set x = x + 1
endloop
set udg_SaveLoad_Valid = true
endfunction
function CodeGen_Compile takes nothing returns string
local integer i = 0
local integer j = 0
local string out = ""
local string ln = ""
local string x = ""
loop
exitwhen i > udg_SaveCount
set x = CodeGen_Encode(udg_Save[i])
set j = StringLength(x)
if (j > 1) then
set out = out + udg_SaveLoad_Char[j-1]
endif
set out = out + x
set i = i + 1
endloop
if (udg_SaveLoad_CheckName) then
set out = out + CodeGen_Encode(CodeGen_StringChecksum(GetPlayerName(GetTriggerPlayer())))
endif
if (udg_SaveLoad_Security) then
set out = CodeGen_Encode(CodeGen_StringChecksum(out)) + out
endif
return CodeGen_Format(out)
endfunction
Name | Type | is_array | initial_value |
a | real | No | |
actionne | boolean | Yes | |
AleoIndi | integer | No | |
Alive | boolean | Yes | |
Alpha | force | No | |
ammo | boolean | No | |
Armement1 | boolean | Yes | |
Armement10 | boolean | Yes | |
Armement2 | boolean | Yes | |
Armement3 | boolean | Yes | |
Armement4 | boolean | Yes | |
Armement5 | boolean | Yes | |
Armement6 | boolean | Yes | |
Armement7 | boolean | Yes | |
Armement8 | boolean | Yes | |
Armement9 | boolean | Yes | |
AutoPickupCount | integer | No | |
AutoPickupInteger | integervar | Yes | |
AutoPickupItemType | itemcode | Yes | |
AutoPickupRange | rect | No | |
AutoPickupTempLoc | location | No | |
Bonus | boolean | No | |
bonus | integer | No | |
boss | unit | No | |
bouh | integer | No | |
bouton1 | button | No | |
bouton2 | button | No | |
bouton3 | button | No | |
bouton4 | button | No | |
bouton5 | button | No | |
bouton6 | button | No | |
Bravo | force | No | |
casque_red | effect | Yes | |
casque_red_Copier | effect | Yes | |
choix_m | boolean | Yes | |
choix_t | boolean | Yes | |
Code | StringExt | No | |
Computer | force | No | |
cout | rect | No | |
Deaths | integer | Yes | |
Drapeau | location | Yes | |
Drapeau_Base | integer | Yes | |
Drapeauter | unit | Yes | |
DS_BallCreationInterval | integer | Yes | |
DS_BallDamages | real | Yes | |
DS_BallDamagesAoe | real | Yes | |
DS_BallDamagesType | attacktype | No | |
DS_BallDamagesTypes2 | damagetype | No | |
DS_BallDirectionAndSpeed | real | Yes | |
DS_BallHeightIncrease | real | Yes | |
DS_BallLifeSteal | real | Yes | |
DS_BallLiveTime | real | Yes | |
DS_BallLocation | location | No | |
DS_BallLocationNew | location | No | |
DS_BallsGroup | group | No | |
DS_CasterLocation | location | No | |
DS_CastersGroup | group | No | |
DS_CircleAoe | real | Yes | |
DS_CircleDirectionAndSpeed | real | Yes | |
DS_CircleStartAngle | real | Yes | |
DS_Duration | real | Yes | |
DS_Effect | string | No | |
DS_Hashtable | hashtable | No | |
DS_NumberOfCircle | integer | Yes | |
DS_TempInteger | integer | No | |
DS_TempInteger2 | integer | No | |
DS_TempReal | real | No | |
DS_TempUnit | unit | No | |
DS_TempUnit2 | unit | No | |
DUMMY | unitcode | No | |
equip | boolean | No | |
F_Integers | integer | Yes | |
F_ReachedFading | real | Yes | |
F_Time | real | Yes | |
F_Unit | unit | Yes | |
FA_Time | real | No | |
FA_Unit | unit | No | |
Fin | force | No | |
flare | unit | Yes | |
fleche | unit | Yes | |
GhostAppear | unit | Yes | |
h_Bolean | boolean | No | |
h_Bolean2 | boolean | No | |
h_Caster | unit | No | |
h_hook | unit | Yes | |
h_Number | integer | No | |
hardcore | boolean | No | |
HARVESTER | unit | No | |
Hauteur | real | Yes | |
heoesalife | integer | No | |
Hero | unit | No | |
i | integervar | No | |
ID | integer | No | |
ID2 | integer | No | |
Immu | force | No | |
IndiOk | boolean | Yes | |
integer | integer | No | |
intro | dialog | No | |
intro1 | dialog | No | |
intro2 | dialog | No | |
intro3 | dialog | No | |
isgoingforward | boolean | Yes | |
ismovingbackwards | boolean | Yes | |
isturningleft | boolean | Yes | |
isturningright | boolean | Yes | |
Item | item | No | |
joueur | player | No | |
Joueur | force | No | |
joueur_Copier | player | No | |
Jump_AOE | real | Yes | |
JUMP_AOE | real | No | |
JUMP_ATTACHMENT | string | No | |
Jump_AX | real | Yes | |
Jump_AY | real | Yes | |
Jump_BX | real | Yes | |
Jump_BY | real | Yes | |
Jump_COLLISION | boolean | Yes | |
JUMP_COLLISION | boolean | No | |
Jump_COUNT | integer | Yes | |
Jump_D | real | Yes | |
Jump_DEFAULTHEIGHT | real | Yes | |
JUMP_GROUP | group | No | |
JUMP_HEIGHT | real | No | |
Jump_HEIGHT | real | Yes | |
JUMP_LOOP | real | No | |
JUMP_POINTA | location | No | |
JUMP_POINTB | location | No | |
Jump_SFXATTACHMENT | effect | Yes | |
JUMP_SFXATTACHMENT | string | No | |
JUMP_SFXPM | string | No | |
Jump_SFXPM | string | Yes | |
Jump_SFXPMATTACHMENT | string | Yes | |
JUMP_SFXPMATTACHMENT | string | No | |
Jump_SPEED | real | Yes | |
JUMP_TIME | real | No | |
JUMP_TREE | boolean | No | |
Jump_TREE | boolean | Yes | |
Jump_UNIT | unit | Yes | |
JUMP_UNIT | unit | No | |
JUMP_VALUE | integer | No | |
k7 | integer | Yes | |
Kills | integer | Yes | |
leaklocation | location | No | |
leaklocation2 | location | No | |
leaklocation3 | location | No | |
leaklocation_Copier | location | No | |
LF_lastCreatedSound | sound | No | |
LF_x_channel | integer | No | |
LF_x_duration | integer | No | |
LF_x_eaxSetting | string | No | |
LF_x_fadeInRate | integer | No | |
LF_x_fadeOutRate | integer | No | |
LF_x_is3D | boolean | No | |
LF_x_looping | boolean | No | |
LF_x_Path | string | No | |
LF_x_pitch | real | No | |
LF_x_stopwhenoutofrange | boolean | No | |
LF_x_volume | integer | No | |
Load | integer | Yes | |
LoadCount | integer | No | |
loc | location | No | |
loc_Copier | location | No | |
mini_unit | unit | No | |
mini_unit_Copier | unit | No | |
mob | unit | No | |
Mort | force | No | |
name | string | Yes | |
nom | texttag | Yes | |
objet | item | No | |
otage1 | boolean | No | |
otage2 | boolean | No | |
otage3 | boolean | No | |
PD_Angle | real | Yes | |
PD_Distances | real | Yes | |
PD_Integers | integer | Yes | |
PD_ReachedDistance | real | Yes | |
PD_RealTimer | real | Yes | |
PD_SpeedUnits | real | Yes | |
PD_TempPoint | location | Yes | |
PD_TestGroup | group | No | |
PD_TreesDestroy | boolean | Yes | |
PD_Unit | unit | Yes | |
playernumber | integer | No | |
PlayerUnit | unit | Yes | |
POINT | location | Yes | |
Point | location | No | |
Quete | quest | Yes | |
r | real | No | |
region | rect | No | |
rez_team | unit | Yes | |
Rez_time | timer | Yes | |
Rez_TW | timerdialog | Yes | |
Safe | integer | No | |
sang | effect | Yes | |
Save | integer | Yes | |
SaveCount | integer | No | |
SaveLoad_Alphabet | string | No | |
SaveLoad_Base | integer | No | |
SaveLoad_Char | string | Yes | |
SaveLoad_CheckName | boolean | No | |
SaveLoad_Error | string | No | |
SaveLoad_Full | string | No | |
SaveLoad_Hero | unitcode | Yes | |
SaveLoad_HeroCount | integer | No | |
SaveLoad_HyphenSpace | integer | No | |
SaveLoad_Item | itemcode | Yes | |
SaveLoad_ItemCount | integer | No | |
SaveLoad_Lower | string | No | |
SaveLoad_MaxValue | integer | No | |
SaveLoad_Number | string | No | |
SaveLoad_Security | boolean | No | |
SaveLoad_SeperationChar | string | No | |
SaveLoad_Upper | string | No | |
SaveLoad_Valid | boolean | No | |
SE_AttackType | attacktype | No | |
SE_DamageType | damagetype | No | |
SE_ExplosionDamages | real | Yes | |
SE_ExplosionDamagesAoe | real | Yes | |
SE_ExplosionModel | string | No | |
SE_Hash | hashtable | No | |
SE_Integer | integer | No | |
SE_Integer2 | integer | No | |
SE_Integer3 | integer | No | |
SE_Integer4 | integer | No | |
SE_Point | location | No | |
SE_Point2 | location | No | |
SE_Real | real | No | |
SE_Real2 | real | No | |
SE_Real3 | real | No | |
SE_RockGroup | group | No | |
SE_RockHeightDecrement | real | Yes | |
SE_RockHeightSpeed | real | Yes | |
SE_RocksAngle | real | Yes | |
SE_RocksAngleRandom | real | Yes | |
SE_RockScaleMax | real | Yes | |
SE_RockScaleMin | real | Yes | |
SE_RocksDamages | real | Yes | |
SE_RocksDamagesAoe | real | Yes | |
SE_RocksIntervalAngle | real | Yes | |
SE_RocksNumber | integer | Yes | |
SE_RockSpeed | real | Yes | |
SE_RocksUnitType | unitcode | No | |
SE_SandInterval | integer | Yes | |
SE_SandModel | string | No | |
SE_SandSpeed | real | Yes | |
SE_SandUnitType | unitcode | No | |
SE_Unit | unit | No | |
SE_Unit2 | unit | No | |
SE_WaveGroup | group | No | |
ShockRifle_Data | real | Yes | |
ShockRifle_Group | group | Yes | |
ShockRifle_Max | integer | No | |
ShockRifle_Orbs | group | No | |
ShockRifle_Unit | unit | Yes | |
Son | integer | No | |
spawn | integer | No | |
SPLITBOOM_AOE | real | Yes | |
SPLITBOOM_COUNT | integer | Yes | |
SPLITBOOM_DAMAGE | real | Yes | |
SPLITBOOM_DEGREE | real | Yes | |
SPLITBOOM_DUMMY | unitcode | Yes | |
SPLITBOOM_HEIGHT | real | Yes | |
SPLITBOOM_SCALE | real | Yes | |
Sprint | force | No | |
StringColor | string | Yes | |
TEMP_GROUP | group | No | |
TEMP_LOC | location | No | |
TEMP_LOC2 | location | No | |
TEMP_REAL | real | No | |
TEMP_UNIT | unit | No | |
TempAngle | real | No | |
TempForce | force | No | |
TempGroup | group | No | |
TempPoint | location | No | |
TempPoint2 | location | No | |
TempTarget | unit | No | |
texte1 | texttag | No | |
texte10 | texttag | No | |
texte11 | texttag | No | |
texte12 | texttag | No | |
texte13 | texttag | No | |
texte14 | texttag | No | |
texte15 | texttag | No | |
texte16 | texttag | No | |
texte17 | texttag | No | |
texte18 | texttag | No | |
texte19 | texttag | No | |
texte2 | texttag | No | |
texte20 | texttag | No | |
texte21 | texttag | No | |
texte22 | texttag | No | |
texte23 | texttag | No | |
texte24 | texttag | No | |
texte25 | texttag | No | |
texte26 | texttag | No | |
texte27 | texttag | No | |
texte28 | texttag | No | |
texte29 | texttag | No | |
texte3 | texttag | No | |
texte30 | texttag | No | |
texte31 | texttag | No | |
texte32 | texttag | No | |
texte33 | texttag | No | |
texte34 | texttag | No | |
texte35 | texttag | No | |
texte4 | texttag | No | |
texte5 | texttag | No | |
texte6 | texttag | No | |
texte7 | texttag | No | |
texte8 | texttag | No | |
texte9 | texttag | No | |
timer | timer | No | |
timerwindow | timerdialog | No | |
turning | real | Yes | |
u | unit | No | |
u1 | unit | No | |
u2 | unit | No | |
u3 | unit | No | |
u4 | unit | No | |
UC_Counter | integer | Yes | |
UC_Groups | group | Yes | |
UC_Inv | boolean | Yes | |
UC_SETTINGS_AreaOfEffect | real | Yes | |
UC_SETTINGS_Collosion | boolean | No | |
UC_SETTINGS_DestroyTrees_Dash | boolean | No | |
UC_SETTINGS_Invulnerable | boolean | No | |
UC_SETTINGS_Speed | real | No | |
UC_Target | unit | No | |
UC_TempPoint | location | Yes | |
UDex | integer | No | |
UDexGen | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexRecycle | integer | No | |
UDexUnits | unit | Yes | |
UDexWasted | integer | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
v1 | unit | No | |
v10 | unit | No | |
v11 | unit | No | |
v12 | unit | No | |
v2 | unit | No | |
v3 | unit | No | |
v4 | unit | No | |
v5 | unit | No | |
v6 | unit | No | |
v7 | unit | No | |
v8 | unit | No | |
v9 | unit | No | |
Vivant | force | No | |
weapon | effect | Yes | |
x | real | No | |
x2 | real | No | |
y | real | No | |
y2 | real | No | |
YourSounds | sound | Yes | |
zLoc | location | No | |
Zombie | force | No | |
zombie | unit | Yes |
//TESH.scrollpos=21
//TESH.alwaysfold=0
library AdvancedCameraSystem initializer Init
// Advanced Camera System by The_Witcher
//
// This is a very advanced advanced camera system which adjusts the camera
// distance to the target so the camera isn't looking through houses/trees/...
// and the cameras angle of attack so the view isn't blocked because of hills...
//
// useful for RPGs and that stuff
//
// To bind the camera to a unit for a player use
// SetCameraUnit( unit, player )
//
// if you want to have your normal camera again use
// ReleaseCameraUnit( player )
//
// in case you want to know which unit is bound to the camera for player xy use
// GetCameraUnit( player )
//
// to change the AngleOfAttack of a player ingame use
// SetCamDefaultAngleOfAttack( Player, NewValue )
//
// to change the maximal camera target distance of a player ingame use
// SetCamMaxDistance( Player, NewValue )
//
// to change the maximal distance behind the target, the z-offset is checked (for z-angle), of a player ingame use
// SetCamMaxZCheckDistance( Player, NewValue )
//
// SETUP PART
globals
// The max. distance the camera can have to the target
private real DEFAULT_MAX_DISTANCE = 250
// The max. distance the zOffset behind the unit is checked (for zAngle)
private real DEFAULT_MAX_Z_CHECK_DISTANCE = 250
// the camera angle of attack correction after the zAngle calculation
private real DEFAULT_ANGLE_OF_ATTACK = -19
// the timer interval (0.01 is best but can lagg in huge maps with many of these short intervals)
private constant real INTERVAL = 0.10
// the time the camera will need to adjust
private constant real DELAY = 0.25
// the standart z of the camera
private constant real NORMAL_HEIGHT = 100
// the accuracy increases if the value gets smaller
private constant real ACCURACY = 50
// the secondary accruracy when the camera reaches a barricade (just leave at this amount)
private constant real EXTREME_ACCURACY = 10
endglobals
// SETUP END
// don't modify the code below!
globals
private item ite
private real array Aoa[15]
private real array Dist[15]
private real array CheckDist[15]
private unit array CamUnit[15]
private timer tim = CreateTimer()
private location loc = Location(0,0)
private integer active = 0
private hashtable h = InitHashtable()
endglobals
private function IsCoordPathable takes real x, real y returns boolean
call SetItemVisible(ite,true)
call SetItemPosition(ite,x,y)
set x = GetItemX( ite) - x
set y = GetItemY( ite) - y
call SetItemVisible(ite,false)
if x < 1 and x > -1 and y < 1 and y > -1 then
return true
endif
return false
endfunction
private function HideAllItems takes nothing returns nothing
if IsItemVisible(GetEnumItem()) then
call SaveInteger(h,GetHandleId(GetEnumItem()),0,1)
endif
call SetItemVisible(GetEnumItem(),false)
endfunction
private function ShowAllItems takes nothing returns nothing
if LoadInteger(h,GetHandleId(GetEnumItem()),0) == 1 then
call SetItemVisible(GetEnumItem(),true)
call FlushChildHashtable(h,GetHandleId(GetEnumItem()))
endif
endfunction
private function Actions takes nothing returns nothing
local real x
local real y
local real angle
local real rz
local real z
local integer i = 0
local integer Check
local real CheckDistance
local real DistanceDone
local rect rec
loop
exitwhen i >= bj_MAX_PLAYERS
if CamUnit[i] != null then
set DistanceDone = 0
set rz = 0
set x = GetUnitX(CamUnit[i])
set y = GetUnitY(CamUnit[i])
set Check = 1
set angle = (GetUnitFacing(CamUnit[i]) - 180)*bj_DEGTORAD
set CheckDistance = ACCURACY
set z = DEFAULT_ANGLE_OF_ATTACK
if not IsUnitType(CamUnit[i], UNIT_TYPE_FLYING) then
loop
set x = x + CheckDistance * Cos(angle)
set y = y + CheckDistance * Sin(angle)
set DistanceDone = DistanceDone + CheckDistance
call MoveLocation(loc,x,y)
set z = GetLocationZ(loc)
if RAbsBJ(z) > RAbsBJ(rz) and DistanceDone <= CheckDist[i] then
set rz = z
endif
if not IsCoordPathable(x,y)then
set rec = Rect(x-ACCURACY,y-ACCURACY,x+ACCURACY,y+ACCURACY)
call EnumItemsInRect(rec,null, function HideAllItems)
if not IsCoordPathable(x,y)then
set Check = 0
endif
call RemoveRect(rec)
endif
if Check == 0 and CheckDistance == ACCURACY then
set DistanceDone = DistanceDone - CheckDistance
set x = x - CheckDistance * Cos(angle)
set y = y - CheckDistance * Sin(angle)
set Check = 1
set CheckDistance = EXTREME_ACCURACY
endif
exitwhen (Check == 0 and CheckDistance == EXTREME_ACCURACY) or DistanceDone > Dist[i]
endloop
else
set DistanceDone = Dist[i]
endif
call MoveLocation(loc,GetUnitX(CamUnit[i]),GetUnitY(CamUnit[i]))
set x = GetLocationZ(loc)
loop
exitwhen x - rz < 180
set x = x - 180
endloop
set z = Atan2(x-rz,200) * bj_RADTODEG + Aoa[i]
if IsUnitType(CamUnit[i], UNIT_TYPE_FLYING) then
set z = Aoa[i]
endif
if GetLocalPlayer() == Player(i) then
call CameraSetSmoothingFactor(1)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, DistanceDone, DELAY)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, z, DELAY)
call SetCameraField(CAMERA_FIELD_ZOFFSET,GetCameraField(CAMERA_FIELD_ZOFFSET)+x+GetUnitFlyHeight(CamUnit[i])+NORMAL_HEIGHT-GetCameraTargetPositionZ(),DELAY)
call SetCameraField(CAMERA_FIELD_ROTATION, angle*bj_RADTODEG+180, DELAY)
call SetCameraTargetController(CamUnit[i],0,0,false)
endif
endif
set i = i + 1
endloop
call EnumItemsInRect(bj_mapInitialPlayableArea,null, function ShowAllItems)
set rec = null
endfunction
function ReleaseCameraUnit takes player p returns nothing
if CamUnit[GetPlayerId(p)] != null then
set CamUnit[GetPlayerId(p)] = null
call ResetToGameCameraForPlayer(p,0)
if GetLocalPlayer() == p then
call CameraSetSmoothingFactor(0)
endif
set active = active - 1
if active == 0 then
call PauseTimer(tim)
endif
endif
endfunction
function SetCameraUnit takes unit u, player owner returns nothing
if CamUnit[GetPlayerId(owner)] != null then
call ReleaseCameraUnit(owner)
endif
set CamUnit[GetPlayerId(owner)] = u
set active = active + 1
if active == 1 then
call TimerStart(tim,INTERVAL,true,function Actions)
endif
endfunction
function SetCamDefaultAngleOfAttack takes player p, real a returns nothing
set Aoa[GetPlayerId(p)] = a
endfunction
function SetCamMaxDistance takes player p, real d returns nothing
set Dist[GetPlayerId(p)] = d
endfunction
function SetCamMaxZCheckDistance takes player p, real d returns nothing
set CheckDist[GetPlayerId(p)] = d
endfunction
function GetCameraUnit takes player pl returns unit
return CamUnit[GetPlayerId(pl)]
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYERS
set CamUnit[i] = null
set Aoa[i] = DEFAULT_ANGLE_OF_ATTACK
set Dist[i] = DEFAULT_MAX_DISTANCE
set CheckDist[i] = DEFAULT_MAX_Z_CHECK_DISTANCE
set i = i + 1
endloop
set ite = CreateItem( 'wolg', 0,0 )
call SetItemVisible(ite,false)
endfunction
endlibrary
//TESH.scrollpos=36
//TESH.alwaysfold=0
library KeyboardSystem initializer Init
// Keyboard System by The_Witcher
// This System helps you to get rid of all the triggers
// you would need for creating an effective arrow key
// system.
// This system has aditionally the power to add a key twice press event to a trigger
// you just need to adjust this little variable:
globals
// this is the time the player has to "double press" a key
// if a key is pressed twice in this time the registered triggers are executed
private constant real DELAY = 0.2
endglobals
// Use this function to see which keys are hold down:
//
// IsKeyDown( key, pl) returns boolean
// string player
//
// key can be KEY_LEFT, KEY_RIGHT, KEY_UP or KEY_DOWN
// pl is the player who is checked
// if the function returns true the key is hold down by player pl
//
// And this 2 functions to register a double press event to a trigger
//
// TriggerRegisterKeyDoublePressEvent(t, key)
//
// TriggerRegisterPlayerKeyDoublePressEvent(t, key, pl)
//
// TriggerRegisterKeyDoubleInterruptEvent(t, key)
//
// TriggerRegisterPlayerKeyDoubleInterruptEvent(t, key, pl)
//
// t is the trigger you want to register that event to
// key is the pressed key (again can be KEY_LEFT, KEY_RIGHT, KEY_UP or KEY_DOWN)
// pl is in the second function the player who has to press
// the keys to fire the trigger
// the first function fires the trigger regardless of which player pressed the key
//
//
//--------------Don't edit anything below---------------------------
globals
private timer array time[13]
private trigger array TRIGGERS
private trigger array TRIGGERS2
private integer total = 0
private integer total2 = 0
private integer array PLAYER
private integer array PLAYER2
private string array KEY
private string array KEY2
constant string KEY_LEFT = "left"
constant string KEY_RIGHT = "right"
constant string KEY_UP = "up"
constant string KEY_DOWN = "down"
private hashtable h = InitHashtable()
endglobals
function IsKeyDown takes string key, player pl returns boolean
return LoadBoolean(h,GetPlayerId(pl),StringHash(key))
endfunction
function TriggerRegisterKeyDoublePressEvent takes trigger t, string key returns nothing
set TRIGGERS[total] = t
set KEY[total] = key
set PLAYER[total] = 100
set total = total + 1
endfunction
function TriggerRegisterPlayerKeyDoublePressEvent takes trigger t, string key, player pl returns nothing
set TRIGGERS[total] = t
set KEY[total] = key
set PLAYER[total] = GetPlayerId(pl)
set total = total + 1
endfunction
function TriggerRegisterKeyDoubleInterruptEvent takes trigger t, string key returns nothing
set TRIGGERS2[total2] = t
set KEY2[total2] = key
set PLAYER2[total2] = 100
set total2 = total2 + 1
endfunction
function TriggerRegisterPlayerKeyDoubleInterruptEvent takes trigger t, string key, player pl returns nothing
set TRIGGERS2[total2] = t
set KEY2[total2] = key
set PLAYER2[total2] = GetPlayerId(pl)
set total2 = total2 + 1
endfunction
//! textmacro TriggerActions takes NAME, VarTrue, VarFalse
private function $NAME$press takes nothing returns nothing
local integer i = GetPlayerId(GetTriggerPlayer())
local integer x = 0
call SaveBoolean(h,i,StringHash("$VarTrue$"),true)
call SaveBoolean(h,i,StringHash("$VarFalse$"),false)
if LoadStr(h,i,StringHash("LastKey")) != "$VarTrue$" then
call TimerStart(time[i],0,false,null)
endif
if TimerGetRemaining(time[i]) > 0 and LoadStr(h,i,StringHash("LastKey")) == "$VarTrue$" then
call SaveInteger(h,i,StringHash("Debug"),0)
call SaveBoolean(h,i,StringHash("$VarTrue$Double"),true)
loop
exitwhen x >= total
if TriggerEvaluate(TRIGGERS[x]) and KEY[x] == "$VarTrue$" and (PLAYER[x] == 100 or PLAYER[x] == i) then
call TriggerExecute(TRIGGERS[x])
endif
set x = x + 1
endloop
endif
if LoadInteger(h,i,StringHash("Debug")) == 1 then
call TimerStart(time[i],DELAY,false,null)
else
call SaveInteger(h,i,StringHash("Debug"),1)
endif
call SaveStr(h,i,StringHash("LastKey"),"$VarTrue$")
endfunction
private function $NAME$release takes nothing returns nothing
local integer i = GetPlayerId(GetTriggerPlayer())
local integer x = 0
call SaveBoolean(h,i,StringHash("$VarTrue$"),false)
if LoadBoolean(h,i,StringHash("$VarTrue$Double")) then
call SaveBoolean(h,i,StringHash("$VarTrue$Double"),false)
loop
exitwhen x >= total2
if TriggerEvaluate(TRIGGERS2[x]) and KEY2[x] == "$VarTrue$" and (PLAYER2[x] == 100 or PLAYER2[x] == i) then
call TriggerExecute(TRIGGERS2[x])
endif
set x = x + 1
endloop
endif
endfunction
//! endtextmacro
//! runtextmacro TriggerActions("LEFT","left","right")
//! runtextmacro TriggerActions("RIGHT","right","left")
//! runtextmacro TriggerActions("UP","up","down")
//! runtextmacro TriggerActions("DOWN","down","up")
//! textmacro Initiate takes NAME
set i = 0
set t = CreateTrigger()
set tt = CreateTrigger()
call TriggerAddAction(t,function $NAME$press)
call TriggerAddAction(tt,function $NAME$release)
loop
exitwhen i > 12
call TriggerRegisterPlayerEvent(t,Player(i),EVENT_PLAYER_ARROW_$NAME$_DOWN)
call TriggerRegisterPlayerEvent(tt,Player(i),EVENT_PLAYER_ARROW_$NAME$_UP)
set i = i + 1
endloop
//! endtextmacro
private function Init takes nothing returns nothing
local trigger t
local trigger tt
local integer i
//! runtextmacro Initiate("LEFT")
//! runtextmacro Initiate("RIGHT")
//! runtextmacro Initiate("UP")
//! runtextmacro Initiate("DOWN")
set i = 0
loop
exitwhen i > 12
set time[i] = CreateTimer()
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ArrowKeyMovement initializer Init requires KeyboardSystem, ArrowKeyMovementPlugins
// Arrow key movement by The_Witcher
// this system allows each player to control 1 unit
// with his arrow keys even if he doesn't own the unit!
// It features turning on the left and right arrow, walking foreward
// by pressing the up arrow and walking backwards by pressing the down arrow...
//
// You can improve this system with plugins but you need vJass knowledge for that!
//
// --> The TurnRate of a unit inside the object editor STILL influences the turn rate from this system <--
//
// Included functions:
//
// SetMovementUnit ( whichunit, forWhichPlayer, walkAnimationIndex )
// unit player integer
// this gives the player the arrow key movement control over the unit
// while the unit moves the animation of the given index is played
// (just try around to find the index... start at 0 and increase
// by 1 until you find the walk index of that unit)
//
//
// ReleaseMovementUnit ( fromWhichPlayer )
// player
// this function removes the control from a player
//
//
// GetMovementUnit ( fromWhichPlayer ) returns unit
// player
// I think its self explaining...
//
//
// SetMovementUnitAnimation ( fromWhichPlayer, animation )
// player integer
// this function allows ingame changing of the played animation of a unit
// ------- SETUP PART ---------
globals
// the timer interval... increase if laggy
private constant real INTERVAL = 0.04
// the facing change in degrees each interval (must be a positive value)
private constant real DEFAULT_VIEW_CHANGE = 12
// when you move backwards you move slower than normal...
private constant real BACKWARDS_MOVING_FACTOR = 0.7
// if the unit turns it will turn faster the longer it does...
// some people may need that but then it should be 1.02 (1.0 means disabled)
private constant real TURN_ACCELERATION = 1
// (can only be 1 or -1) if you walk backwards you have 2 ways of turning
// 1. way: pressing left will make the char turn left
// 2. way: pressing left will make the char turn so he moves to the left
private constant integer REVERSED_BACKWARDS_MOVING = 1
endglobals
// whenever this function returns false for a unit it won't be moved even if the player
// presses the keys! change to create your own "No Movement" conditions
private function MoveConditions takes unit u returns boolean
return not IsUnitType(u,UNIT_TYPE_SLEEPING) and not IsUnitType(u,UNIT_TYPE_STUNNED)
endfunction
// --------- don't modify anything below this line ------------
struct ArrowKeyMovement
private static ArrowKeyMovement array all [12] // = bj_MAX_PLAYERS
private static timer tim
integer walking
unit u
integer animation
real SpeedFactor
real ViewChange
real SpecialDirection
boolean SpecialDirectionActive
static method operator [] takes player p returns ArrowKeyMovement
local integer i = GetPlayerId(p)
if .all[i] == 0 then
set .all[i] = ArrowKeyMovement.create()
set .all[i].SpeedFactor = 1
set .all[i].SpecialDirection = 0
set .all[i].SpecialDirectionActive = false
set .all[i].ViewChange = DEFAULT_VIEW_CHANGE
endif
return .all[i]
endmethod
private static method Walking takes nothing returns nothing
local integer i = 0
local real x
local real y
local real X
local real Y
local boolean boolX
local boolean boolY
local boolean left
local boolean right
local boolean up
local boolean down
local ArrowKeyMovement mov
loop
exitwhen i >= 12 // = bj_MAX_PLAYERS
set mov = .all[i]
if mov.u != null and MoveConditions(mov.u) then
// special movement <-- plugins
if mov.SpecialDirectionActive then
if mov.walking != 1 then
call SetUnitTimeScale(mov.u,mov.SpeedFactor)
call SetUnitAnimationByIndex(mov.u,mov.animation)
set mov.walking = 1
else
call SetUnitTimeScale(mov.u,mov.SpeedFactor)
endif
set x = GetUnitX(mov.u)
set y = GetUnitY(mov.u)
set X = x + GetUnitMoveSpeed(mov.u)*INTERVAL * Cos(mov.SpecialDirection*bj_DEGTORAD) * mov.SpeedFactor
set Y = y + GetUnitMoveSpeed(mov.u)*INTERVAL * Sin(mov.SpecialDirection*bj_DEGTORAD) * mov.SpeedFactor
call SetUnitPosition(mov.u,X,Y)
if (RAbsBJ(GetUnitX(mov.u)-X)>0.5)or(RAbsBJ(GetUnitY(mov.u)-Y)>0.5)then
call SetUnitPosition(mov.u,X,y)
set boolX = RAbsBJ(GetUnitX(mov.u)-X)<=0.5
call SetUnitPosition(mov.u,x,Y)
set boolY = RAbsBJ(GetUnitY(mov.u)-Y)<=0.5
if boolX then
call SetUnitPosition(mov.u,X,y)
elseif boolY then
call SetUnitPosition(mov.u,x,Y)
else
call SetUnitPosition(mov.u,x,y)
endif
endif
else
// Normal movement
set left = IsKeyDown(KEY_LEFT,Player(i))
set right = IsKeyDown(KEY_RIGHT,Player(i))
set up = IsKeyDown(KEY_UP,Player(i))
set down = IsKeyDown(KEY_DOWN,Player(i))
//right down
if right then
if down then
call SetUnitFacing(mov.u,GetUnitFacing(mov.u)-mov.ViewChange * -REVERSED_BACKWARDS_MOVING)
else
call SetUnitFacing(mov.u,GetUnitFacing(mov.u)-mov.ViewChange)
endif
set mov.ViewChange = mov.ViewChange * TURN_ACCELERATION
elseif not left then
set mov.ViewChange = DEFAULT_VIEW_CHANGE
endif
//left down
if left then
if down then
call SetUnitFacing(mov.u,GetUnitFacing(mov.u)+mov.ViewChange * -REVERSED_BACKWARDS_MOVING)
else
call SetUnitFacing(mov.u,GetUnitFacing(mov.u)+mov.ViewChange)
endif
set mov.ViewChange = mov.ViewChange * TURN_ACCELERATION
elseif not right then
set mov.ViewChange = DEFAULT_VIEW_CHANGE
endif
//up down
if up then
if mov.walking != 1 then
call SetUnitTimeScale(mov.u,mov.SpeedFactor)
call SetUnitAnimationByIndex(mov.u,mov.animation)
set mov.walking = 1
else
call SetUnitTimeScale(mov.u,mov.SpeedFactor)
endif
set x = GetUnitX(mov.u)
set y = GetUnitY(mov.u)
set X = x + GetUnitMoveSpeed(mov.u)*INTERVAL * Cos(GetUnitFacing(mov.u)*bj_DEGTORAD) * mov.SpeedFactor
set Y = y + GetUnitMoveSpeed(mov.u)*INTERVAL * Sin(GetUnitFacing(mov.u)*bj_DEGTORAD) * mov.SpeedFactor
//down down
elseif down then
if mov.walking != 2 then
call SetUnitTimeScale(mov.u,-BACKWARDS_MOVING_FACTOR * mov.SpeedFactor)
call SetUnitAnimationByIndex(mov.u,mov.animation)
set mov.walking = 2
else
call SetUnitTimeScale(mov.u,-BACKWARDS_MOVING_FACTOR * mov.SpeedFactor)
endif
set x = GetUnitX(mov.u)
set y = GetUnitY(mov.u)
set X = x - GetUnitMoveSpeed(mov.u) * INTERVAL * Cos(GetUnitFacing(mov.u)*bj_DEGTORAD) * BACKWARDS_MOVING_FACTOR * mov.SpeedFactor
set Y = y - GetUnitMoveSpeed(mov.u) * INTERVAL * Sin(GetUnitFacing(mov.u)*bj_DEGTORAD) * BACKWARDS_MOVING_FACTOR * mov.SpeedFactor
endif
//move
if down or up then
call SetUnitPosition(mov.u,X,Y)
if (RAbsBJ(GetUnitX(mov.u)-X)>0.5)or(RAbsBJ(GetUnitY(mov.u)-Y)>0.5)then
call SetUnitPosition(mov.u,X,y)
set boolX = RAbsBJ(GetUnitX(mov.u)-X)<=0.5
call SetUnitPosition(mov.u,x,Y)
set boolY = RAbsBJ(GetUnitY(mov.u)-Y)<=0.5
if boolX then
call SetUnitPosition(mov.u,X,y)
elseif boolY then
call SetUnitPosition(mov.u,x,Y)
else
call SetUnitPosition(mov.u,x,y)
endif
endif
else
if mov.walking != 0 then
call SetUnitAnimation(mov.u,"stand")
call SetUnitTimeScale(mov.u,1)
set mov.walking = 0
endif
endif
endif
endif
set i = i + 1
endloop
endmethod
static method onInit takes nothing returns nothing
set .tim = CreateTimer()
call TimerStart(.tim,INTERVAL,true,function ArrowKeyMovement.Walking)
endmethod
endstruct
function GetMovementUnit takes player p returns unit
return ArrowKeyMovement[p].u
endfunction
function SetMovementUnitAnimation takes player p, integer animation returns nothing
set ArrowKeyMovement[p].animation = animation
endfunction
function ReleaseMovementUnit takes player p returns nothing
if ArrowKeyMovement[p].u != null then
set ArrowKeyMovement[p].walking = 0
call SetUnitAnimation(ArrowKeyMovement[p].u,"stand")
call SetUnitTimeScale(ArrowKeyMovement[p].u,1)
set ArrowKeyMovement[p].u = null
endif
endfunction
function SetMovementUnit takes unit u, player p, integer anim returns nothing
if u == null then
call ReleaseMovementUnit(p)
return
endif
if ArrowKeyMovement[p].u != null then
call ReleaseMovementUnit(p)
endif
call SetUnitAnimation(ArrowKeyMovement[p].u,"stand")
set ArrowKeyMovement[p].u = u
set ArrowKeyMovement[p].animation = anim
endfunction
//! runtextmacro ArrowKeyMovement_Plugins_Functions()
private function Init takes nothing returns nothing
//! runtextmacro Init_ArrowKeyMovement_Plugins()
endfunction
endlibrary
//TESH.scrollpos=48
//TESH.alwaysfold=0
library ArrowKeyMovementPlugins
// code your own plugins for my Arrow key movement system!
// how you do that is explained in detail in the "How to use the Movement System Plugins"
// comment included in this map
//
//
// the plugins I coded for the test map are:
// 1. running fast/dashing when double pressing up
// 2. turning around (180°) when double pressing down
// 3. moving left without changing face direction when double pressing left
// 4. moving right without changing face direction when double pressing right
//! textmacro Init_ArrowKeyMovement_Plugins
local trigger t
// This is the initialization for turning around on double down press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleDownPress)
call TriggerRegisterKeyDoublePressEvent(t,KEY_DOWN)
// This is the initialization for dashing on double up press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleUpPress)
call TriggerRegisterKeyDoublePressEvent(t,KEY_UP)
// This is the initialization for sliding left on double left press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleLeftPress)
call TriggerRegisterKeyDoublePressEvent(t,KEY_LEFT)
// This is the initialization for sliding right on double right press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleRightPress)
call TriggerRegisterKeyDoublePressEvent(t,KEY_RIGHT)
// This is the initialization for stoping the dash of double up press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleUpRelease)
call TriggerRegisterKeyDoubleInterruptEvent(t,KEY_UP)
// This is the initialization for stoping slide of double left press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleLeftRelease)
call TriggerRegisterKeyDoubleInterruptEvent(t,KEY_LEFT)
// This is the initialization for stoping slide of double right press
set t = CreateTrigger()
call TriggerAddAction(t, function OnDoubleRightRelease)
call TriggerRegisterKeyDoubleInterruptEvent(t,KEY_RIGHT)
//! endtextmacro
//! textmacro ArrowKeyMovement_Plugins_Functions
// This is the function for turning around on double down press
private function OnDoubleDownPress takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = false
call SetUnitFacing(mov.u,GetUnitFacing(mov.u)-180)
endfunction
// This is the function for dashing on double up press
private function OnDoubleUpPress takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = false
set mov.SpeedFactor = 1
endfunction
// This is the function for sliding left on double left press
private function OnDoubleLeftPress takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = true
set mov.SpecialDirection = GetUnitFacing(mov.u) + 90
set mov.SpeedFactor = 0.6
endfunction
// This is the function for sliding right on double right press
private function OnDoubleRightPress takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = true
set mov.SpecialDirection = GetUnitFacing(mov.u) - 90
set mov.SpeedFactor = 0.6
endfunction
// This is the function for stoping the dash of double up press
private function OnDoubleUpRelease takes nothing returns nothing
set ArrowKeyMovement[GetTriggerPlayer()].SpeedFactor = 1
endfunction
// This is the function for stoping slide of double left press
private function OnDoubleLeftRelease takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = false
set mov.SpeedFactor = 1
endfunction
// This is the function for stoping slide of double right press
private function OnDoubleRightRelease takes nothing returns nothing
local ArrowKeyMovement mov = ArrowKeyMovement[GetTriggerPlayer()]
set mov.SpecialDirectionActive = false
set mov.SpeedFactor = 1
endfunction
//! endtextmacro
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Table
//***************************************************************
//* Table object 3.1
//* ------------
//*
//* set t=Table.create() - instanceates a new table object
//* call t.destroy() - destroys it
//* t[1234567] - Get value for key 1234567
//* (zero if not assigned previously)
//* set t[12341]=32 - Assigning it.
//* call t.flush(12341) - Flushes the stored value, so it
//* doesn't use any more memory
//* t.exists(32) - Was key 32 assigned? Notice
//* that flush() unassigns values.
//* call t.reset() - Flushes the whole contents of the
//* Table.
//*
//* call t.destroy() - Does reset() and also recycles the id.
//*
//* If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//* You can use Table on structs' onInit if the struct is
//* placed in a library that requires Table or outside a library.
//*
//* You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//* set Table["thisstring"][ 7 ] = 2
//* set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************
//=============================================================
globals
private constant integer MAX_INSTANCES=8100 //400000
//Feel free to change max instances if necessary, it will only affect allocation
//speed which shouldn't matter that much.
//=========================================================
private hashtable ht = InitHashtable()
endglobals
private struct GTable[MAX_INSTANCES]
method reset takes nothing returns nothing
call FlushChildHashtable(ht, integer(this) )
endmethod
private method onDestroy takes nothing returns nothing
call this.reset()
endmethod
endstruct
//Hey: Don't instanciate other people's textmacros that you are not supposed to, thanks.
//! textmacro Table__make takes name, type, key
struct $name$ extends GTable
method operator [] takes $type$ key returns integer
return LoadInteger(ht, integer(this), $key$)
endmethod
method operator []= takes $type$ key, integer value returns nothing
call SaveInteger(ht, integer(this) ,$key$, value)
endmethod
method flush takes $type$ key returns nothing
call RemoveSavedInteger(ht, integer(this), $key$)
endmethod
method exists takes $type$ key returns boolean
return HaveSavedInteger( ht, integer(this) ,$key$)
endmethod
static method flush2D takes string firstkey returns nothing
call $name$(- StringHash(firstkey)).reset()
endmethod
static method operator [] takes string firstkey returns $name$
return $name$(- StringHash(firstkey) )
endmethod
endstruct
//! endtextmacro
//! runtextmacro Table__make("Table","integer","key" )
//! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
//! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library MemoryLeakHelper initializer Init requires Table
// ==================================
// Give credits to Mr.Malte when used!
//===========================================================================
// Information:
//==============
//
// There are things called 'memory Leaks'. When you create a group or use a location
// without destroying it, you will cause lag that stays in the whole game.
// If you implement this library into your map it will automatically fix a big part
// of those memory leaks, so reduce the lag extremely.
// This should mainfully be used by GUI-users because the system is designed for them.
//
// Of course no system can work totally automatically.
// But there is only one thing you have to do in order to prevent bugs:
// If you make groups or locations that have to be filled for more than CLEAN_UP_INTERVAL seconds
// you have to save them with the code:
//
// call ProtectHandle(XXX)
//
// Where XXX is filled with your variable. Otherwise that variable gets destroyed
// automatically. You can also fill in XXX with
//
// GetLastCaughtHandle()
//
// But if you save the things in a variable, I'd recommend to directly put the
// variable into the brackets. Note: GUI variables have the prefix 'udg_' in JASS.
//
// This gives the 'Do Nothing' function in GUI a sense!
// When you call DoNothing, all data that were caught by this system
// will be destroyed in CLEAN_UP_INTERVAL seconds, ignoring how big
// the number of caught handles is. This will not work, if the system is
// already cleaning up.
//===========================================================================
// Implementation:
//===============
//
// The easiest thing is to directly implement this thing into your map, when you start making
// it, so you don't have to look over your globals and use ProtectHandle on them.
// These are the steps you have to do to clear the memory leaks:
//
// 1. Download a tool called 'JassNewGen', and unpack it somewhere. You need that
// edit to use this tool. The 'JassNewGen' is used very commonly and offers other
// nice features. You can find it at:
// [url]http://www.wc3c.net/showthread.php?t=90999[/url]
// 2. Make a new trigger, and convert it to custom text. Insert everything
// the library contains into that trigger.
//
// 3. Download a system called 'Table' from this link:
// [url]http://www.wc3c.net/showthread.php?t=101246[/url]
// Do the same installation stuff for 'Table' as for this system.
//
// 4. Save your map and enjoy :-)
//
// Note: Instead of doing 2 and 3 you can also copy and paste the folder 'MemoryLeakHelper'
// from the example map.
//===========================================================================
// How bad are memory leaks?
//==========================
// If you don't remove memory leaks, they suck memory:
//
// Location: 0.361 kb
// Group: 0.62 kb + 0.040 kb for each unit in the group.
// Effect: 11.631 kb
//
// Both, locations and groups are used very frequently. So when you don't fix those memory leaks,
// you will experience lag.
// When you want to see, how useful this is for your map, implement it
// and write 'call DisplayLeaks()' into a custom script that is fired when
// they game ends.
//===========================================================================
// Changelog:
//===========
// v1.00 --- first version
// v1.01 --- able to detect special effects, too now.
// v1.02 --- made the system safer and reduced the number of variables to protect greatly.
// v1.03 --- Gave a sense to 'DoNothing'* GUI function and made the Pass Data part
// more accurate, so the time until data get destroyed are much more explicit
// now.
// v1.04 --- Added the very important constant MAX_LEAK_INSTANCES
//
// *if you don't want it to be hooked, comment line 350.
//===========================================================================
// FAQ:
// ====
// 1. Why don't you hook functions like GetLocationX or the ForGroup without BJ?
//
// Answer: Well, in jass you would never destroy groups, rather have one global group
// and clear/recycle it. But GUI always creates new groups with the functions.
// So actually, jass groups don't have to be destroyed.
// And special effects are mostly instantly destroyed and locations are never used.
// So I don't want to endanger breaking jass systems, I rather make it for GUI, where it is
// really useful and neccessary
//
// 2. Why should I protect my variables instead of killing my leaks?
//
// Answer: In GUI, unitgroup effect and location variables are actually just used
// for destroying stuff. It is rare that you really want to keep the groups.
// So in fact, it is like one-hundred times less frequent that you want to keep
// your data instead of destroying it.
//
// 3. I can't use jass. How can this system be useful for me?
//
// Answer: This system works mainly automatically; You just have to use jass very rarely (and then a simple function).
// The functions you need are:
//
// ProtectVariable(udg_###)
// GetLastCaughtHandle()
//
// where ProtectVariable saves something you want to keep from getting destroyed. Just replace ### with your
// variable name. NOTE: You don't have to protect the variable, when you want to keep the data inside less than
// CLEAN_UP_INTERVAL seconds.
//
// and where GetLastCaughtHandle responses to the handle* that was used lastly.
// That can be for example the point where you just spawned a unit.
//
// * 'handle' means a specialeffect, a location or a unitgroup
//
// 4. If you give functions like 'DelayMMH', why don't you add functions like 'Disable/EnableMMH'?
//
// Answer: Well, I want to protect the user. You do not need Disable/Enable functions.
// To me the danger is too big, that you forget to activate it again or do
// something like that. DelayMMH is totally enough if you don't want this system
// to affect the code that comes next. Also that prevents, that there are
// spells like 'Trojan Horses' that get too much access to this and can
// change it's infrastructure.
//
//===========================================================================
// Functions:
//==========
// ProtectHandle : Saves a handle from getting destroyed
// ProtectVariable : Same.
// DoNothing() : Destroys all data caught by the system right now in X seconds.
// DelayMMD() : Stops the system working until the trigger ends/next wait *
//
// * This is as fast as an automatic memory leak destroyer can get. Why should
// you want to disable the system? Because it offers the possibilty to make things
// more efficient. I don't want to say, this is unefficient, because it is not.
// But this will destroy leaks like 10% slower.
//
//===========================================================================
globals
// The system fires when you do something that creates a leak.
// The data that cause leak are saved in a variable then.
// And every CLEAN_UP_INTERVAL seconds those data are destroyed.
// This shouldn't be too high, or too low.
private constant real CLEAN_UP_INTERVAL = 120.
// If this is set to true, the system will work more slowly (but you wont notice)
// and count, how much memory this system was able to save.
// This value is display by the function DisplayLeaks() then.
// WARNING: This sucks a lot of performance. I would ONLY use it when you want
// to test, if this is useful for your map. Later set it to false.
private constant boolean DISPLAY_SAVED_MEMORY = false
// The Data are only cleaned up, when that many handles were caught
private constant integer MIN_LEAK_NUMBER = 1750
// How often are data passed to the destroyer?
// Leaks stay for a random time between CLEAN_UP_INTERVAL and CLEAN_UP_INTERVAL+PASS_INTERVAL
// in the game
private constant real PASS_INTERVAL = 2.5
// Memory leaks occur pretty frequently. When a leak is caught it is saved in
// an array. But the array can't have more than MAX_LEAK_INSTANCES instances, so
// if more than MAX_LEAK_INSTANCES memory leaks occur during a destroy interval,
// the system fails.
private constant integer MAX_LEAK_INSTANCES = 60000
endglobals
globals
private HandleTable IndexData
private HandleTable IsSaved
//! textmacro MemoryLeakVars takes NAME, TYPE
private integer Caught$NAME$Leaks = 0
private $TYPE$ array $NAME$LeakData[MAX_LEAK_INSTANCES]
private integer $NAME$DestroyCount = 0
private $TYPE$ array $NAME$DestroyData[MAX_LEAK_INSTANCES]
//! endtextmacro
//! runtextmacro MemoryLeakVars("Location","location")
//! runtextmacro MemoryLeakVars("Effect","effect")
//! runtextmacro MemoryLeakVars("Group","group")
private integer DestroyedLeaks = 0
private integer CaughtLeaks = 0
private integer DestroyedLeaksUser = 0
private handle LastCaught
private timer PassTimer = CreateTimer()
private timer CleanTimer = CreateTimer()
private timer DelayTimer = CreateTimer()
private boolean IsDestroying = false
private real SavedMemory = 0.
private real LastCheckedGroupMemoryUsage = 0.
private boolean DestroyThreadRunning = false
private boolean Disabled = false
// These values were found out in a big leak test by gekko.
private constant real LOCATION_MEMORY_USAGE = 0.361
private constant real GROUP_MEMORY_USAGE = 0.62
private constant real GROUP_UNIT_MEMORY_USAGE = 0.040
private constant real EFFECT_MEMORY_USAGE = 11.631
private constant real REMOVED_EFFECT_MEMORY_USAGE = 0.066
endglobals
// ======================================
// ============= Basic Code =============
// ======================================
function GetLastCaughtHandle takes nothing returns handle
return LastCaught
endfunction
function ProtectHandle takes handle h returns nothing
set IsSaved[h] = 1
endfunction
function ProtectVariable takes handle h returns nothing
set IsSaved[h] = 1
endfunction
private function EnableMMH takes nothing returns nothing
set Disabled = false
endfunction
function DelayMMH takes nothing returns nothing
set Disabled = true
call TimerStart(DelayTimer,0.00,false,function EnableMMH)
endfunction
function DisplayLeaks takes nothing returns nothing
call ClearTextMessages()
call BJDebugMsg("======= MemoryLeakHelper =======")
call BJDebugMsg("Destroyed Leaks: "+I2S(DestroyedLeaks))
call BJDebugMsg("Destroyed Leaks by user: "+I2S(DestroyedLeaksUser))
call BJDebugMsg("Percentage System: "+R2S(I2R(DestroyedLeaks)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Percentage User: "+R2S(I2R(DestroyedLeaksUser)/I2R(DestroyedLeaks+DestroyedLeaksUser)*100.)+"%")
call BJDebugMsg("Leaks until next destroy: "+I2S(MIN_LEAK_NUMBER-CaughtLeaks))
call BJDebugMsg(" === In Destroy Queue === ")
call BJDebugMsg(" Group Leaks: "+I2S(GroupDestroyCount))
call BJDebugMsg(" Location Leaks: "+I2S(LocationDestroyCount))
call BJDebugMsg(" Effect Leaks: "+I2S(EffectDestroyCount))
call BJDebugMsg(" === Not in Destroy Queue yet === ")
call BJDebugMsg(" Group Leaks: "+I2S(CaughtGroupLeaks))
call BJDebugMsg(" Location Leaks: "+I2S(CaughtLocationLeaks))
call BJDebugMsg(" Effect Leaks: "+I2S(CaughtEffectLeaks))
call BJDebugMsg("Time until next PassSequence: "+I2S(R2I(TimerGetRemaining(PassTimer)+0.5))+" seconds.")
call BJDebugMsg(" ")
if DISPLAY_SAVED_MEMORY then
call BJDebugMsg("All in all the MemoryLeakHelper could release "+R2S(SavedMemory)+" kb of memory.")
endif
call BJDebugMsg("================================")
endfunction
private function GroupGetMemoryUsageEnum takes nothing returns nothing
set LastCheckedGroupMemoryUsage = LastCheckedGroupMemoryUsage + GROUP_UNIT_MEMORY_USAGE
endfunction
function GroupGetMemoryUsage takes group g returns real
set LastCheckedGroupMemoryUsage = 0.
call ForGroup(g,function GroupGetMemoryUsageEnum)
return LastCheckedGroupMemoryUsage + GROUP_MEMORY_USAGE
endfunction
//! textmacro ResponseOnLeak takes NAME, VALUE
private function Catch$NAME$ takes $VALUE$ l returns nothing
set LastCaught = l
if Disabled then
return
elseif Caught$NAME$Leaks == MAX_LEAK_INSTANCES then
debug call BJDebugMsg("MemoryLeakHelper: Failed to store leak because of size limitations")
return
endif
if IndexData.exists(l) == false then
//call BJDebugMsg("Caught $NAME$")
set Caught$NAME$Leaks = Caught$NAME$Leaks + 1
set $NAME$LeakData[Caught$NAME$Leaks] = l
set IndexData[l] = Caught$NAME$Leaks
endif
endfunction
private function AddTo$NAME$DestroyQueue takes $VALUE$ l returns nothing
set $NAME$DestroyCount = $NAME$DestroyCount + 1
set $NAME$DestroyData[$NAME$DestroyCount] = l
set IndexData[l] = $NAME$DestroyCount*-1 // Put his to negative, so we know that this is used in the DestroyQueue now.
endfunction
private function Release$NAME$ takes $VALUE$ l returns nothing
local integer index
if IsDestroying == false and IndexData.exists(l) then
set index = IndexData[l]
// If this is true, the index wasn't put to a destroy queue yet.
if index > 0 then
set $NAME$LeakData[index] = $NAME$LeakData[Caught$NAME$Leaks]
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
else
set index = index * -1
set $NAME$DestroyData[index] = $NAME$DestroyData[$NAME$DestroyCount]
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endif
call IndexData.flush(l)
set DestroyedLeaksUser = DestroyedLeaksUser + 1
endif
endfunction
//! endtextmacro
//! runtextmacro ResponseOnLeak("Location","location")
//! runtextmacro ResponseOnLeak("Group","group")
//! runtextmacro ResponseOnLeak("Effect","effect")
private function DestroyMemoryLeaks takes nothing returns nothing
set IsDestroying = true
//call BJDebugMsg("DESTROYING Memory Leaks")
//! textmacro DestroyLeaks takes NAME, DESTROYCALL, MEMORYUSAGE
set DestroyedLeaks = DestroyedLeaks + $NAME$DestroyCount
loop
exitwhen $NAME$DestroyCount == 0
if DISPLAY_SAVED_MEMORY then
set SavedMemory = SavedMemory + $MEMORYUSAGE$
endif
call $DESTROYCALL$($NAME$DestroyData[$NAME$DestroyCount])
call IndexData.flush($NAME$DestroyData[$NAME$DestroyCount])
set $NAME$DestroyCount = $NAME$DestroyCount - 1
endloop
//! endtextmacro
//! runtextmacro DestroyLeaks ("Group","DestroyGroup","GroupGetMemoryUsage(GroupDestroyData[GroupDestroyCount])")
//! runtextmacro DestroyLeaks ("Location","RemoveLocation","LOCATION_MEMORY_USAGE")
//! runtextmacro DestroyLeaks ("Effect","DestroyEffect","EFFECT_MEMORY_USAGE")
set IsDestroying = false
set DestroyThreadRunning = false
//call StartPassTimer.execute() // Strange. This causes bugs sometimes and the function isn't called
// This is slower, but safe.
call ExecuteFunc("StartPassTimer")
endfunction
function StartDestroyThread takes nothing returns nothing
if DestroyThreadRunning == false then
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
call PauseTimer(PassTimer)
endif
endfunction
hook DoNothing StartDestroyThread
// We want that the user doesn't have to protect too many variables, but all the variables that are filled longer
// than CLEAN_UP_INTERVAL seconds. But what, when the handle thing is put into the destroy stack and the next destroy is
// in 5 seconds, because the last one was 15 seconds ago? We can simply avoid something like that by using a 2-step-system
// that goes sure, the handle is only destroyed when it passed the CLEAN_UP_INTERVAL twice.
// Having two kinds of variables is simply easier and more efficient than having another variable that refers to
// how many times the handle passed the timer; If it isn't passed/cleared in the Interval then, we can't loop
// that easily through the data and we'd have to fix gaps later; That would suck a lot of performacne.
private function PassMemoryLeaks takes nothing returns nothing
//call BJDebugMsg("PassMemoryLeaks")
//! textmacro PassLeaks takes NAME
set CaughtLeaks = CaughtLeaks + Caught$NAME$Leaks
//call BJDebugMsg("Caught $NAME$s: "+I2S(Caught$NAME$Leaks))
loop
exitwhen Caught$NAME$Leaks < 1
if IsSaved.exists($NAME$LeakData[Caught$NAME$Leaks]) == false and $NAME$LeakData[Caught$NAME$Leaks] != null then
call AddTo$NAME$DestroyQueue($NAME$LeakData[Caught$NAME$Leaks])
endif
set $NAME$LeakData[Caught$NAME$Leaks] = null
set Caught$NAME$Leaks = Caught$NAME$Leaks - 1
endloop
//! endtextmacro
//! runtextmacro PassLeaks ("Group")
//! runtextmacro PassLeaks ("Location")
//! runtextmacro PassLeaks ("Effect")
if CaughtLeaks > MIN_LEAK_NUMBER then
set CaughtLeaks = 0
//call BJDebugMsg("Caught Leaks: "+I2S(MIN_LEAK_NUMBER))
//call BJDebugMsg("Now start Destroy Timer")
set DestroyThreadRunning = true
call TimerStart(CleanTimer,CLEAN_UP_INTERVAL,false,function DestroyMemoryLeaks)
// We have to pause this timer a bit; Otherwise it would break the CLEAN_UP_INTERVAL rule.
call PauseTimer(PassTimer)
endif
endfunction
// =================================
// ============= Usage =============
// =================================
private function PP takes location source, real dist, real angle returns nothing
call CatchLocation(source)
endfunction
private function CU takes integer count, integer unitId, player p, location l, real face returns nothing
call CatchLocation(l)
endfunction
private function IPO takes unit k, string order, location l returns nothing
call CatchLocation(l)
endfunction
private function SUP takes unit who, location l returns nothing
call CatchLocation(l)
endfunction
private function SUF takes unit who, location l, real dur returns nothing
call CatchLocation(l)
endfunction
private function GUR takes real radius, location l, boolexpr filter returns nothing
call CatchLocation(l)
endfunction
private function CUF takes integer count, integer unitId, player whichPlayer, location loc, location lookAt returns nothing
call CatchLocation(loc)
call CatchLocation(lookAt)
endfunction
hook PolarProjectionBJ PP
hook CreateNUnitsAtLoc CU
hook CreateNUnitsAtLocFacingLocBJ CUF
hook IssuePointOrderLocBJ IPO
hook SetUnitPositionLoc SUP
hook SetUnitFacingToFaceLocTimed SUF
hook GetUnitsInRangeOfLocMatching GUR
hook RemoveLocation ReleaseLocation
private function FG takes group g, code callback returns nothing
call CatchGroup(g)
endfunction
hook ForGroupBJ FG // :D This should catch all GUI usages for groups.
hook GroupPickRandomUnit CatchGroup
hook CountUnitsInGroup CatchGroup
hook DestroyGroup ReleaseGroup
private function ASETU takes string bla, widget d, string blu returns nothing
// We can not catch THIS effect, but the effect that was created before.
// So we can destroy all SpecialEffects excpet one.
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
private function ASE takes location where, string modelName returns nothing
call CatchLocation(where)
call CatchEffect(GetLastCreatedEffectBJ())
endfunction
hook AddSpecialEffectLocBJ ASE
hook AddSpecialEffectTargetUnitBJ ASETU
hook DestroyEffect ReleaseEffect
hook DestroyEffectBJ ReleaseEffect
// When I want to make the timer run the PassMemoryLeaks things, I have to use an .execute command which requires an extra func.
function StartPassTimer takes nothing returns nothing
//call BJDebugMsg("Restarting PassTimer")
call TimerStart(PassTimer,PASS_INTERVAL,true,function PassMemoryLeaks)
endfunction
private function Init takes nothing returns nothing
set IndexData = HandleTable.create()
set IsSaved = HandleTable.create()
call StartPassTimer()
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library LocalFiles
function LF_CreateSound takes nothing returns nothing
set udg_LF_lastCreatedSound = CreateSound(udg_LF_x_Path, udg_LF_x_looping, udg_LF_x_is3D, udg_LF_x_stopwhenoutofrange, udg_LF_x_fadeInRate, udg_LF_x_fadeOutRate, udg_LF_x_eaxSetting)
call SetSoundDuration(udg_LF_lastCreatedSound, udg_LF_x_duration)
call SetSoundChannel(udg_LF_lastCreatedSound, udg_LF_x_channel)
call SetSoundVolume(udg_LF_lastCreatedSound, udg_LF_x_volume)
call SetSoundPitch(udg_LF_lastCreatedSound, udg_LF_x_pitch)
endfunction
endlibrary
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X X
X SHOCK RIFLE X
X X
X by D4RK_G4ND4LF X
X X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Credits to Champara Bros for Laser Ray model
You will have to copy
-the shock rifle ability
-the 2 custom units
-the triggers (just copy&paste the folder)
and import the BlueLaserRay model
in order to make this spell work
Remember to enable "Automatically create unknown variables while pasting trigger data"
Check under "File - Preferences - General"
It is also recommended to create the variable "i" (Integer) manually
'cause it is known to be not created automatically
Please give credits if you intend to use this spell in your map(s)
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DestructableLib initializer Initialization
//* ============================================================================ *
//* Made by PitzerMike *
//* *
//* I made this to detect if a destructable is a tree or not. It works not only *
//* for the standard trees but also for custom destructables created with the *
//* object editor. It uses a footie as a dummy with the goul's harvest ability. *
//* The dummy ids can be changed though. I also added the IsDestructableDead *
//* function for completeness. *
//* ============================================================================ *
globals
private constant integer DUMMY_UNIT_ID = 'hfoo' // footman
private constant integer HARVEST_ID = 'Ahrl' // ghouls harvest
private constant player OWNING_PLAYER = Player(15)
private unit dummy = null
endglobals
function IsDestructableDead takes destructable dest returns boolean
return GetDestructableLife(dest) <= 0.405
endfunction
function IsDestructableTree takes destructable dest returns boolean
local boolean result = false
if (dest != null) then
call PauseUnit(dummy, false)
set result = IssueTargetOrder(dummy, "harvest", dest)
call PauseUnit(dummy, true) // stops order
endif
return result
endfunction
private function Initialization takes nothing returns nothing
set dummy = CreateUnit(OWNING_PLAYER, DUMMY_UNIT_ID, 0.0, 0.0, 0.0)
call ShowUnit(dummy, false) // cannot enumerate
call UnitAddAbility(dummy, HARVEST_ID)
call UnitAddAbility(dummy, 'Aloc') // unselectable, invulnerable
call PauseUnit(dummy, true)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library RT initializer Init
globals
private trigger Trig = CreateTrigger()
private constant real RegrowTime = 20
endglobals
function RegrowTrees takes nothing returns nothing
local destructable d = GetTriggerDestructable()
call TriggerSleepAction(RegrowTime)
call DestructableRestoreLife( d, GetDestructableMaxLife(d), true )
set d=null
endfunction
function Revival takes nothing returns nothing
if IsDestructableTree(GetEnumDestructable())==true then
call TriggerRegisterDeathEvent( Trig, GetEnumDestructable() )
endif
endfunction
function Init takes nothing returns nothing
call EnumDestructablesInRect(bj_mapInitialPlayableArea,null,function Revival )
call TriggerAddAction(Trig,function RegrowTrees)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Init initializer Set
globals
private real MAP_MIN_X
private real MAP_MAX_X
private real MAP_MIN_Y
private real MAP_MAX_Y
endglobals
function IsInMapXY takes real x , real y returns boolean
return x > MAP_MIN_X and x < MAP_MAX_X and y > MAP_MIN_Y and y < MAP_MAX_Y
endfunction
private function Set takes nothing returns nothing
set MAP_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
set MAP_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
set MAP_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
set MAP_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//***************************************************************************
//*
//* SetUnitZ - By TriggerHappy187
//*
//***************************************************************************
//*
//* Installation
//* * All you need to do is copy this script into your map and you can use
//* the provided functions.
//*
//***************************************************************************
//*
//* Requirements
//* * This requires no external systems, all it requires is JassHelper.
//*
//***************************************************************************
//
// Precautions
// * If this function is used on a point with a terarin deformation
// A desync may occur.
//
//***************************************************************************
library SetUnitZ
globals
private location heightFixer = Location(0,0)
endglobals
function GetCoordZ takes real x, real y returns real
call MoveLocation(heightFixer, x, y)
return GetLocationZ(heightFixer)
endfunction
function SetUnitZ takes unit u, real h returns nothing
local location loc = GetUnitLoc(u)
local real z = GetLocationZ(loc)
call RemoveLocation(loc)
set loc = null
call SetUnitFlyHeight(u,h-z,0.)
endfunction
//function SetUnitZ takes unit whichUnit, real height, real rate returns nothing
// if GetUnitFlyHeight(whichUnit) == 0 then
// if UnitAddAbility(whichUnit, 'Arav') then
// call UnitRemoveAbility(whichUnit, 'Arav')
// endif
// endif
// //call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
// call SetUnitFlyHeight(whichUnit, height-GetCoordZ(GetUnitX(whichUnit), GetUnitY(whichUnit)), rate)
//endfunction
function GetUnitZ takes unit whichUnit returns real
call MoveLocation(heightFixer, GetUnitX(whichUnit), GetUnitY(whichUnit))
return GetUnitFlyHeight(whichUnit)+GetLocationZ(heightFixer)
endfunction
endlibrary
library GetTerrainZ
// How to Implement:
//
// by D.V.D
//
// Copy this code
// Create a trigger in your map
// Change the trigger to custom script
// Paste the code into the trigger
globals
location GL = Location(0,0)
endglobals
function GetTerrainZ takes real x, real y returns real
call MoveLocation(GL, x, y)
return GetLocationZ(GL)
endfunction
function GetTerrainZLoc takes location loc returns real
call MoveLocation(GL, GetLocationX(loc), GetLocationY(loc))
return GetLocationZ(GL)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope Grenade initializer Init
private keyword Data
globals
// Editable Globals
private constant integer GRENADE_ID = 'gdum' // Grenade unit
private constant integer GRENADE_SFX1 = 'xdum' // SFX 1
private constant integer GRENADE_SFX2 = 'xsfx' // SFX 2
private constant integer SPELL_ID = 'GAId' // Ability ID
private constant real MAX_RANGE = 1000
private constant real MIN_RANGE = 400
private constant real MAX_HEIGHT = 200
private constant attacktype AT = ATTACK_TYPE_NORMAL
private constant damagetype DT = DAMAGE_TYPE_NORMAL
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS
private constant boolean DAMAGE_SELF = true// Can it hurt player units ?
private constant boolean DAMAGE_ALLY = true// Can it hurt ally units ?
// Editable Globals
// Don't change...
private constant real PERIOD = 0.04 // Depends on what period you like ... don't moan at me if your .0001 period lags though...
private constant real SPEED = 700 * PERIOD// How fast the grenade travels per second
private Data DATA //Temp Globals
private real X //Temp Globals
private real Y //Temp Globals
private real DIST //Temp Globals
private integer COUNT = 0
private Data array GData
private timer TIMER = CreateTimer()
private location LOC = Location(0,0)
//Don't change
endglobals
private constant function AOE_Range takes integer lvl returns real
return 150 + lvl*50 *1.0
endfunction
private function MinMax takes real val,real min,real max returns real
if(min>val) then
return min
elseif(val>max) then
return max
else
return val
endif
endfunction
private function GetParabolaZ takes real x,real d,real h returns real
return 4 * h * x * (d - x) / (d * d)
endfunction // By AceHart
private function GetDamage takes integer level returns real
return GetRandomReal (400,500) + 15 * (level-1)
endfunction// I guess Flare @ TH.net helped me with this O_o...
private struct Data
unit Grenade
unit caster
player p
real x
real y
real DistCur
real DistMax
real baseH
real aoe
integer level
real cos
real sin
static group GROUP = CreateGroup()
static method Damage takes nothing returns boolean
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(u)
local Data d = DATA
local real damage = GetDamage(d.level)
local boolean dmg = false
if(DAMAGE_SELF and p==d.p)then
set dmg = true
elseif(DAMAGE_ALLY and IsPlayerAlly(p,d.p))then
set dmg = true
elseif(IsPlayerEnemy(p,d.p))then
set dmg = true
endif
if(dmg) then
call UnitDamageTarget(d.caster,u,damage,true,true,AT,DT,WT)
endif
set u = null
return false
endmethod
static method InCircle takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real x = DATA.x - GetDestructableX(d)
local real y = DATA.y - GetDestructableY(d)
local real dist = x*x+y*y
set d = null
if(dist>DATA.aoe*DATA.aoe)then// or SquareRoot(dist) > AOE_RANGE either workz...
return false
else
return true
endif
endmethod
static method TreeDestroy takes nothing returns nothing
local destructable d = GetEnumDestructable()
if IsDestructableTree(d) then
call KillDestructable(d)
endif
set d = null
endmethod
method KillTrees takes real x,real y returns nothing
local rect r = Rect(x-.aoe,y-.aoe,x+.aoe,y+.aoe)
call EnumDestructablesInRect(r,Filter(function Data.InCircle),function Data.TreeDestroy)
call RemoveRect(r)
set r = null
endmethod
method Explode takes nothing returns nothing
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX1,.x,.y,0),0,1)
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX2,.x,.y,0),0,1)
set DATA = this
call GroupEnumUnitsInRange(.GROUP,.x,.y,this.aoe,Filter(function Data.Damage))
call .KillTrees(.x,.y)
call .destroy()
endmethod
method onDestroy takes nothing returns nothing
call ShowUnit(.Grenade,false)// Don't know wether this is neccesary ?
call RemoveUnit(.Grenade)
endmethod
endstruct
private function Execute takes nothing returns nothing
local integer i = 0
local Data d
local unit u
local boolean zhit
loop
exitwhen i == COUNT
set zhit = false
set d = GData[i]
set u = d.Grenade
set d.DistCur = d.DistCur + SPEED
set d.x = d.x + SPEED * d.cos
set d.y = d.y + SPEED * d.sin
if IsInMapXY(d.x,d.y) == true then
call SetUnitX(u,d.x)
call SetUnitY(u,d.y)
call SetUnitZ(u,d.baseH+GetParabolaZ(d.DistCur,d.DistMax,MAX_HEIGHT))
call MoveLocation(LOC,d.x,d.y)
if(R2I(GetUnitZ(u))==R2I(GetLocationZ(LOC)))then
// R2I because it gives me '0.001' and stuff ... so it isn't 'equal' unit height
set zhit=true
endif
if zhit==true then
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.Explode()
else
set i = i + 1
endif
else
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]
call d.destroy()
endif
endloop
set u = null
if COUNT == 0 then
call PauseTimer(TIMER)
endif
endfunction
private function Run takes nothing returns nothing
local Data d = Data.create()
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real dist = 0
local real facing
call RemoveLocation(l)// do I need to 'set l = null' ?
set d.caster = GetTriggerUnit()
set l = GetUnitLoc(d.caster)
set d.baseH = GetLocationZ(l)
call RemoveLocation(l)
set l = null
set d.p = GetOwningPlayer(d.caster)
set d.x = GetUnitX(d.caster)
set d.y = GetUnitY(d.caster)
set d.level = GetUnitAbilityLevel(d.caster,SPELL_ID)
set d.aoe = AOE_Range(d.level)
set x = x - d.x
set y = y - d.y
set facing = Atan2(y,x)
set d.cos = Cos(facing)
set d.sin = Sin(facing)
set d.Grenade = CreateUnit(d.p,GRENADE_ID,d.x,d.y,facing)
call UnitAddAbility(d.Grenade,'Amrf')// I have to do this or else it goes buggy over raised terrain
call UnitRemoveAbility(d.Grenade,'Amrf')
set d.DistMax = MinMax(SquareRoot(x*x+y*y),MIN_RANGE,MAX_RANGE)
set d.DistCur = 0
set GData[COUNT] = d
set COUNT = COUNT + 1
if COUNT == 1 then
call TimerStart(TIMER,PERIOD,true,function Execute)
endif
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Run()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t,Condition(function Cond))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
//
// To Implement the spell
//
//
// Copy the following : UNITS
//
// Explosion -> 'xdum'
// Explosion SFX -> 'xsfx''
// Grenade -> ' gdum''
//
//
//
// Copy the following : ABILITy
//
// Grenade -> 'GAId'
//
//
// Copy the following : Triggers
//
// Regrow Trees
// IsDestructableTree
// InitLibrary
//
//
//
// You can change many of the grenades features, such as :
//
// max height , max/min range , aoe range
// damage , wether it can hurt allied or player units
//
//TESH.scrollpos=-1
//TESH.alwaysfold=0
scope BouncyGrenade initializer Init
private keyword Data
globals
// Editable Globals
private constant integer GRENADE_ID = 'gdum'
private constant integer GRENADE_SFX1 = 'xdum'
private constant integer GRENADE_SFX2 = 'xsfx'
private constant integer SPELL_ID = 'BGid'
private constant integer MAX_BOUNCES = 2// How many bounces ?
private constant real BOUNCE_DECREASE = 1.5// How much the range divises by per bounce
private constant real MAX_RANGE = 1200// max range of grenade
private constant real MIN_RANGE = 400// min range of grenade
private constant real MAX_HEIGHT = 200// maximum height reachable
private constant attacktype AT = ATTACK_TYPE_NORMAL // attack type..
private constant damagetype DT = DAMAGE_TYPE_NORMAL// damage type..
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS// Weapon type..
private constant boolean DAMAGE_SELF = true// Can it hurt player units ?
private constant boolean DAMAGE_ALLY = true// Can it hurt ally units ?
//
// Don't change...
private constant real PERIOD = 0.04 // Depends on what period you like ... don't moan at me if your .0001 period lags though...
private constant real SPEED = 700 *PERIOD // How fast the grenade travels per second
private Data DATA// Temp Globals
private real X //Temp Globals
private real Y //Temp Globals
private real DIST //Temp Globals
private integer COUNT = 0
private Data array GData
private timer TIMER = CreateTimer()
//You can now continue to the rest of the code...
endglobals
private constant function AOE_Range takes integer lvl returns real
return 150 + lvl*50 *1.0// Find AoE for Grenade explosion
endfunction
private function MinMax takes real val,real min,real max returns real
if(min>val) then
return min
elseif(val>max) then
return max
else
return val
endif
endfunction
private function GetRange takes real range returns real
return range/BOUNCE_DECREASE// devise the range
endfunction
private function GetSpeed takes real range returns real
return (range/MAX_RANGE)*SPEED*2// find speed with this 'formula'
endfunction
private function GetHeight takes real range returns real// find the max height for that bounce
return MinMax((range/MAX_RANGE)*MAX_HEIGHT*3,0,MAX_HEIGHT)
endfunction
private function GetParabolaZ takes real x,real d,real h returns real
return 4 * h * x * (d - x) / (d * d)
endfunction // By AceHart
private function GetDamage takes integer level returns real
return GetRandomReal (400,500) + 15 * (level-1)
endfunction// I guess Flare @ TH.net helped me with this O_o...
private struct Data
unit Grenade
unit caster
player p
real x
real y
real DistCur
real DistMax
real HeightMax
real heightBase
real baseH
real aoe
real facing
integer level
real speed
real cos
real sin
integer bounce
boolean justBounced
static group GROUP = CreateGroup()
static method Damage takes nothing returns boolean// To damage the targets near grenade
local unit u = GetFilterUnit()
local player p = GetOwningPlayer(u)
local Data d = DATA
local real damage = GetDamage(d.level)
local boolean dmg = false
if(DAMAGE_SELF and p==d.p)then// damage the caster's and player units ... if possible ?
set dmg = true
elseif(DAMAGE_ALLY and IsPlayerAlly(p,d.p))then// hurt allies ?
set dmg = true
elseif(IsPlayerEnemy(p,d.p))then// or just enemies...
set dmg = true
endif
if(dmg) then
call UnitDamageTarget(d.caster,u,damage,true,true,AT,DT,WT)// the damage..
endif
set u = null
return false// return false to not add to global group..
endmethod
static method InCircle takes nothing returns boolean
local destructable d = GetFilterDestructable()
local real x = DATA.x - GetDestructableX(d)
local real y = DATA.y - GetDestructableY(d)
local real dist = x*x+y*y
// Check if the destructable is in range of the grenade AoE
set d = null
if(dist>DATA.aoe*DATA.aoe)then// or SquareRoot(dist) > AOE_RANGE either workz...
return false
else
return true
endif
endmethod
static method TreeDestroy takes nothing returns nothing
local destructable d = GetEnumDestructable()
if IsDestructableTree(d) then
call KillDestructable(d)// Destroy the tree if its a tree...
endif
set d = null//nulls...
endmethod
method KillTrees takes real x,real y returns nothing
local rect r = Rect(x-.aoe,y-.aoe,x+.aoe,y+.aoe)
// find trees within a rect then find within a circle...
call EnumDestructablesInRect(r,Filter(function Data.InCircle),function Data.TreeDestroy)
call RemoveRect(r)// nulls...
set r = null
endmethod
method Explode takes nothing returns nothing
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX1,.x,.y,0),0,1)
call UnitApplyTimedLife(CreateUnit(.p,GRENADE_SFX2,.x,.y,0),0,1)// Add each SFX for a second
set DATA = this
// global data for enums ...
call GroupEnumUnitsInRange(.GROUP,.x,.y,this.aoe,Filter(function Data.Damage))
call .KillTrees(.x,.y)
call .destroy()// kill trees then destroy self..
endmethod
method onDestroy takes nothing returns nothing
call ShowUnit(.Grenade,false)// Don't know wether this is neccesary ?
call RemoveUnit(.Grenade)
endmethod
method NewBounce takes nothing returns nothing// set new data for that bounce
local location l = GetUnitLoc(.Grenade)
set .bounce = .bounce + 1// increase bounce
set .DistMax = .DistCur/BOUNCE_DECREASE// find the distmax from the distance traveled / decrement
set .DistCur = 0// reset dist traveled
set .HeightMax = GetHeight(.DistMax)// formula for height
set .speed = GetSpeed(.DistMax)// find the speed for new bounce
set .baseH = GetLocationZ(l)//find 'this' bounce height again..
call RemoveLocation(l)// leaks
set l = null
endmethod
endstruct
private function Execute takes nothing returns nothing
local integer i = 0
local Data d
local unit u
local boolean zhit // Z - Hit if anyone has a weird font like me which looks like an s ...
local location l = Location(0,0)
loop
exitwhen i == COUNT
set zhit = false
set d = GData[i]
set u = d.Grenade
set d.DistCur = d.DistCur + d.speed
set d.x = d.x + d.speed * d.cos// moving data...
set d.y = d.y + d.speed * d.sin
if IsInMapXY(d.x,d.y) == true then// grenade in map
call SetUnitX(u,d.x)
call SetUnitY(u,d.y)// move the grenade
call SetUnitZ(u,d.baseH+GetParabolaZ(d.DistCur,d.DistMax,d.HeightMax))
// set unit Z
call MoveLocation(l,d.x,d.y)
if(R2I(GetUnitZ(u))==R2I(GetLocationZ(l)))then
// R2I because it gives me '0.001' and stuff ... so it isn't 'equal' unit height
set zhit=true
endif
// I dont think the dist current can go higher than the max... but just in case
if zhit==true then
if d.bounce==2 then
set COUNT = COUNT - 1
set GData[i] = GData[COUNT]// next instance
call d.Explode()
else
call d.NewBounce()// new bounce because of zhit
endif
else
set i = i + 1// just increase the value to the next instance
endif
else
set COUNT = COUNT - 1// change to next instance
set GData[i] = GData[COUNT]
call d.destroy()
endif
endloop
call RemoveLocation(l)
set u = null// leaks
set l = null
if COUNT == 0 then
call PauseTimer(TIMER)// pause
endif
endfunction
private function Run takes nothing returns nothing
local Data d = Data.create()
local location l = GetSpellTargetLoc()
local real x = GetLocationX(l)
local real y = GetLocationY(l)
local real dist = 0// locals for data
local real facing
call RemoveLocation(l)// do I need to 'set l = null' ?
set d.caster = GetTriggerUnit()
set l = GetUnitLoc(d.caster)
set d.baseH = GetLocationZ(l)
call RemoveLocation(l)
set l = null// leaks
set d.caster = GetTriggerUnit()
set d.p = GetOwningPlayer(d.caster)
set d.x = GetUnitX(d.caster)// caster data
set d.y = GetUnitY(d.caster)
set d.level = GetUnitAbilityLevel(d.caster,SPELL_ID)
set d.aoe = AOE_Range(d.level)
set d.bounce = 0
set x = x - d.x
set y = y - d.y
set facing = Atan2(y,x)
set d.cos = Cos(facing)
set d.sin = Sin(facing)// facing,,,
set d.Grenade = CreateUnit(d.p,GRENADE_ID,d.x,d.y,facing)
call UnitAddAbility(d.Grenade,'Amrf')// I have to do this or else it goes buggy over raised terrain
call UnitRemoveAbility(d.Grenade,'Amrf')
set d.DistMax = MinMax(SquareRoot(x*x+y*y)/Pow(BOUNCE_DECREASE,MAX_BOUNCES),0,MAX_RANGE)
set d.HeightMax = GetHeight(d.DistMax)// height, dist , speed data
set d.speed = GetSpeed(d.DistMax)
//MinMax(SquareRoot(x*x+y*y),MIN_RANGE,MAX_RANGE)
set d.DistCur = 0
set GData[COUNT] = d
set COUNT = COUNT + 1
if COUNT == 1 then
call TimerStart(TIMER,PERIOD,true,function Execute)
endif
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SPELL_ID then
call Run()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t,Condition(function Cond))
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//
//
// To Implement the spell
//
//
// Copy the following : UNITS
//
// Explosion -> 'xdum'
// Explosion SFX -> 'xsfx''
// Grenade -> ' gdum''
//
//
//
// Copy the following : ABILITy
//
// Grenade -> 'BGid'
//
//
// Copy the following : Triggers
//
// Regrow Trees
// IsDestructableTree
// InitLibrary
//
//
// You can change many of the grenades features, such as :
//
// max height , max/min range , aoe range
// damage , wether it can hurt allied or player units
// max bounces , how far each bounce ... bounces
//
// I tried to make the formulas even as if they were a real grenade...
// slowing down , not bouncing as high , and traveling less distance