//=========================================================================== // // Caster System 14.3 // // Warcraft III map script // Generated by the Warcraft III World Editor // Date: Tue Aug 21 00:23:04 2007 // Map Author: Vexorian // //=========================================================================== //*************************************************************************** //* //* Global Variables //* //*************************************************************************** globals // User-defined unit udg_UnitVar = null location udg_PointVar = null real udg_RealVar = 0 real udg_RealVar2 = 0 location udg_PointVar2 = null group udg_GroupVar = null unit udg_UnitVar2 = null integer udg_IntegerVar = 0 integer udg_DamageOptions = 0 integer udg_hash = 0 string udg_hasht timer udg_crono = null integer udg_oho = 0 unit udg_tUnit = null // Generated rect gg_rct_sheep_invasion = null trigger gg_trg_Readme = null trigger gg_trg_Version_History = null trigger gg_trg_CSCache = null trigger gg_trg_CSSafety = null trigger gg_trg_CasterSystem = null trigger gg_trg_Casting_Functions = null trigger gg_trg_Damage_and_Projectiles = null trigger gg_trg_Collision_Missiles = null trigger gg_trg_Damagers_and_DamagerGroups = null trigger gg_trg_Damage_and_Target_Options = null trigger gg_trg_CSCache_Module = null trigger gg_trg_Spell_Events_Module = null trigger gg_trg_Spell_Helpers = null trigger gg_trg_Safe_item_hiding = null trigger gg_trg_Rune_of_Illusions = null trigger gg_trg_Scroll_of_Rejuvenation = null trigger gg_trg_Levelable_Mass_Slow = null trigger gg_trg_Cripple_Everything = null trigger gg_trg_Muradins_Hammer = null trigger gg_trg_Thors_Hammer = null trigger gg_trg_Grenade = null trigger gg_trg_Nova = null trigger gg_trg_Poisonous_Weeds = null trigger gg_trg_Green_Fire_Balls = null trigger gg_trg_Stone_of_Ligthning = null trigger gg_trg_Queltallas_Revenge = null trigger gg_trg_IceWave = null trigger gg_trg_Inferno = null trigger gg_trg_Pools_demo = null trigger gg_trg_Abilities_Preload = null trigger gg_trg_Rune_of_Bloodlust = null trigger gg_trg_Sheep_Staff = null trigger gg_trg_Fire_Wall = null trigger gg_trg_SpellDemoMap = null trigger gg_trg_Number_of_Casters_Check_Debug = null // Random Groups integer array gg_rg_000 integer array gg_rg_001 integer array gg_rg_002 endglobals function InitGlobals takes nothing returns nothing set udg_RealVar = 0 set udg_RealVar2 = 0 set udg_GroupVar = CreateGroup() set udg_IntegerVar = 0 set udg_DamageOptions = 0 set udg_hash = 0 set udg_hasht = "" set udg_crono = CreateTimer() set udg_oho = 0 endfunction //*************************************************************************** //* //* Random Groups //* //*************************************************************************** function InitRandomGroups takes nothing returns nothing local integer curset // Group 0 - Powerful Creeps call RandomDistReset( ) call RandomDistAddItem( 0, 34 ) call RandomDistAddItem( 1, 33 ) call RandomDistAddItem( 2, 33 ) set curset = RandomDistChoose( ) if (curset == 0) then set gg_rg_000[0] = 'nelb' elseif (curset == 1) then set gg_rg_000[0] = 'nbld' elseif (curset == 2) then set gg_rg_000[0] = 'nwzd' else set gg_rg_000[0] = -1 endif // Group 1 - less Powerful Creep call RandomDistReset( ) call RandomDistAddItem( 0, 34 ) call RandomDistAddItem( 1, 33 ) call RandomDistAddItem( 2, 33 ) set curset = RandomDistChoose( ) if (curset == 0) then set gg_rg_001[0] = 'nele' elseif (curset == 1) then set gg_rg_001[0] = 'nenf' elseif (curset == 2) then set gg_rg_001[0] = 'nwzg' else set gg_rg_001[0] = -1 endif // Group 2 - Weak Creeps call RandomDistReset( ) call RandomDistAddItem( 0, 25 ) call RandomDistAddItem( 1, 25 ) call RandomDistAddItem( 2, 25 ) call RandomDistAddItem( 3, 25 ) set curset = RandomDistChoose( ) if (curset == 0) then set gg_rg_002[0] = 'nban' elseif (curset == 1) then set gg_rg_002[0] = 'nbrg' elseif (curset == 2) then set gg_rg_002[0] = 'nwiz' elseif (curset == 3) then set gg_rg_002[0] = 'nwzr' else set gg_rg_002[0] = -1 endif endfunction //*************************************************************************** //* //* Map Item Tables //* //*************************************************************************** function ItemTable000000_DropItems takes nothing returns nothing local widget trigWidget = null local unit trigUnit = null local integer itemID = 0 local boolean canDrop = true set trigWidget = bj_lastDyingWidget if (trigWidget == null) then set trigUnit = GetTriggerUnit() endif if (trigUnit != null) then set canDrop = not IsUnitHidden(trigUnit) if (canDrop and GetChangingUnit() != null) then set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE)) endif endif if (canDrop) then // Item set 0 call RandomDistReset( ) call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_PERMANENT, -1 ), 30 ) call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, -1 ), 70 ) set itemID = RandomDistChoose( ) if (trigUnit != null) then call UnitDropItem( trigUnit, itemID ) else call WidgetDropItem( trigWidget, itemID ) endif endif set bj_lastDyingWidget = null call DestroyTrigger(GetTriggeringTrigger()) endfunction function ItemTable000001_DropItems takes nothing returns nothing local widget trigWidget = null local unit trigUnit = null local integer itemID = 0 local boolean canDrop = true set trigWidget = bj_lastDyingWidget if (trigWidget == null) then set trigUnit = GetTriggerUnit() endif if (trigUnit != null) then set canDrop = not IsUnitHidden(trigUnit) if (canDrop and GetChangingUnit() != null) then set canDrop = (GetChangingUnitPrevOwner() == Player(PLAYER_NEUTRAL_AGGRESSIVE)) endif endif if (canDrop) then // Item set 0 call RandomDistReset( ) call RandomDistAddItem( ChooseRandomItemEx( ITEM_TYPE_CHARGED, 8 ), 100 ) set itemID = RandomDistChoose( ) if (trigUnit != null) then call UnitDropItem( trigUnit, itemID ) else call WidgetDropItem( trigWidget, itemID ) endif endif set bj_lastDyingWidget = null call DestroyTrigger(GetTriggeringTrigger()) endfunction //*************************************************************************** //* //* Items //* //*************************************************************************** function CreateAllItems takes nothing returns nothing local integer itemID call CreateItem( 'I001', -1565.7, -17.9 ) call CreateItem( 'I002', -2013.5, -28.9 ) call CreateItem( 'I003', -1481.1, 152.9 ) call CreateItem( 'I004', -1407.0, -250.4 ) call CreateItem( 'I005', -1915.2, -28.9 ) call CreateItem( 'I006', -1795.0, -23.6 ) call CreateItem( 'I007', -1572.9, 140.1 ) call CreateItem( 'I008', -1661.3, 128.1 ) call CreateItem( 'I00A', -1460.9, -4.8 ) call CreateItem( 'I00B', -1757.0, 119.1 ) call CreateItem( 'I00C', -1824.4, 105.5 ) call CreateItem( 'I00D', -1911.6, 99.0 ) call CreateItem( 'I00E', -1387.6, -153.9 ) call CreateItem( 'lgdh', -2063.2, 444.7 ) endfunction //*************************************************************************** //* //* Unit Creation //* //*************************************************************************** //=========================================================================== function CreateUnitsForPlayer0 takes nothing returns nothing local player p = Player(0) local unit u local integer unitID local trigger t local real life set u = CreateUnit( p, 'Hblm', -2066.5, -176.8, 272.470 ) call SetHeroLevel( u, 6, false ) call SelectHeroSkill( u, 'A00N' ) call IssueImmediateOrder( u, "" ) call SelectHeroSkill( u, 'AHbn' ) call SelectHeroSkill( u, 'A00J' ) call IssueImmediateOrder( u, "" ) call SelectHeroSkill( u, 'A00H' ) call IssueImmediateOrder( u, "" ) call SelectHeroSkill( u, 'A00Z' ) call IssueImmediateOrder( u, "" ) endfunction //=========================================================================== function CreateNeutralHostile takes nothing returns nothing local player p = Player(PLAYER_NEUTRAL_AGGRESSIVE) local unit u local integer unitID local trigger t local real life set u = CreateUnit( p, 'nrvl', -2452.9, 2606.4, 258.709 ) set u = CreateUnit( p, 'nfgl', -5266.6, 439.8, 291.113 ) set u = CreateUnit( p, 'efon', -3826.4, -170.3, 129.181 ) set u = CreateUnit( p, 'efon', -3860.5, -282.5, 56.548 ) set u = CreateUnit( p, 'efon', -3718.1, -316.4, 212.625 ) set u = CreateUnit( p, 'efon', -3959.8, -337.5, 136.224 ) set u = CreateUnit( p, 'nepl', -5457.7, -999.8, 57.592 ) set u = CreateUnit( p, 'nenp', -5674.7, -1032.2, 14.964 ) set u = CreateUnit( p, 'nrvs', -2369.8, -1925.1, 68.202 ) set u = CreateUnit( p, 'nrvs', -2169.1, -1787.7, 153.817 ) set u = CreateUnit( p, 'nsrv', -86.6, -2832.3, 22.786 ) set u = CreateUnit( p, 'nsrv', -295.9, -3009.1, 47.517 ) set u = CreateUnit( p, 'nsel', 650.1, -1902.7, 51.604 ) set u = CreateUnit( p, 'nrel', 798.2, -2110.9, 25.665 ) set u = CreateUnit( p, 'nrel', 394.9, -1992.9, 357.847 ) set u = CreateUnit( p, 'ndrv', -46.9, -3034.0, 248.584 ) set u = CreateUnit( p, 'nadw', 576.2, -3787.7, 333.852 ) set u = CreateUnit( p, 'nadw', 816.8, -3610.5, 319.371 ) set u = CreateUnit( p, 'nadk', 739.5, -3787.7, 260.867 ) set u = CreateUnit( p, 'nrvi', -2078.3, -2031.5, 177.632 ) set u = CreateUnit( p, 'Nfir', 1660.6, 850.8, 276.060 ) call SetHeroLevel( u, 13, false ) call SetUnitState( u, UNIT_STATE_MANA, 720 ) call SelectHeroSkill( u, 'ANso' ) call SelectHeroSkill( u, 'ANso' ) call SelectHeroSkill( u, 'ANso' ) call SelectHeroSkill( u, 'ANlm' ) call SelectHeroSkill( u, 'ANlm' ) call SelectHeroSkill( u, 'ANlm' ) call SelectHeroSkill( u, 'ANia' ) call SelectHeroSkill( u, 'ANia' ) call SelectHeroSkill( u, 'ANia' ) call IssueImmediateOrder( u, "incineratearrowon" ) call SelectHeroSkill( u, 'ANvc' ) call SelectHeroSkill( u, 'AHfs' ) call SelectHeroSkill( u, 'AHfs' ) call SelectHeroSkill( u, 'AHfs' ) call UnitAddItemToSlotById( u, 'modt', 0 ) call UnitAddItemToSlotById( u, 'pghe', 1 ) call UnitAddItemToSlotById( u, 'rlif', 2 ) call UnitAddItemToSlotById( u, 'pgin', 3 ) call UnitAddItemToSlotById( u, 'I00F', 4 ) call UnitAddItemToSlotById( u, 'pgma', 5 ) set u = CreateUnit( p, 'hphx', 1763.5, -1673.8, 236.710 ) set u = CreateUnit( p, 'nslr', 1519.3, 3119.3, 81.158 ) set u = CreateUnit( p, 'nrvf', 145.3, 1548.7, 40.497 ) set u = CreateUnit( p, 'nrvf', 89.4, 1367.2, 346.662 ) set u = CreateUnit( p, 'nrvf', 32.0, 1181.1, 110.075 ) set u = CreateUnit( p, 'nsll', 1269.9, 3175.1, 71.249 ) set u = CreateUnit( p, 'nslr', 1147.2, 3407.7, 351.716 ) set u = CreateUnit( p, 'hphx', 1602.5, -1406.7, 236.710 ) set u = CreateUnit( p, 'n000', 2011.7, -566.9, 86.894 ) set u = CreateUnit( p, 'n000', 1766.0, -270.6, 251.507 ) set u = CreateUnit( p, 'n000', 1958.7, 187.8, 249.002 ) set u = CreateUnit( p, 'n000', 1604.5, -30.0, 208.516 ) set u = CreateUnit( p, 'n000', 1356.6, 200.9, 69.546 ) set u = CreateUnit( p, 'n000', 1104.0, 231.8, 297.859 ) set u = CreateUnit( p, 'n000', 1135.3, 82.3, 66.810 ) set u = CreateUnit( p, 'n000', 1686.5, 310.3, 37.970 ) set u = CreateUnit( p, 'n000', 1678.1, 227.4, 89.948 ) set u = CreateUnit( p, 'n000', 1632.0, 177.1, 153.209 ) set u = CreateUnit( p, 'n000', 1446.4, 345.6, 91.365 ) set u = CreateUnit( p, 'n000', 1254.6, 522.5, 212.010 ) set u = CreateUnit( p, 'n000', 1204.0, 590.2, 130.873 ) set u = CreateUnit( p, 'n000', 1319.6, 901.6, 300.870 ) set u = CreateUnit( p, 'n000', 1318.7, 981.4, 274.348 ) set u = CreateUnit( p, 'n000', 1327.7, 1064.1, 252.243 ) set u = CreateUnit( p, 'n000', 1385.0, 1432.3, 261.351 ) set u = CreateUnit( p, 'n000', 1538.3, 1578.2, 338.213 ) set u = CreateUnit( p, 'n000', 1740.0, 1585.0, 281.962 ) set u = CreateUnit( p, 'n000', 1772.3, 1340.5, 115.646 ) set u = CreateUnit( p, 'n000', 1783.9, 1210.8, 120.963 ) set u = CreateUnit( p, 'n000', 1890.0, 1254.7, 243.508 ) set u = CreateUnit( p, 'n000', 1900.2, 1364.0, 332.401 ) set u = CreateUnit( p, 'n000', 1177.3, 1135.9, 341.169 ) set u = CreateUnit( p, 'n000', 1365.8, 1237.9, 122.523 ) set u = CreateUnit( p, 'n000', 1553.3, 1383.0, 97.001 ) set u = CreateUnit( p, 'n000', 870.8, 830.1, 274.106 ) set u = CreateUnit( p, 'n000', 1010.5, 360.2, 225.205 ) set u = CreateUnit( p, 'n002', -1077.2, 3323.0, 236.177 ) set u = CreateUnit( p, 'nbzd', -3918.9, 3357.1, 239.516 ) set u = CreateUnit( p, 'nbzk', -4840.4, 2687.4, 132.356 ) set u = CreateUnit( p, 'nbzk', -5038.0, 2502.0, 32.081 ) set u = CreateUnit( p, 'nthl', -4798.1, 2538.8, 196.057 ) set u = CreateUnit( p, 'nstw', -1321.5, 1522.1, 105.450 ) set u = CreateUnit( p, 'h000', -2045.1, -3114.1, 1.000 ) set u = CreateUnit( p, 'n000', 1828.5, 1888.9, 172.139 ) set u = CreateUnit( p, 'n000', 922.8, 1308.2, 224.567 ) set u = CreateUnit( p, 'n000', 1432.7, 1866.7, 16.557 ) set u = CreateUnit( p, 'n000', 1567.5, 1899.7, 15.118 ) set u = CreateUnit( p, 'n000', 1141.7, 1758.9, 342.652 ) set u = CreateUnit( p, 'nrvl', -2295.8, 2267.9, 184.748 ) endfunction //=========================================================================== function CreateNeutralPassiveBuildings takes nothing returns nothing local player p = Player(PLAYER_NEUTRAL_PASSIVE) local unit u local integer unitID local trigger t local real life set u = CreateUnit( p, 'ncp3', -4416.0, -3072.0, 270.000 ) endfunction //=========================================================================== function CreateNeutralPassive takes nothing returns nothing local player p = Player(PLAYER_NEUTRAL_PASSIVE) local unit u local integer unitID local trigger t local real life set u = CreateUnit( p, 'n000', 2025.6, 834.7, 288.213 ) endfunction //=========================================================================== function CreatePlayerBuildings takes nothing returns nothing endfunction //=========================================================================== function CreatePlayerUnits takes nothing returns nothing call CreateUnitsForPlayer0( ) endfunction //=========================================================================== function CreateAllUnits takes nothing returns nothing call CreateNeutralPassiveBuildings( ) call CreatePlayerBuildings( ) call CreateNeutralHostile( ) call CreateNeutralPassive( ) call CreatePlayerUnits( ) endfunction //*************************************************************************** //* //* Regions //* //*************************************************************************** function CreateRegions takes nothing returns nothing local weathereffect we set gg_rct_sheep_invasion = Rect( -4608.0, -3264.0, -4224.0, -2880.0 ) endfunction //*************************************************************************** //* //* Triggers //* //*************************************************************************** //=========================================================================== // Trigger: CSCache //=========================================================================== library CSCache initializer InitCSCache //*************************************************************************** //* * //* CSCache 14.3 http://wc3campaigns.net/vexorian * //* ¯¯¯¯¯¯¯ * //* From attach variables to Dynamic Arrays, not forgetting the tables, * //* CSData and the Pools, this is a pack of storage options * //* * //*************************************************************************** //================================================================================================= // CSCache globals: // globals gamecache cs_cache = null integer array cs_array1 integer array cs_array3 integer array cs_array2 integer array cs_freeindexes integer array cs_pairx integer array cs_pairy integer array cs_freepairs gamecache udg_cscache = null //udg_ for compat! endglobals //================================================================================================= // Note: //! define macro commands are used accross the script, they are usually to be parsed by // WEHelper, no //! define parser is really required, but if present it would improve the // performance of some calls. // //================================================================================================= // a.k.a H2I, changed name to CS_H2I to prevent conflicts with other systems (I intended this // system to be easy to copy // function CS_H2I takes handle h returns integer return h return 0 endfunction //================================================================================================== // Bunch of other return bug exploiters // function CS_i2r takes integer i returns real return i return 0. endfunction function CS_h2r takes handle h returns real return h return 0. endfunction function CS_r2i takes real r returns integer return r return 0 endfunction function CS_lx takes location l returns location return GetLocationX(l) return null endfunction function CS_ly takes location l returns location return GetLocationY(l) return null endfunction function CS_i2l takes integer l returns location return l return null endfunction //================================================================================================== // location linked list kit // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // Thanks: Pipedream | No thanks: Blizzard (for lame bug) // // It is a great irony, but locations are only useful when you don't use them as points but as // structs thanks to the return bug. They only allow 2 values so they are limited in comparission // to gamecache and arrays (see bellow) still useful for single linked lists. // // These functions are what I call enough to use locations as single list nodes, X holds values and // Y can just hold a location (or real) . The Get functions use bj globals to fix an odd operator // bug that can happen after converting pointer to real into pointer to integer. // // The Set functions can be replaced by the Location() constructor, the MoveLocation() native and // the return bug exploiters up there. // //=================================================================================================== // Constructors // function Location_IntLoc takes integer x , location y returns location return Location(CS_i2r(x),CS_h2r(y)) endfunction //! define Location_IntLoc(x,y) Location(CS_i2r(x),CS_h2r(y)) function Location_ObjectLoc takes handle x , location y returns location return Location(CS_h2r(x),CS_h2r(y)) endfunction //! define Location_ObjectLoc(x,y) Location(CS_h2r(x),CS_h2r(y)) function Location_LocLoc takes handle x , location y returns location return Location(CS_h2r(x),CS_h2r(y)) endfunction //! define Location_LocLoc(x,y) Location(CS_h2r(x),CS_h2r(y)) function Location_RealLoc takes real x , location y returns location return Location(x,CS_h2r(y)) endfunction //! define Location_RealLoc(x,y) Location(x,CS_h2r(y)) //==================================================================================================== // Combined assigments // function SetLocation_IntLoc takes location loc, integer x , location y returns nothing call MoveLocation(loc,CS_i2r(x),CS_h2r(y)) endfunction //! define SetLocation_IntLoc(loc,x,y) MoveLocation(loc,CS_i2r(x),CS_h2r(y)) function SetLocation_ObjectLoc takes location loc, handle x , location y returns nothing call MoveLocation(loc,CS_h2r(x),CS_h2r(y)) endfunction //! define SetLocation_ObjectLoc(loc,x,y) MoveLocation(loc,CS_h2r(x),CS_h2r(y)) function SetLocation_LocLoc takes location loc, handle x , location y returns nothing //Funny name call MoveLocation(loc,CS_h2r(x),CS_h2r(y)) endfunction //! define SetLocation_LocLoc(loc,x,y) MoveLocation(loc,CS_h2r(x),CS_h2r(y)) function SetLocation_RealLoc takes location loc, real x , location y returns nothing call MoveLocation(loc,x,CS_h2r(y)) endfunction //! define SetLocation_RealLoc(loc,x,y) MoveLocation(loc,x,CS_h2r(y)) //=================================================================================================== // Lack of SetLocationX / SetLocationY natives is kind of lame // function SetLocationX_Object takes location loc, handle val returns nothing call MoveLocation(loc,CS_h2r(val),GetLocationY(loc)) endfunction // Notice how define SetLocationX_Object(loc,v) MoveLocation(loc,CS_h2r(v),GetLocationY(loc)) // would have a chance of messing sometimes since it has 2 loc in the result. function SetLocationX_Loc takes location loc, location val returns nothing //just name candy call MoveLocation(loc,CS_h2r(val),GetLocationY(loc)) endfunction function SetLocationX_Real takes location loc, real val returns nothing call MoveLocation(loc,val,GetLocationY(loc)) endfunction function SetLocationX_Int takes location loc, integer val returns nothing call MoveLocation(loc,CS_i2r(val),GetLocationY(loc)) endfunction function SetLocationY_Loc takes location loc, location val returns nothing call MoveLocation(loc,GetLocationX(loc),CS_h2r(val)) endfunction //================================================================================================== // All right, crazyness that started with Attacheable variables, and had to continue with everything // from tables, arrays and now this. Sorry I can't help itç // // The good thing about these functions is that they are safe, you won't deal with real->(int/handle) // conversion related bugs thanks to the use of bj variables these functions do // function GetLocationX_Loc takes location loc returns location set bj_enumDestructableCenter=CS_lx(loc) return bj_enumDestructableCenter endfunction function GetLocationY_Loc takes location loc returns location set bj_enumDestructableCenter=CS_ly(loc) return bj_enumDestructableCenter endfunction function GetLocationX_Int takes location loc returns integer set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex endfunction function GetLocationX_Unit takes location loc returns unit set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Item takes location loc returns item set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Effect takes location loc returns effect set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Lightning takes location loc returns lightning set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Widget takes location loc returns widget set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Object takes location loc returns handle set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Rect takes location loc returns rect set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Region takes location loc returns region set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_TimerDialog takes location loc returns timerdialog set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Destructable takes location loc returns destructable set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Trigger takes location loc returns trigger set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Timer takes location loc returns timer set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Group takes location loc returns group set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_TriggerAction takes location loc returns triggeraction set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Image takes location loc returns image set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Ubersplat takes location loc returns ubersplat set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction function GetLocationX_Sound takes location loc returns sound set bj_forLoopAIndex=CS_r2i(GetLocationX(loc)) return bj_forLoopAIndex return null endfunction // //That should be all we needed to abuse Locations, Love lists. // // CSCache initializer : function InitCSCache takes nothing returns nothing call FlushGameCache(InitGameCache("cscache")) set cs_cache=InitGameCache("cscache") set udg_cscache = cs_cache call ExecuteFunc("InitArrayIndexes") call ExecuteFunc("Pool_SetupCharMap") endfunction //================================================================================================== // CSData // ¯¯¯¯¯¯ // CSDatas are like UserData in units and items, they are faster than gamecache unless you have more // than 8191 handles in your map. In that case it would be a little slower but only for those // handles. And if you have more than 8191 handles your map is too slow already anyways. // // Notice that for public spells or systems to be distributed you should only use these // for private objects (those who the mapper would never have access to) If you are making something // for your map you can use them wherever you want. // // Best to be used in conjunction to CSArrays so you just specify an array id for a handle. // // DO NOT USE THIS ON THESE HANDLE TYPES: -lightning, -ubersplat, -image, -texttag, // -any 'argument' handle (like playerstate, damagetype, etc) // function SetCSData takes handle h, integer v returns nothing local integer i=CS_H2I(h)-0x100000 if (i>=8191) then call StoreInteger(cs_cache,"csdata",I2S(i),v) else set cs_array3[i]=v endif endfunction function GetCSData takes handle h returns integer local integer i=CS_H2I(h)-0x100000 if (i>=8191) then //can't use Get without Set return GetStoredInteger(cs_cache,"csdata",I2S(i)) endif return cs_array3[i] endfunction //================================================================================================================= // CS Pairs // ¯¯¯¯¯¯¯¯ // This is a sub system to assist csarrays, you can use them but CSArrays of size 2 have the same functionality // although cspairs are be faster their space is limited and will start using gamecache if abused // function NewPair takes integer x, integer y returns integer local integer i if (cs_freepairs[0]==0) then set cs_freepairs[8190]=cs_freepairs[8190]+1 set i= cs_freepairs[8190] else set i= cs_freepairs[cs_freepairs[0]] set cs_freepairs[0]=cs_freepairs[0]-1 endif if (i>=8189) then //because we can only recycle up to 8189 (free pairs array uses indexes 0 and 8190 for other purposes) call StoreInteger(cs_cache,"pairx",I2S(i),x) call StoreInteger(cs_cache,"pairy",I2S(i),y) else set cs_pairx[i]=x set cs_pairy[i]=y endif return i endfunction function DestroyPair takes integer id returns nothing if (id>=8189) then call FlushStoredInteger(cs_cache,"pairx",I2S(id)) call FlushStoredInteger(cs_cache,"pairy",I2S(id)) else set cs_freepairs[0]=cs_freepairs[0]+1 set cs_freepairs[cs_freepairs[0]] = id endif endfunction function SetPairXY takes integer id, integer x, integer y returns nothing if (id>=8189) then call StoreInteger(cs_cache,"pairx",I2S(id),x) call StoreInteger(cs_cache,"pairy",I2S(id),y) else set cs_pairx[id]=x set cs_pairy[id]=y endif endfunction function SetPairX takes integer id, integer x returns nothing if (id>=8189) then call StoreInteger(cs_cache,"pairx",I2S(id),x) else set cs_pairx[id]=x endif endfunction function SetPairY takes integer id, integer y returns nothing if (id>=8189) then call StoreInteger(cs_cache,"pairy",I2S(id),y) else set cs_pairy[id]=y endif endfunction function GetPairX takes integer id returns integer if (id>=8189) then return GetStoredInteger(cs_cache,"pairy",I2S(id)) endif return cs_pairx[id] endfunction function GetPairY takes integer id returns integer if (id>=8189) then return GetStoredInteger(cs_cache,"pairx",I2S(id)) endif return cs_pairy[id] endfunction //================================================================================================================= // CS Dynamic Arrays // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // Thanks: Pipedream, Peppar // // We can now create arrays in game! , also pass them as arguments or return values! // a 1 length array is a pointer! // function Array_TryFree takes nothing returns nothing local integer i local integer N=cs_array1[0] local integer k local boolean cleaned=false local integer loc local integer q local integer r set i=cs_array1[146] if (i>144) then call TimerStart(GetExpiredTimer(),60.,false,function Array_TryFree) return endif set loc=cs_freeindexes[i] set q=0 loop exitwhen (loc==0) // we could just have used: //set k=GetPairX(loc) //set r=GetPairY(loc) But it is slower than direct usage: if (loc>=8192) then set k=GetStoredInteger(cs_cache,"pairx",I2S(loc)) set r=GetStoredInteger(cs_cache,"pairy",I2S(loc)) else set k=cs_pairx[loc] set r=cs_pairy[loc] endif if (k+i-1==N) then //we found one we can remove from the list set cleaned=true //decrement N set N=k-2 //Remove from the list: if (q==null) then //That was the first, update the array as well set cs_freeindexes[i]=r else //Update the next of the previous one //We could use : call SetPairY(q,,r) but it is slower if (q>=8189) then call StoreInteger(cs_cache,"pairy",I2S(q),r) else set cs_pairy[q]=r endif endif if (r==null) then //This was the last one, update it in the array as well set cs_freeindexes[i+4096]=q endif call DestroyPair(loc) set loc=q endif set q=loc set loc=r endloop if (cleaned) then set cs_array1[0]=N set cs_array1[146]=1 else set cs_array1[146]=cs_array1[i+1] endif call TimerStart(GetExpiredTimer(),0.2,false,function Array_TryFree) endfunction function InitArrayIndexes2 takes nothing returns nothing local integer i=0 loop exitwhen (i==8191) set cs_pairx[i]=777 set cs_pairy[i]=777 set i=i+1 endloop endfunction function InitArrayIndexes takes nothing returns nothing local integer i=0 local integer a=1 local integer b=1 local integer c //By placing 777 there instead of 0 it is easier to recognize non correctly initialized bugs loop exitwhen (i== 8191) set cs_array1[i]=777 set cs_array2[i]=777 set cs_array3[i]=777 //set cs_pairx[i]=777 //set cs_pairy[i]=777 set i=i+1 endloop call ExecuteFunc("InitArrayIndexes2") set cs_freeindexes[0]=0 //The stack for the table indexes. set cs_freepairs[0]=0 set cs_freepairs[8190]=0 set i=1 loop set c=a+b set a=b set b=c exitwhen (b>144) //max size is 144 set cs_freeindexes[b]=0 //the first of the list set cs_freeindexes[b+4096]=0 //the last of the list loop exitwhen (i>b) set cs_array1[i]=b set i=i+1 endloop endloop set cs_array1[i]=b //i is 145 set cs_array1[146]=1 set cs_array1[147]=101 //initial table index is 101 set cs_array1[0]=147 //index 0: Last used index // 1 to 145 : Fibonacci sequence // 146 : last check // 147 : Table indexes check //This has a good chance to compress the thing when necesary call TimerStart(CreateTimer(),60.,false,function Array_TryFree) endfunction //============================================================================================= // Create an array of size, max size is 144, if doinit is true it will put a bunch of zeros // in the indexes // function NewArray takes integer size, boolean doinit returns integer local integer i local integer rsize=cs_array1[size] local integer loc set loc=cs_freeindexes[rsize] if (loc!=0) then set cs_freeindexes[rsize]= GetPairY(loc) if (cs_freeindexes[rsize]==0) then set cs_freeindexes[4096+rsize]=0 endif set i=GetPairX(loc) call DestroyPair(loc) if (i==0) then //this code was probably a good idea when we used locations for the free indexes list, now we use pairs which should not ever //do this unless someone modiffied the pair array incorrectly call BJDebugMsg("Caster System: Unexpected error (5): corrupt stack, attempt to recover "+I2S(rsize)) // recovering involves forgetting about the stack which got corrupted and start again from zero, it will leak // and probably get slow due to usage of gamecache but it is better than the problems that a corrupt stack might cause set cs_freeindexes[rsize]=0 set cs_freeindexes[4096+rsize]=0 return NewArray(size,doinit) endif else //sz i i+1 i+2 //[ ][ ][ ][ ] set i=cs_array1[0]+2 set cs_array1[0]=i+rsize-1 endif //It used to store size in the index equal to the array's id // but that required the get/set functions to increment 1 in every index // calculation. Instead, making size the previous index to the array works if (i<=8191) then set cs_array1[i-1]=size elseif (i<=16382) then set cs_array2[i-8192]=size else call StoreInteger(cs_cache,I2S(-i),"size",size) endif if (not doinit) then return i endif // 3 //[i][i+1][i+2] set size=i+size-1 if (size>=16382) then set size=16381 endif loop exitwhen (size16382) then if (lstpace==cs_array1[0]) then //We just destroyed the array that happens to be at the end of the heap. //Just get it back set cs_array1[0]=id-2 set cs_array1[146]=1 else //Add to the last set loc=cs_freeindexes[L+4096] if (loc==0) then set loc=NewPair(id,0) set cs_freeindexes[L]=loc set cs_freeindexes[L+4096]=loc else set cs_freeindexes[L+4096]= NewPair(id,0) //we could just use: call SetPairY(loc, cs_freeindexes[L+4096] ) //but that's slower if (loc>=8189) then call StoreInteger(cs_cache,"pairy",I2S(loc), cs_freeindexes[L+4096] ) else set cs_pairy[loc]=cs_freeindexes[L+4096] endif endif endif elseif (lstpace==cs_array1[0]) then //We just destroyed the array that happens to be at the end of the heap. //Just get it back set cs_array1[0]=id-2 set cs_array1[146]=1 else set loc=cs_freeindexes[L] set cs_freeindexes[L]=NewPair(id,loc) if (loc==0) then set cs_freeindexes[L+4096]=cs_freeindexes[L] endif endif endfunction //================================================================================================================ // Int Set/Get array usage prototypes. // // These are the actual functions, the rest are just the result of copy paste, if these functions are updated // the other ones should be updated as well (They are just return bugged variations) // function SetArrayInt takes integer id, integer index, integer val returns nothing set index=id+index if (index<8191) then set cs_array1[index]=val elseif (index<16382) then set cs_array2[index-8191]=val else call StoreInteger(cs_cache,I2S(-id),I2S(index),val) endif endfunction function GetArrayInt takes integer id, integer index returns integer set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) endfunction //================================================================================================================ // String Set/Get array // // Due String related return bug issues, these are forced to use gamecache // function SetArrayString takes integer id, integer index, string val returns nothing call StoreString(cs_cache,I2S(-id),I2S(index),val) endfunction function GetArrayString takes integer id, integer index returns string return GetStoredString(cs_cache,I2S(-id),I2S(index)) endfunction //(Boolean is not needed) //=================================================================================================== // Indexes of real types // function SetArrayReal takes integer id, integer index, real val returns nothing set index=id+index if (index<8191) then set cs_array1[index]=CS_r2i(val) elseif (index<16382) then set cs_array2[index-8191]=CS_r2i(val) else call StoreInteger(cs_cache,I2S(-id),I2S(index),CS_r2i(val)) endif endfunction function GetArrayReal takes integer id, integer index returns real set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return 0.0 endfunction //=================================================================================================== // // function SetArrayObject takes integer id, integer index, handle val returns nothing set index=id+index if (index<8191) then set cs_array1[index]=CS_H2I(val) elseif (index<16382) then set cs_array2[index-8191]=CS_H2I(val) else call StoreInteger(cs_cache,I2S(-id),I2S(index),CS_H2I(val)) endif endfunction // // //Yep, I am crazy. But These are FASTER than using the function and a return bug exploiter separatedly. function GetArrayObject takes integer id, integer index returns handle set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayWidget takes integer id, integer index returns widget set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayTimer takes integer id, integer index returns timer set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayUnit takes integer id, integer index returns unit set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayLoc takes integer id, integer index returns location set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayTrigger takes integer id, integer index returns trigger set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayTriggerAction takes integer id, integer index returns triggeraction set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayGroup takes integer id, integer index returns group set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayEffect takes integer id, integer index returns effect set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayItem takes integer id, integer index returns item set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction function GetArrayLightning takes integer id, integer index returns lightning set index=id+index if (index<8191) then return cs_array1[index] elseif (index<16382) then return cs_array2[index-8191] endif return GetStoredInteger(cs_cache,I2S(-id),I2S(index)) return null endfunction //The rest are not used that much and they are a waste of space instead of a save of speed //most of the times. THEY ARE STILL MUCH FASTER THAN GAMECACHE function GetArrayRect takes integer id, integer index returns rect return GetArrayInt(id,index) return null endfunction function GetArrayRegion takes integer id, integer index returns region return GetArrayInt(id,index) return null endfunction function GetArrayTimerDialog takes integer id, integer index returns timerdialog return GetArrayInt(id,index) return null endfunction function GetArrayDestructable takes integer id, integer index returns destructable return GetArrayInt(id,index) return null endfunction function GetArrayImage takes integer id, integer index returns image return GetArrayInt(id,index) return null endfunction function GetArrayUbersplat takes integer id, integer index returns ubersplat return GetArrayInt(id,index) return null endfunction function GetArraySound takes integer id, integer index returns sound return GetArrayInt(id,index) return null endfunction // // The horror! // //========================================================================================================================== // Returns the size of an array (the specified by player one, not the actual size of it) should be useful. // function GetArraySize takes integer id returns integer if (id<=8191) then return cs_array1[id-1] elseif (id<=16382) then return cs_array2[id-8192] endif return GetStoredInteger(cs_cache,I2S(-id),"size") endfunction //=========================================================================================================================== // Returns an array that is an exact copy of the given array // function CloneArray takes integer id returns integer local integer sz local integer i local integer sz2 local integer x local integer y if (id<=8191) then set sz=cs_array1[id-1] elseif (id<=16382) then set sz=cs_array2[id-8192] else set sz=GetStoredInteger(cs_cache,I2S(-id),"size") //No way you are gonna call DestroyArray without calling //NewArray first, so we can use the gamecache variable directly instead endif set i=NewArray(sz,false) set sz2=i+sz-1 set sz=id+sz-1 set x=i set y=id loop exitwhen ((y>sz) or (y>=8191) or (x>=8191)) set cs_array1[x]=cs_array1[y] set y=y+1 set x=x+1 endloop loop exitwhen ((y>sz) or (y>=8191) or (x>=16382)) set cs_array2[x-8191]=cs_array1[y] set y=y+1 set x=x+1 endloop loop exitwhen ((y>sz) or (y>=8191)) call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array1[y]) set x=y+1 set y=y+1 endloop //... loop exitwhen ((y>sz) or (y>=16382) or (x>=8191)) set cs_array1[x]=cs_array2[y-8191] set y=y+1 set x=x+1 endloop loop exitwhen ((y>sz) or (y>=16382) or (x>=16382)) set cs_array2[x-8191]=cs_array2[y-8191] set y=y+1 set x=x+1 endloop loop exitwhen ((y>sz) or (y>=16382)) call StoreInteger(cs_cache,I2S(-i),I2S(x-i),cs_array2[y-8191]) set y=y+1 set x=x+1 endloop //... loop exitwhen ((y>sz) or (x>=8191)) set cs_array1[x]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id)) set y=y+1 set x=x+1 endloop loop exitwhen ((y>sz) or (x>=16382)) set cs_array2[x-8191]=GetStoredInteger(cs_cache,I2S(-id),I2S(y-id)) set y=y+1 set x=x+1 endloop loop exitwhen (y>sz) call StoreInteger(cs_cache,I2S(-i),I2S(x-i),GetStoredInteger(cs_cache,I2S(-id),I2S(y-id))) set y=y+1 set x=x+1 endloop return i endfunction //================================================================================================== // Attachable vars : Attacheable variables are what most other people call Handle Variables, they // allow to relate data with any handle, using a label, and its value, the stuff auto flushes if // the value is 0, false, "", or null . // // Differences between Attacheable variables and "Local Handle Variables" : // - The names of the functions // - The name of the function group does not cause confusion, it is difficult to say: // "you should set local handle variables to null at the end of a function" since // it sounds as if you were talking about the "Local Handle Variables" // - And can work together with Tables. // // Gamecache stuff are NOT Case Sensitive, don't ever use "" for label (Crashes game!) // // // Although locations and dynamic arrays are faster than gamecache, gamecache still keeps the flexibility // Best thing to do in my opinion is to combine these options. By combining you can acquire gamecache // flexibility and arrays/locs speed to solve a problem // //============================================================================================================ // For integers // function AttachInt takes handle h, string label, integer x returns nothing if x==0 then call FlushStoredInteger(cs_cache,I2S(CS_H2I(h)),label) else call StoreInteger(cs_cache,I2S(CS_H2I(h)),label,x) endif endfunction function GetAttachedInt takes handle h, string label returns integer return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) endfunction //============================================================================================================= function AttachReal takes handle h, string label, real x returns nothing if x==0 then call FlushStoredReal(cs_cache,I2S(CS_H2I(h)),label) else call StoreReal(cs_cache,I2S(CS_H2I(h)),label,x) endif endfunction function GetAttachedReal takes handle h, string label returns real return GetStoredReal(cs_cache,I2S(CS_H2I(h)),label) endfunction //============================================================================================================= function AttachBoolean takes handle h, string label, boolean x returns nothing if not x then call FlushStoredBoolean(cs_cache,I2S(CS_H2I(h)),label) else call StoreBoolean(cs_cache,I2S(CS_H2I(h)),label,x) endif endfunction function GetAttachedBoolean takes handle h, string label returns boolean return GetStoredBoolean(cs_cache,I2S(CS_H2I(h)),label) endfunction //============================================================================================================= function AttachString takes handle h, string label, string x returns nothing if ((x=="") or (x==null)) then call FlushStoredString(cs_cache,I2S(CS_H2I(h)),label) else call StoreString(cs_cache,I2S(CS_H2I(h)),label,x) endif endfunction function GetAttachedString takes handle h, string label returns string return GetStoredString(cs_cache,I2S(CS_H2I(h)),label) endfunction //============================================================================================================= function AttachObject takes handle h, string label, handle x returns nothing if (x==null) then call FlushStoredInteger(cs_cache,I2S(CS_H2I(h)),label) else call StoreInteger(cs_cache,I2S(CS_H2I(h)),label,CS_H2I(x)) endif endfunction function GetAttachedObject takes handle h, string label returns handle return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedWidget takes handle h, string label returns widget return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedRect takes handle h, string label returns rect return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedRegion takes handle h, string label returns region return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedTimerDialog takes handle h, string label returns timerdialog return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedUnit takes handle h, string label returns unit return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedItem takes handle h, string label returns item return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedEffect takes handle h, string label returns effect return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedDestructable takes handle h, string label returns destructable return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedTrigger takes handle h, string label returns trigger return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedTimer takes handle h, string label returns timer return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedGroup takes handle h, string label returns group return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedTriggerAction takes handle h, string label returns triggeraction return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedLightning takes handle h, string label returns lightning return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedImage takes handle h, string label returns image return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedUbersplat takes handle h, string label returns ubersplat return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedSound takes handle h, string label returns sound return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction function GetAttachedLoc takes handle h, string label returns location return GetStoredInteger(cs_cache, I2S(CS_H2I(h)), label) return null endfunction //============================================================================================================ function CleanAttachedVars takes handle h returns nothing call FlushStoredMission(cs_cache,I2S(CS_H2I(h))) endfunction //! define CleanAttachedVars(h) FlushStoredMission(cs_cache,I2S(CS_H2I(h))) //============================================================================================================ // Left for compat function CleanAttachedVars_NoSets takes handle h returns nothing call FlushStoredMission(cs_cache,I2S(CS_H2I(h))) endfunction //! define CleanAttachedVars_NoSets(h) FlushStoredMission(cs_cache,I2S(CS_H2I(h))) //============================================================================================= // Tables // // Tables are lame, the real name would be hash tables, they are just abbreviated usage // of gamecache natives with the addition that you can also Copy the values of a table to // another one, but don't expect it to be automatic, it must use a FieldData object to know // which fields and of wich types to copy, Copying a table to another, with a lot of Fields, // should surelly be lag friendly. // // The other thing about tables is that I can say that the Attached variables of a handle work // inside a table and GetAttachmentTable which is just return bug and I2S , works to allow you // to manipulate a handle's attached variables through a table. // // NewTable and DestroyTable were created to allow to create tables in the fly, but you can // simply use strings for tables, but place the table names should be between "("")" for example // "(mytable)" to avoid conflicts with other caster system stuff. // function NewTableIndex takes nothing returns integer local integer loc=cs_freeindexes[0] local integer i if (loc!=0) then set i=GetPairX(loc) set cs_freeindexes[0]=GetPairY(loc) call DestroyPair(loc) return i endif set i=cs_array1[147]+1 set cs_array1[147]=i return i endfunction function NewTable takes nothing returns string local integer loc=cs_freeindexes[0] local integer i if (loc!=0) then set i=GetPairX(loc) set cs_freeindexes[0]=GetPairY(loc) call DestroyPair(loc) return I2S(i) endif set i=cs_array1[147]+1 set cs_array1[147]=i return I2S(i) endfunction function GetAttachmentTable takes handle h returns string return I2S(CS_H2I(h)) endfunction //! define GetAttachmentTable(h) I2S(CS_H2I(h)) //============================================================================================================ function DestroyTable takes string table returns nothing local integer i=S2I(table) local integer n call FlushStoredMission(cs_cache,table) if ((i>100) and (i<1000000)) then //All right, more than 1000000 tables is just wrong. if (i==cs_array1[147]) then set cs_array1[147]=cs_array1[147]-1 else set cs_freeindexes[0]= NewPair(i,cs_freeindexes[0]) endif endif endfunction //============================================================================================================ function ClearTable takes string table returns nothing call FlushStoredMission(cs_cache,table) endfunction //============================================================================================================ function SetTableInt takes string table, string field, integer val returns nothing if (val==0) then call FlushStoredInteger(cs_cache,table,field) else call StoreInteger(cs_cache,table,field,val) endif endfunction function GetTableInt takes string table, string field returns integer return GetStoredInteger(cs_cache,table,field) endfunction //! define GetTableInt(table,field) GetStoredInteger(cs_cache,table,field) //============================================================================================================ function SetTableReal takes string table, string field, real val returns nothing if (val==0) then call FlushStoredReal(cs_cache,table,field) else call StoreReal(cs_cache,table,field,val) endif endfunction function GetTableReal takes string table, string field returns real return GetStoredReal(cs_cache,table,field) endfunction //! define GetTableReal(table,field) GetStoredReal(cs_cache,table,field) //============================================================================================================ function SetTableBoolean takes string table, string field, boolean val returns nothing if (not(val)) then call FlushStoredBoolean(cs_cache,table,field) else call StoreBoolean(cs_cache,table,field,val) endif endfunction function GetTableBoolean takes string table, string field returns boolean return GetStoredBoolean(cs_cache,table,field) endfunction //! define GetTableBoolean(table,field) GetStoredBoolean(cs_cache,table,field) //============================================================================================================ function SetTableString takes string table, string field, string val returns nothing if (val=="") or (val==null) then call FlushStoredString(cs_cache,table,field) else call StoreString(cs_cache,table,field,val) endif endfunction function GetTableString takes string table, string field returns string return GetStoredString(cs_cache,table,field) endfunction //! define GetTableString(table,field) GetStoredString(cs_cache,table,field) //============================================================================================================ // You may ask why am I using thousands of functions instead of multi-use return bug exploiters? Well, // these make the thing much easier to read (in my opinion) and it is also better in performance since we // have less function calls (H2U(GetTableObject("table","unit"))) would be worse than GetTableUnit that is // quite direct. // function SetTableObject takes string table, string field, handle val returns nothing if (val==null) then call FlushStoredInteger(cs_cache,table,field) else call StoreInteger(cs_cache,table,field,CS_H2I(val)) endif endfunction function GetTableObject takes string table, string field returns handle return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableWidget takes string table, string field returns widget return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableRect takes string table, string field returns rect return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableRegion takes string table, string field returns region return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableTimerDialog takes string table, string field returns timerdialog return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableUnit takes string table, string field returns unit return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableItem takes string table, string field returns item return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableEffect takes string table, string field returns effect return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableDestructable takes string table, string field returns destructable return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableTrigger takes string table, string field returns trigger return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableTimer takes string table, string field returns timer return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableGroup takes string table, string field returns group return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableTriggerAction takes string table, string field returns triggeraction return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableLightning takes string table, string field returns lightning return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableImage takes string table, string field returns image return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableUbersplat takes string table, string field returns ubersplat return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableSound takes string table, string field returns sound return GetStoredInteger(cs_cache,table,field) return null endfunction function GetTableLoc takes string table, string field returns location return GetStoredInteger(cs_cache,table,field) return null endfunction //============================================================================================================ // Returns true if the fiel contains a value different from 0, false, null, or "" (depending on the type) // it is worthless to use this with boolean, since it would be the same as reading the boolean value // function HaveSetField takes string table, string field, integer fieldType returns boolean if (fieldType == bj_GAMECACHE_BOOLEAN) then return HaveStoredBoolean(cs_cache,table,field) elseif (fieldType == bj_GAMECACHE_INTEGER) then return HaveStoredInteger(cs_cache,table,field) elseif (fieldType == bj_GAMECACHE_REAL) then return HaveStoredReal(cs_cache,table,field) elseif (fieldType == bj_GAMECACHE_STRING) then return HaveStoredString(cs_cache,table,field) endif return false endfunction //============================================================================================================ // Allows to copy a table to another one, but it needs a FieldData object to know which fields of which type // it is supposed to copy. // function CopyTable takes integer FieldData, string sourceTable, string destTable returns nothing local integer i=1 local string k=I2S(FieldData) local string k2 local string k3 local integer n=GetStoredInteger(cs_cache,k,"N") local integer t loop exitwhen (i>n) set k2=I2S(i) set t=GetStoredInteger(cs_cache,k,k2) set k3=GetStoredString(cs_cache,k,k2) if (t==bj_GAMECACHE_BOOLEAN) then if (HaveStoredBoolean(cs_cache,sourceTable,k3)) then call StoreBoolean(cs_cache,destTable,k3,GetStoredBoolean(cs_cache,sourceTable,k3)) else call FlushStoredBoolean(cs_cache,destTable,k3) endif elseif (t==bj_GAMECACHE_INTEGER) then if (HaveStoredInteger(cs_cache,sourceTable,k3)) then call StoreInteger(cs_cache,destTable,k3,GetStoredInteger(cs_cache,sourceTable,k3)) else call FlushStoredInteger(cs_cache,destTable,k3) endif elseif (t==bj_GAMECACHE_REAL) then if (HaveStoredReal(cs_cache,sourceTable,k3)) then call StoreReal(cs_cache,destTable,k3,GetStoredReal(cs_cache,sourceTable,k3)) else call FlushStoredReal(cs_cache,destTable,k3) endif elseif (t==bj_GAMECACHE_STRING) then if (HaveStoredString(cs_cache,sourceTable,k3)) then call StoreString(cs_cache,destTable,k3,GetStoredString(cs_cache,sourceTable,k3)) else call FlushStoredString(cs_cache,destTable,k3) endif endif set i=i+1 endloop endfunction //============================================================================================= // FieldData inherits from Table, was just designed to be used by CopyTable. // function FieldData_Create takes nothing returns integer return NewTableIndex() endfunction //! define FieldData_Create NewTableIndex //============================================================================================================ // valueType uses the same integer variables from blizzard.j : // bj_GAMECACHE_BOOLEAN, bj_GAMECACHE_INTEGER, bj_GAMECACHE_REAL and bj_GAMECACHE_STRING // function FieldData_AddField takes integer fielddata, string field, integer valueType returns nothing local string k=I2S(fielddata) local integer n=GetStoredInteger(cs_cache,k,"N")+1 local string k2=I2S(n) call StoreString(cs_cache,k,k2,field) call StoreInteger(cs_cache,k,k2,valueType) call StoreInteger(cs_cache,k,"N",n) endfunction //============================================================================================= // Destroys Field Data function FieldData_Destroy takes integer fielddata returns nothing call DestroyTable(I2S(fielddata)) endfunction //! define FieldData_Destroy(fielddata) DestroyTable(I2S(fielddata)) //============================================================================================= // Pools // // A better name for pools would be sets, but by the time I made them I couldn't think of that // name, besides the word set is already a JASS syntax word so it would have been problematic. // // Another naming failure is that values of a pool are called "items" but that conflicts with // the word item that points to wc3 items, Pools can only store integer values, but if you want // you can go and use the return bug on them. // function CreatePool takes nothing returns integer local integer i=NewArray(34,false) call SetArrayInt(i,0,0) return i endfunction function ClearPool takes integer poolid returns nothing call SetArrayInt(poolid,0,0) //[0:integer:n] call FlushStoredMission(cs_cache,I2S(-poolid)) endfunction function DestroyPool takes integer poolid returns nothing call DestroyArray(poolid) endfunction //! define DestroyPool(p) DestroyArray(p) function PoolAddItem takes integer poolid, integer value returns nothing local integer n local string k=I2S(-poolid) local string vk="#"+I2S(value) if not HaveStoredInteger(cs_cache,k,vk) then set n=GetArrayInt(poolid,0)+1 //[0:integer:N] call StoreInteger(cs_cache,k,vk,n) if (n>33) then call StoreInteger(cs_cache,k,I2S(n),value) else call SetArrayInt(poolid,n,value) endif call SetArrayInt(poolid,0,n) //[0:integer:N] endif endfunction function PoolRemoveItem takes integer poolid, integer value returns nothing local string k=I2S(-poolid) local string vk="#"+I2S(value) local integer p=GetStoredInteger(cs_cache,k,vk) local integer n if (p!=0) then set n=GetArrayInt(poolid,0) //[0:integer:N] call FlushStoredInteger( cs_cache, k, vk) if (n>p) then if (n>33) then set vk=I2S(n) set value=GetStoredInteger(cs_cache,k,vk) call FlushStoredInteger(cs_cache,k,vk) else set value=GetArrayInt(poolid,n) endif call StoreInteger(cs_cache,k,"#"+I2S(value),p) if (p>33) then call StoreInteger(cs_cache,k,I2S(p),value) else call SetArrayInt(poolid,p,value) endif elseif (p>33) then call FlushStoredInteger(cs_cache,k,I2S(p)) endif call SetArrayInt( poolid,0,n - 1) //[0:integer:N] endif endfunction //=================================================================================== function PoolGetItem takes integer poolid, integer itemn returns integer if (itemn>33) then return GetStoredInteger( cs_cache, I2S(-poolid), I2S(itemn)) endif return GetArrayInt(poolid,itemn) endfunction //=================================================================================== function CountItemsInPool takes integer poolid returns integer return GetArrayInt(poolid,0) //[0:integer:N] endfunction //! define CountItemsInPool(p) GetArrayInt(p,0) //=================================================================================== // Removed : GetEnumPoolItem , ForPool and ForPool2 they are much worse than just // using CountItemsInPool and PoolGetItem to iterate the pool // //=================================================================================== function GetFirstOfPool takes integer poolid returns integer return GetArrayInt(poolid,1) //[1 is just the first of the pool] endfunction //! define GetFirstOfPool(p) GetArrayInt(p,1) //=================================================================================== function PoolPickRandomItem takes integer poolid returns integer local integer p=GetRandomInt( 1, GetArrayInt(poolid,0) ) if (p>33) then return GetStoredInteger( cs_cache, I2S(-poolid), I2S(p)) endif return GetArrayInt(poolid,p) endfunction //=================================================================================== function GetItemPositionInPool takes integer poolid, integer it returns integer return GetStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it)) endfunction //! define GetItemPositionInPool(p,i) GetStoredInteger( cs_cache, I2S(- (p) ), "#"+I2S(i)) //=================================================================================== function IsItemInPool takes integer poolid, integer it returns boolean return(HaveStoredInteger( cs_cache, I2S(-poolid), "#"+I2S(it)) ) endfunction //! define IsItemInPool(p,i) HaveStoredInteger( cs_cache, I2S(- (p) ), "#"+I2S(i)) //=================================================================================== // This had to be optimized for speed, if it was just a loop using the above functions // that would have been too slow to be worth keeping. That's a bad thing about JASS // it is such an slow language that code reusability always has the cost of speed // function PoolAddPool takes integer sourcepoolid, integer destpoolid returns nothing local integer a=1 local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N] local integer dn=GetArrayInt( destpoolid,0) //[0:integer:N] local string sk=I2S(-sourcepoolid) local string k=I2S(-destpoolid) local integer v local string vk loop exitwhen (a>n) if (a>33) then set v=GetStoredInteger(cs_cache,sk,I2S(a)) else set v=GetArrayInt(sourcepoolid,a) endif set vk="#"+I2S(v) if not HaveStoredInteger(cs_cache,k,vk) then set dn=dn+1 call StoreInteger(cs_cache,k,vk,dn) if (dn>33) then call StoreInteger(cs_cache,k,I2S(dn),v) else call SetArrayInt(destpoolid,dn,v) endif endif set a=a+1 endloop call SetArrayInt(destpoolid,0,dn) //[0:integer:N] endfunction //============================================================================================= // Oh darn, After making PoolAddPool I don't feel like writting this one // All right I am at least make the get code // function PoolRemovePool takes integer sourcepoolid, integer destpoolid returns nothing local integer a=1 local integer n=GetArrayInt( sourcepoolid,0) //[0:integer:N] local integer v local string sk=I2S(-sourcepoolid) loop exitwhen a>n if (a>33) then set v=GetStoredInteger(cs_cache,sk,I2S(a) ) else set v=GetArrayInt(sourcepoolid,a) endif call PoolRemoveItem( destpoolid, v) set a=a+1 endloop endfunction //=================================================================================== // Adds a tokenized string to a pool, // Example: PoolAddS(udg_p, "1;2;3;4") will add to the udg_p pool : 1,2,3 and 4 // function PoolAddS takes integer poolid, string s returns nothing local integer i=0 local integer st local string c set s=s+";" set st=0 loop set c=SubString(s, i, i+1) exitwhen (c == "") or (c == null) if (c == ";") then call PoolAddItem( poolid, S2I(SubString(s, st, i)) ) set st=i+1 endif set i=i+1 endloop endfunction //=================================================================================== // Converts a tokenized string into a pool, // Example: S2Pool( "1;2;3;4") will return a pool that has 1,2,3 and 4 inside // function S2Pool takes string s returns integer local integer spool= CreatePool() call PoolAddS(spool,s) return spool endfunction //=================================================================================== // Does the opposite of S2Pool, debugging is a good use for this function. // function Pool2S takes integer P returns string local integer N=CountItemsInPool(P) local integer i local string s if (N>=1) then set s=I2S(PoolGetItem(P,1) ) set i=2 else return "" endif loop exitwhen (i>N) set s=s+";"+I2S(PoolGetItem(P,i)) set i=i+1 endloop return s endfunction //============================================================================================================= // Fixes a lame bug by blizzard related to the custom script section (The condition of the if statement might // actually be true. // function Pool_Percent takes nothing returns string if ("%"=="") then return "%%" endif return "%" endfunction function Pool_SetupCharMap takes nothing returns nothing local string cm=".................................!.#$"+Pool_Percent()+"&'()*+,-./0123456789:;<=>.@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................." local integer i=0 local string c if HaveStoredInteger(cs_cache,"charmap_upper","A") then return endif loop set c=SubString(cm,i,i+1) exitwhen (c==null) or (c=="") if (c!=".") then if c==StringCase(c,true) then call StoreInteger(cs_cache,"charmap_upper",c,i) else call StoreInteger(cs_cache,"charmap_lower",c,i) endif endif set i=i+1 endloop endfunction function Pool_Rawcode2Int takes string s returns integer local string c local integer i=0 local integer r=0 loop exitwhen i>3 set c=SubString(s,i,i+1) set r=r*256 if c==StringCase(c,true) then set r=r+GetStoredInteger(cs_cache,"charmap_upper",c) else set r=r+GetStoredInteger(cs_cache,"charmap_lower",c) endif set i=i+1 endloop return r endfunction function PoolAddRawcodes_thread takes nothing returns nothing //Threaded because I don't want it to halt execution for no reason // local string s=bj_lastPlayedMusic local integer poolid=bj_groupEnumTypeId local string c local integer i=0 local integer st=0 set s=s+";" loop set c=SubString(s, i, i+1) exitwhen (c == "") or (c == null) if c == ";" then call PoolAddItem(poolid, Pool_Rawcode2Int(SubString(s,st,i) )) set st=i+1 endif set i=i+1 endloop endfunction //===================================================================================================================== // Adds a string of tokenized rawcodes to a pool // Example: PoolAddRawcodes(udg_p,"A000;A001") will add 'A000' and 'A001' to the pool // // (Saves some lines, but is not as good efficiency wise) // function PoolAddRawcodes takes integer poolid, string s returns nothing local string b=bj_lastPlayedMusic set bj_groupEnumTypeId=poolid set bj_lastPlayedMusic=s call ExecuteFunc("PoolAddRawcodes_thread") set bj_lastPlayedMusic=b endfunction //=================================================================================================================== // Converts a tokenized string of rawcodes into a pool, // Example: Rawcodes2Pool( "A000;A001;AHbz;S000") will return a pool that has 'A000,'A001','AHbx' and 'S000' inside // // (Saves some lines, but is not as good efficiency wise) // function Rawcodes2Pool takes string s returns integer local integer spool= CreatePool() call PoolAddRawcodes(spool,s) return spool endfunction //=================================================================================================================== // A subproduct of the Pool's Rawcode support is that we can easily have this function so I am including it even if // it has nothing to do with data storage. // // takes "Aloc" and converts it into 'Aloc' // it is different to the Pool_Rawcode2Int function in that it is safe to use it when it is the first CSCache // function ever used. But it is a little slower (wc3mapoptimizer should make it as fast though) // function CS_Rawcode2Int takes string s returns integer local string c local integer i=0 local integer r=0 loop exitwhen i>3 set c=SubString(s,i,i+1) set r=r*256 if c==StringCase(c,true) then set r=r+GetStoredInteger(cs_cache,"charmap_upper",c) else set r=r+GetStoredInteger(cs_cache,"charmap_lower",c) endif set i=i+1 endloop return r endfunction function CSCache takes nothing returns gamecache return cs_cache //Left for compat. endfunction endlibrary //Forced by WE function InitTrig_CSCache takes nothing returns nothing endfunction//=========================================================================== // Trigger: CSSafety //=========================================================================== library CSSafety //****************************************************************************************** //* //* CSSafety 14.3 //* ¯¯¯¯¯¯¯¯ //* //* Utilities to make things safer. Currently this simply includes a timer recycling //* Stack. Once you replace CreateTimer with NewTimer and DestroyTimer with ReleaseTimer //* you no longer have to care about setting timers to null nor about timer related issues //* with the handle index stack. //* //****************************************************************************************** //========================================================================================== globals private timer array T private integer N = 0 endglobals //========================================================================================== function NewTimer takes nothing returns timer if (N==0) then return CreateTimer() endif set N=N-1 return T[N] endfunction //========================================================================================== function ReleaseTimer takes timer t returns nothing call PauseTimer(t) if (N==8191) then debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!") //stack is full, the map already has much more troubles than the chance of bug call DestroyTimer(t) else set T[N]=t set N=N+1 endif endfunction endlibrary //Forced by WE function InitTrig_CSSafety takes nothing returns nothing endfunction //=========================================================================== // Trigger: CasterSystem //=========================================================================== library CasterSystem initializer InitCasterSystem, requires CSCache, CSSafety //*************************************************************************** //* * //* Caster System 14.3 * //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ http://wc3campaigns.net/vexorian * //* Requires: * //* ¯¯¯¯¯¯¯¯¯ * //* * //* - The CSCache Module * //* - The CSSafety Module * //* * //* - The caster unit from this map Can be found in this map's unit editor * //* ( Custom Units\Neutral Passive\Units\Caster ) * //* * //* ( Update the cs_CasterUnitId constant next:) * //* * //* - the war3mapImported\dummy.mdx imported file (find it in this map) * //* * //*************************************************************************** //==================================================================================================================================================================== // Caster System Configuration constants : // globals // // Caster Unit type rawcode (changes betwen maps, always use it inside '') // constant integer cs_CasterUnitId = 'e000' // cs_TIMER_CYCLE : Cycle value for the projectile movement in seconds (Each 0.04 the projectiles get moved) // 0.01 looks smooth but is lag friendly // 0.025 looks smooth and probably matches wc3's frame rate (so in theory, lower values than it are not needed) // 0.1 looks horrible but is not laggy // 0.04 is decent for the human eye and very efficient. // 0.035 is ... well, a little smoother than 0.04 // 0.05 would be an improvement in efficiency but probably doesn't look too well ) // constant real cs_TIMER_CYCLE = 0.035 //0.035 // // The eat tree ability, don't need to change this rawcode unless you modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here. // constant integer cs_DamageTreeDetectorId = 'Aeat' // // Medivh's Crow form ability, don't need to change this rawcode unless you // modiffied that ability in your map, in that case copy it, reset the copied one and use its rawcode here: // constant integer cs_FlyingHeightHack = 'Amrf' // // This must point to an inventory ability with 6 slots that does not add bonuses, you don't need one unless // the caster system item hiding functions are used in your map // constant integer cs_DummyInventory_Id = 'null' // //Maximum collision size in your map - Affects the caster system's area cast/damage functions // constant real cs_MaxUnitCollisionSize = 55.0 // // Next are default attack and damage types for the old caster system functions or when using 0 as damageoptions // constant attacktype cs_DefaultAttackType = ATTACK_TYPE_CHAOS constant damagetype cs_DefaultDamageType = DAMAGE_TYPE_UNIVERSAL // // cs_InitialCastersNumber: Number of casters to create on map init: // constant integer cs_InitialCastersNumber = 12 endglobals // //================================================================================================= // Caster System script: // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ // Note: many //! defines are distributed along the script, these defines are optional, and are // just an optimization, which means that if saved in WEHelper , the caster system will be able to // replace wrapper versions of functions to direct calls and save some overhead. // //================================================================================================= // main Caster System global variables: // globals //old ones (udg_ preffix forced for compat ( ) unit udg_currentcaster = null real array udg_castervars group udg_casters = null integer udg_currentabi = 0 unit udg_currenthurter = null real udg_delayhack = 0. location udg_sourcehack = null //-- integer array cs_missiles integer cs_missilecount = 0 timer cs_movementtimer = CreateTimer() boolean cs_movementtimer_active = false endglobals //================================================================================================= function CS_Rawcode2Real takes integer i returns real return i return 0. endfunction function CS_LoadRawcodeFromReal takes integer n returns integer return udg_castervars[n] return 0 endfunction function CS_CopyGroup takes group g returns group set bj_groupAddGroupDest=CreateGroup() call ForGroup(g, function GroupAddGroupEnum) return bj_groupAddGroupDest endfunction function CS_IsUnitVisible takes unit u, player p returns boolean return IsUnitVisible(u,p) endfunction //! define CS_IsUnitVisible(u,p) IsUnitVisible(u,p) function CS_UnitHasInvisiblity takes unit u, player p returns boolean return IsUnitVisible(u,Player(bj_PLAYER_NEUTRAL_VICTIM)) and not( IsUnitVisible(u,p)) endfunction globals constant real cs_RectLimitOffSet = 50.0 real cs_game_maxx real cs_game_maxy real cs_game_miny real cs_game_minx endglobals function CS_SafeXY_Init takes nothing returns nothing set cs_game_maxx=GetRectMaxX(bj_mapInitialPlayableArea)-cs_RectLimitOffSet set cs_game_maxy=GetRectMaxY(bj_mapInitialPlayableArea)-cs_RectLimitOffSet set cs_game_miny=GetRectMinY(bj_mapInitialPlayableArea)+cs_RectLimitOffSet set cs_game_minx=GetRectMinX(bj_mapInitialPlayableArea)+cs_RectLimitOffSet endfunction function CS_SafeX takes real x returns real if (xcs_game_maxx) then return cs_game_maxx endif return(x) endfunction function CS_SafeY takes real y returns real if (ycs_game_maxy) then return cs_game_maxy endif return(y) endfunction function CS_MoveUnit takes unit u, real x, real y returns boolean local boolean b=true if (xcs_game_maxx) then set b=false elseif (y>cs_game_maxy) then set b=false elseif (ya2 then set x=a1 set a1=a2 set a2=x endif set x=a2-360 if a2-a1 > a1-x then set a2=x endif set x=a1-a2 if (x<0) then return -x endif return x endfunction //================================================================================================= // Returns the mid angle between a1 and a2 (For example: a1=30 , a2=60 , return= 45 ) // function Angles_GetMidAngle takes real a1, real a2 returns real local real x set a1=ModuloReal(a1,360) set a2=ModuloReal(a2,360) if a1>a2 then set x=a1 set a1=a2 set a2=x endif set x=a2-360 if a2-a1 > a1-x then set a2=x endif return (a1+a2)/2 endfunction //================================================================================================= // Makes angle a1 advance i units towards angle a2 (For Example: a1=30, a2=60, i=10, return=40 ) // function Angles_MoveAngleTowardsAngle takes real a1, real a2, real i returns real local real x set a1=ModuloReal(a1,360) set a2=ModuloReal(a2,360) if a1>a2 then set x=a1-360 if a1-a2 > a2-x then set a1=x endif else set x=a2-360 if a2-a1 > a1-x then set a2=x endif endif if a1>a2 then set x=a1-i if x<=a2 then return a2 endif return x endif set x=a1+i if x>=a2 then return a2 endif return x endfunction //================================================================================================= // Returns true if the angle 'angle' is between 'angle1' and 'angle2' // function Angles_IsAngleBetweenAngles takes real angle, real angle1, real angle2 returns boolean local real x set angle=ModuloReal(angle,360) set angle1=ModuloReal(angle1,360) set angle2=ModuloReal(angle2,360) if (angle1>angle2) then set x=angle1 set angle1=angle2 set angle2=x endif if (angle2-angle1)>(angle1 - (angle2-360)) then set angle2=angle2-360 if angle > 180 then set angle=angle-360 endif return angle>=angle2 and angle<=angle1 endif return (angle>=angle1) and (angle<=angle2) endfunction //==================================================================================================================================================================== function CreateCaster takes real fac, real x , real y returns unit local unit m if (x!=0) then set x=CS_SafeX(x) endif if (y!=0) then set y=CS_SafeY(y) endif set m=CreateUnit( Player(15), cs_CasterUnitId, x ,y ,fac) call UnitAddAbility(m, 'Aloc') call UnitAddAbility(m, cs_FlyingHeightHack) call UnitRemoveAbility(m, cs_FlyingHeightHack ) set udg_currentcaster=m set m=null return udg_currentcaster endfunction function AddCasterFacing takes real fac returns unit return CreateCaster(fac,0,0) endfunction function AddCaster takes nothing returns unit return CreateCaster(0,0,0) endfunction ///! define AddCaster() CreateCaster(0,0,0) maybe in a future wehelper version this works //==================================================================================================================================================================== function CS_KillTrigger takes trigger t returns nothing if (t!=null) then call TriggerRemoveAction(t,GetAttachedTriggerAction(t,"ac")) call CleanAttachedVars(t) call DestroyTrigger(t) endif endfunction function CS_KillTimer takes timer t returns nothing if (t!=null) then call PauseTimer(t) call CleanAttachedVars(t) call DestroyTimer(t) endif endfunction //==================================================================================================================================================================== function CreateCasters takes integer n returns nothing local integer a=0 local unit c loop exitwhen a>=n set c=CreateCaster(0,0,0) call GroupAddUnit( udg_casters, c) set a=a+1 endloop set c=null endfunction private function InitCasterSystem takes nothing returns nothing set udg_casters=CreateGroup() call CS_SafeXY_Init() call CreateCasters(cs_InitialCastersNumber) set udg_castervars[100]=-1 set udg_castervars[101]=-1 set udg_castervars[102]=-1 set udg_castervars[103]=-1 set udg_castervars[104]=-1 set cs_dmg_caster=CreateCaster(0.,0.,0.) call UnitRemoveAbility(cs_dmg_caster,'Aloc') //Otherwise the units would flee like crazy endfunction //==================================================================================================================================================================== function GetACaster takes nothing returns unit set udg_currentcaster=FirstOfGroup( udg_casters) if udg_currentcaster == null then set udg_currentcaster=CreateCaster(0,0,0) endif call GroupRemoveUnit( udg_casters,udg_currentcaster) call SetUnitState( udg_currentcaster, UNIT_STATE_MANA, 1000) return udg_currentcaster endfunction //==================================================================================================================================================================== function Caster_SetZAngle takes unit caster, real ang returns nothing local real a=(ModuloReal(GetUnitFacing(caster),360)*bj_DEGTORAD) local real x set ang=ModuloReal(ang,360) if ( ang == 90 ) then set ang = 89 endif if ( ang == 270 ) then set ang = 271 endif if (ang>90) and (ang<270) then set x=-1 else set x=1 endif set ang=ang*bj_DEGTORAD call SetUnitLookAt(caster,"Bone_Chest",caster, 10000.0*Cos(a)*Cos(ang), 10000.0*Sin(a)*Cos(ang), x*(10000.0*Tan(ang)+90.0) ) endfunction //==================================================================================================================================================================== function Caster_SetZAngle2 takes unit caster, integer ang returns nothing call SetUnitAnimationByIndex(caster,ang+90) //Thanks infrane! endfunction //==================================================================================================================================================================== function RecycleCaster takes unit caster returns nothing if GetWidgetLife(caster)>=0.405 then call ResetUnitLookAt(caster) call SetUnitOwner( caster, Player(15), true) call SetUnitVertexColor( caster, 255,255,255,255) call SetUnitScale( caster, 1,1,1) call SetUnitTimeScale( caster, 1) call SetUnitMoveSpeed( caster, 522) call SetUnitFlyHeight( caster, 0,0) call UnitAddAbility(caster, 'Aloc') call SetUnitTurnSpeed( caster, 0.6) call GroupAddUnit( udg_casters, caster) endif endfunction function RecycleCaster_Light takes unit caster returns nothing if GetWidgetLife(caster)>=0.405 then call SetUnitOwner( caster, Player(15), true) call GroupAddUnit( udg_casters, caster) endif endfunction function RecicleCaster takes unit caster returns nothing call RecycleCaster(caster) endfunction function RecicleCaster_Light takes unit caster returns nothing call RecycleCaster_Light(caster) endfunction //! define RecicleCaster RecycleCaster //! define RecicleCaster_Light RecycleCaster_Light private struct csrecy unit caster integer abil endstruct function CasterRecycleTimed_X takes nothing returns nothing local timer t=GetExpiredTimer() local csrecy k=GetCSData(t) if (k.abil!=0) then call UnitRemoveAbility(k.caster,k.abil) endif call RecycleCaster(k.caster) call k.destroy() call ReleaseTimer(t) endfunction function CasterRecycleTimed takes unit caster, integer abi, real delay returns nothing local timer t=NewTimer() local csrecy k= csrecy.create() set k.caster=caster set k.abil=abi call SetCSData(t,k) call TimerStart(t,delay,false,function CasterRecycleTimed_X) endfunction function CasterWaitForEndCast takes nothing returns nothing local unit caster=udg_currentcaster local integer abilid=udg_currentabi local real delay=udg_castervars[0] local boolean activeability=(udg_castervars[1]>0) loop exitwhen GetUnitCurrentOrder(caster) == 0 call TriggerSleepAction(0) endloop if (delay>0) then if activeability then call CasterRecycleTimed(caster,abilid,delay) else call UnitRemoveAbility( caster, abilid) call CasterRecycleTimed(caster,0,delay) endif else call UnitRemoveAbility( caster, abilid) call RecycleCaster(caster) endif set caster=null endfunction function RecycleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing set udg_castervars[0]=delaytime set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0) set udg_currentabi=abilid set udg_currentcaster=caster call ExecuteFunc("CasterWaitForEndCast" ) endfunction function RecicleCasterAfterCastEx takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing call RecycleCasterAfterCastEx(caster,delaytime,abilid,activeability) endfunction //! define RecicleCasterAfterCastEx RecycleCasterAfterCastEx function CasterWaitForEndCast_Light takes nothing returns nothing local unit caster=udg_currentcaster local integer abilid=udg_currentabi local real delay=udg_castervars[0] local boolean activeability=(udg_castervars[1]>0) loop exitwhen GetUnitCurrentOrder(caster) == 0 call TriggerSleepAction(0) endloop if (delay>0) then if activeability then call CasterRecycleTimed(caster,abilid,delay) else call UnitRemoveAbility( caster, abilid) call CasterRecycleTimed(caster,0,delay) endif else call UnitRemoveAbility( caster, abilid) call RecycleCaster_Light(caster) endif set caster=null endfunction function RecycleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing set udg_castervars[0]=delaytime set udg_castervars[1]=IntegerTertiaryOp(activeability,1,0) set udg_currentabi=abilid set udg_currentcaster=caster call ExecuteFunc("CasterWaitForEndCast_Light" ) endfunction function RecicleCasterAfterCastEx_Light takes unit caster, real delaytime, integer abilid, boolean activeability returns nothing call RecycleCasterAfterCastEx_Light(caster,delaytime,abilid,activeability) endfunction function RecicleCasterAfterCast takes unit caster, integer abilid returns nothing call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false) endfunction function RecycleCasterAfterCast takes unit caster, integer abilid returns nothing call RecycleCasterAfterCastEx(caster,udg_delayhack,abilid,false) endfunction //! RecicleCasterAfterCastEx_Light RecycleCasterAfterCastEx_Light //! define RecicleCasterAfterCast(c,a) RecycleCasterAfterCastEx(c,udg_delayhack,a,false) //! define RecycleCasterAfterCast(c,a) RecycleCasterAfterCastEx(c,udg_delayhack,a,false) //==================================================================================================================================================================== function PreloadAbility takes integer abilid returns integer local unit u=FirstOfGroup(udg_casters) if u==null then set u=GetACaster() call UnitAddAbility(u, abilid) call UnitRemoveAbility(u, abilid) call RecycleCaster_Light( u) else call UnitAddAbility(u, abilid) call UnitRemoveAbility(u, abilid) endif set u=null return abilid endfunction //==================================================================================================================================================================== function CasterCastAbilityEx takes player owner, real x, real y, real z, integer abilid, integer level, string order, widget target, real delay returns unit local unit caster=GetACaster() local boolean done=false call SetUnitOwner( caster, owner, false) call UnitAddAbility( caster, abilid) call SetUnitAbilityLevel(caster,abilid,level) call CS_MoveUnit( caster, x,y) call SetUnitFlyHeight(caster,z,0) if S2I(order) != 0 then set done=IssueTargetOrderById( caster, S2I(order), target ) else set done=IssueTargetOrder( caster, order, target ) endif if (delay<=0) or not(done) then call UnitRemoveAbility( caster, abilid) call RecycleCaster_Light( caster) else call RecycleCasterAfterCastEx_Light(caster, delay, abilid, true) endif set udg_currentcaster=caster set caster=null return udg_currentcaster endfunction //==================================================================================================================================================================== function CasterCastAbilityExLoc takes player owner, location loc, real z, integer abilid, integer level, string order, widget target, real delay returns unit return CasterCastAbilityEx(owner,GetLocationX(loc),GetLocationY(loc),z,abilid,level,order,target,delay) endfunction //==================================================================================================================================================================== function CasterCastAbilityLevel takes player owner, integer abilid, integer level, string order, widget target, boolean instant returns unit local real x local real y local real d if udg_sourcehack!=null then set x=GetLocationX(udg_sourcehack) set y=GetLocationY(udg_sourcehack) else set x=GetWidgetX(target) set y=GetWidgetY(target) endif if not(instant) then set d=udg_delayhack+0.01 else set d=0 endif return CasterCastAbilityEx(owner,x,y,0,abilid,level,order,target,d) endfunction //==================================================================================================================================================================== function CasterCastAbility takes player owner, integer abilid, string order, widget target, boolean instant returns unit return CasterCastAbilityLevel( owner, abilid, 1, order, target, instant ) endfunction //==================================================================================================================================================================== function CasterCastAbilityPointEx takes player owner, real x1, real y1, real z1, integer abilid, integer level, string order, real x2, real y2, real delay returns unit local unit caster=GetACaster() call SetUnitOwner( caster, owner, false) call UnitAddAbility( caster, abilid) call SetUnitAbilityLevel(caster,abilid,level) call CS_MoveUnit( caster, x1, y1) call SetUnitFlyHeight(caster,z1,0) if S2I(order) != 0 then if not IssuePointOrderById( caster, S2I(order), x2,y2 ) then call IssueImmediateOrderById( caster, S2I(order) ) endif else if not IssuePointOrder( caster, order, x2,y2 ) then call IssueImmediateOrder( caster, order ) endif endif if (delay<=0) then call UnitRemoveAbility( caster, abilid) call RecycleCaster_Light( caster) else call RecicleCasterAfterCastEx_Light(caster, delay, abilid, true) endif set udg_currentcaster=caster set caster=null return udg_currentcaster endfunction //==================================================================================================================================================================== function CasterCastAbilityPointExLoc takes player owner, location loc1, real z1, integer abilid, integer level, string order, location loc2, real delay returns unit return CasterCastAbilityPointEx(owner,GetLocationX(loc1),GetLocationY(loc1),z1,abilid,level,order,GetLocationX(loc2),GetLocationY(loc2),delay) endfunction //==================================================================================================================================================================== function CasterCastAbilityLevelPoint takes player owner, integer abilid, integer level, string order, real x, real y, boolean instant returns unit local real sx local real sy local real d if udg_sourcehack!=null then set sx=GetLocationX(udg_sourcehack) set sy=GetLocationY(udg_sourcehack) else set sx=x set sy=y endif if instant then set d=0 else set d=udg_delayhack+0.01 endif return CasterCastAbilityPointEx(owner,sx,sy,0,abilid,level,order,x,y,d) endfunction function CasterCastAbilityPoint takes player owner, integer abilid, string order, real x, real y, boolean instant returns unit return CasterCastAbilityLevelPoint(owner,abilid,1,order,x,y,instant) endfunction function CasterCastAbilityPointLoc takes player owner, integer abilid, string order, location loc, boolean instant returns unit return CasterCastAbilityLevelPoint( owner, abilid, 1,order, GetLocationX(loc), GetLocationY(loc), instant ) endfunction function CasterCastAbilityLevelPointLoc takes player owner, integer abilid, integer level, string order, location loc, boolean instant returns unit return CasterCastAbilityLevelPoint( owner, abilid, level,order, GetLocationX(loc), GetLocationY(loc), instant ) endfunction //==================================================================================================================================================================== private struct cssabi effect fx unit caster integer abil endstruct function CasterUseAbilityLevelStatic_Rec takes nothing returns nothing local timer t=GetExpiredTimer() local cssabi k=GetCSData(t) call RecycleCaster(k.caster) call k.destroy() call ReleaseTimer(t) endfunction function CasterUseAbilityLevelStatic_X takes nothing returns nothing local timer t=GetExpiredTimer() local cssabi k=GetCSData(t) call DestroyEffect(k.fx) call UnitRemoveAbility( k.caster, k.abil) call TimerStart(t,2,false, function CasterUseAbilityLevelStatic_Rec) endfunction function CasterUseAbilityLevelStatic takes player owner, string modelpath, integer abilityid, integer level, real duration, real x, real y returns unit local timer t=NewTimer() local unit c=GetACaster() local cssabi k= cssabi.create() call SetUnitPosition( c, x, y) set k.fx= AddSpecialEffectTarget( modelpath, c,"origin" ) set k.caster = c set k.abil=abilityid call SetUnitOwner(c, owner, true) call UnitAddAbility(c, abilityid) call SetUnitAbilityLevel(c, abilityid, level) call SetCSData(t,k) call TimerStart(t,duration,false,function CasterUseAbilityLevelStatic_X) set udg_currentcaster=c set c=null return udg_currentcaster endfunction function CasterUseAbilityStatic takes player owner, string modelpath, integer abilityid, real duration, real x, real y returns unit return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration,x,y) endfunction //! define CasterUseAbilityStatic(o,m,a,d,x,y) CasterUseAbilityLevelStatic(o,m,a,1,d,x,y) function CasterUseAbilityStaticLoc takes player owner, string modelpath, integer abilityid, real duration, location loc returns unit return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,1,duration, GetLocationX(loc), GetLocationY(loc)) endfunction //! define CasterUseAbilityStaticLoc(o,m,a,d,L) CasterUseAbilityLevelStatic(o,m,a,1,d,GetLocationX(L),GetLocationY(L)) function CasterUseAbilityLevelStaticLoc takes player owner, string modelpath, integer abilityid, integer level,real duration, location loc returns unit return CasterUseAbilityLevelStatic(owner,modelpath,abilityid,level,duration, GetLocationX(loc), GetLocationY(loc)) endfunction //! define CasterUseAbilityLevelStaticLoc(o,m,a,lev,d,L) CasterUseAbilityLevelStatic(o,m,a,lev,d,GetLocationX(L),GetLocationY(L)) //==================================================================================================================================================================== function CasterCastAbilityLevelGroup takes player owner, integer abilid, integer level,string order, group targetgroup, boolean instant returns nothing local group affected local unit tempunit local unit caster=null if bj_wantDestroyGroup then set bj_wantDestroyGroup=false set affected=targetgroup else set affected=CreateGroup() call GroupAddGroup( targetgroup, affected) endif loop set tempunit=FirstOfGroup(affected) exitwhen tempunit == null if instant then if caster==null then set caster=GetACaster() call SetUnitOwner( caster, owner, false) call UnitAddAbility( caster, abilid) call SetUnitAbilityLevel( caster, abilid,level) endif if udg_sourcehack != null then call CS_MoveUnit(caster,GetLocationX(udg_sourcehack),GetLocationY(udg_sourcehack)) else //If the unit exists then it is in a safe place, so we don't need the checks of CS_MoveUnit. call SetUnitX(caster,GetUnitX(tempunit)) call SetUnitY(caster,GetUnitY(tempunit)) endif if S2I(order) != 0 then call IssueTargetOrderById( caster, S2I(order), tempunit ) else call IssueTargetOrder( caster, order, tempunit ) endif else call CasterCastAbilityLevel( owner, abilid,level, order, tempunit, false) endif call GroupRemoveUnit(affected, tempunit) endloop if caster != null then call UnitRemoveAbility( caster, abilid) call RecycleCaster(caster) endif call DestroyGroup(affected) set affected=null set tempunit=null set caster=null endfunction function CasterCastAbilityGroup takes player owner, integer abilid, string order, group targetgroup, boolean instant returns nothing call CasterCastAbilityLevelGroup(owner,abilid,1,order,targetgroup,instant) endfunction //! define CasterCastAbilityGroup(o,a,or,t,i) CasterCastAbilityLevelGroup(o,a,1,or,t,i) //==================================================================================================================================================================== function CasterAOE_IsFilterEnemy takes nothing returns boolean return IsUnitEnemy( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405) endfunction function CasterAOE_IsFilterAlly takes nothing returns boolean return IsUnitAlly( GetFilterUnit(), bj_groupEnumOwningPlayer ) and ( GetWidgetLife(GetFilterUnit()) > 0.405) endfunction //==================================================================================================================================================================== function CasterCastAbilityLevelAOE takes player owner, integer abilid, integer level, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing local boolexpr b local group aoe=CreateGroup() set bj_groupEnumOwningPlayer=owner if goodeffect then set b=Condition(function CasterAOE_IsFilterAlly) else set b=Condition(function CasterAOE_IsFilterEnemy) endif call CS_EnumUnitsInAOE(aoe, x,y, radius, b) set bj_wantDestroyGroup=true call CasterCastAbilityLevelGroup( owner, abilid, level, order, aoe, instant) call DestroyBoolExpr(b) set b=null set aoe=null endfunction function CasterCastAbilityAOE takes player owner, integer abilid, string order, real x, real y, real radius, boolean goodeffect, boolean instant returns nothing call CasterCastAbilityLevelAOE(owner,abilid,1,order,x,y,radius,goodeffect,instant) endfunction //! define CasterCastAbilityAOE(o,a,or,x,y,r,g,i) CasterCastAbilityLevelAOE(o,a,1,or,x,y,r,g,i) function CasterCastAbilityAOELoc takes player owner, integer abilid, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing call CasterCastAbilityLevelAOE(owner, abilid,1, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant) endfunction //! define CasterCastAbilityAOELoc(o,a,or,L,r,g,i) CasterCastAbilityLevelAOE(o,a,1,or,GetLocationX(L),GetLocationY(L),r,g,i) function CasterCastAbilityLevelAOELoc takes player owner, integer abilid, integer level, string order, location center, real radius, boolean goodeffect, boolean instant returns nothing call CasterCastAbilityLevelAOE(owner, abilid,level, order, GetLocationX(center), GetLocationY(center), radius, goodeffect, instant) endfunction //! define CasterCastAbilityLevelAOELoc(o,a,lev,or,L,r,g,i) CasterCastAbilityLevelAOE(o,a,lev,or,GetLocationX(L),GetLocationY(L),r,g,i) //==================================================================================================================================================================== globals timer cs_sourcehacktimer = CreateTimer() timer cs_delayhacktimer = CreateTimer() endglobals function ResetSourceHack takes nothing returns nothing if (udg_sourcehack!=null) then call RemoveLocation(udg_sourcehack) set udg_sourcehack=null endif endfunction function CasterSetCastSource takes real x, real y returns nothing if (udg_sourcehack==null) then set udg_sourcehack=Location(x,y) else call MoveLocation(udg_sourcehack,x,y) endif call TimerStart(cs_sourcehacktimer,0.,false,function ResetSourceHack) endfunction function CasterSetCastSourceLoc takes location loc returns nothing call CasterSetCastSource( GetLocationX(loc), GetLocationY(loc) ) endfunction //! define CasterSetCastSourceLoc(loc) CasterSetCastSource(GetLocationX(loc),GetLocationY(loc)) function ResetDelayHack takes nothing returns nothing set udg_delayhack=0. endfunction function CasterSetRecycleDelay takes real Delay returns nothing set udg_delayhack=Delay call TimerStart(cs_delayhacktimer,0.,false,function ResetDelayHack) endfunction //==================================================================================================================================================================== //Super DamageOptions structure! globals attacktype cs_dopt_Atype = null damagetype cs_dopt_Dtype = null unittype cs_dopt_ExceptionUtype = null real cs_dopt_ExceptionFct = 1.0 unittype cs_dopt_OnlyUtype = null unittype cs_dopt_IgnoreUtype = null integer cs_dopt_EnemyAlly = 0 //[ 0 = onlyenemies, 1= forceall, 2=onlyallies] integer cs_dopt_dfab1 = 'null' real cs_dopt_dfab1_fc = 1.0 integer cs_dopt_dfab2 = 'null' real cs_dopt_dfab2_fc = 1. integer cs_dopt_dfab3 = 'null' real cs_dopt_dfab3_fc = 1. real cs_dopt_Ally_fc = 1. endglobals function DamageTypes takes attacktype attT, damagetype dmgT returns integer // set udg_castervars[100] = CS_H2I(attT) // set udg_castervars[101] = CS_H2I(dmgT) set cs_dopt_Atype=attT set cs_dopt_Dtype=dmgT return 1 endfunction function DamageException takes unittype Exception, real ExceptionFactor returns integer set cs_dopt_ExceptionUtype=Exception set cs_dopt_ExceptionFct = ExceptionFactor // set udg_castervars[102] = CS_H2I(Exception) // set udg_castervars[103] = ExceptionFactor return 2 endfunction function DamageOnlyTo takes unittype ThisUnitType returns integer set cs_dopt_OnlyUtype = ThisUnitType // set udg_castervars[104] = CS_H2I(ThisUnitType) return 4 endfunction constant function DontDamageSelf takes nothing returns integer return 8 endfunction constant function DamageTrees takes nothing returns integer return 16 endfunction constant function DamageOnlyVisibles takes nothing returns integer return 32 endfunction function DamageOnlyEnemies takes nothing returns integer set cs_dopt_EnemyAlly=0 // ouch, forgot what it was return 64 endfunction function ForceDamageAllies takes nothing returns integer set cs_dopt_EnemyAlly=1 return 64 endfunction function DamageOnlyAllies takes nothing returns integer set cs_dopt_EnemyAlly=2 return 64 endfunction function DamageFactorAbility1 takes integer spellid, real factor returns integer set cs_dopt_dfab1=spellid set cs_dopt_dfab1_fc=factor // set udg_castervars[106]=CS_Rawcode2Real(spellid) // set udg_castervars[107]=factor return 128 endfunction function DamageFactorAbility2 takes integer spellid, real factor returns integer set cs_dopt_dfab2=spellid set cs_dopt_dfab2_fc=factor // set udg_castervars[108]=CS_Rawcode2Real(spellid) // set udg_castervars[109]=factor return 256 endfunction function DamageFactorAbility3 takes integer spellid, real factor returns integer set cs_dopt_dfab3=spellid set cs_dopt_dfab3_fc=factor //set udg_castervars[110]=CS_Rawcode2Real(spellid) // set udg_castervars[111]=factor return 512 endfunction function DamageIgnore takes unittype ThisUnitType returns integer set cs_dopt_IgnoreUtype = ThisUnitType // set udg_castervars[112] = CS_H2I(ThisUnitType) return 1024 endfunction function DamageAlliedFactor takes real fct returns integer set cs_dopt_Ally_fc = fct // set udg_castervars[113] = fct return 2048 endfunction constant function ConsiderOnlyDeadUnits takes nothing returns integer return 4096 endfunction constant function IgnoreDeadState takes nothing returns integer return 8192 endfunction //=============================================================================================== function IsDamageOptionIncluded takes integer DamageOptions, integer whichDamageOption returns boolean local integer i=8192 if (DamageOptions==0) then return false endif loop exitwhen (i<=whichDamageOption) if (DamageOptions>=i) then set DamageOptions=DamageOptions-i endif set i=i/2 endloop return (DamageOptions>=whichDamageOption) endfunction //================================================================================================= globals unit cs_dmg_caster=null endglobals function GetDamageFactor takes unit u,attacktype a, damagetype d returns real local real hp=GetWidgetLife(u) local real mana=GetUnitState(u,UNIT_STATE_MANA) local real r //Since a unit is in that point, we don't need checks. call SetUnitX(cs_dmg_caster,GetUnitX(u)) call SetUnitY(cs_dmg_caster,GetUnitY(u)) call SetUnitOwner(cs_dmg_caster,GetOwningPlayer(u),false) set r=hp if (hp<1) then call SetWidgetLife(u,1) set r=1 endif call UnitDamageTarget(cs_dmg_caster,u,0.01,true,false,a,d,null) call SetUnitOwner(cs_dmg_caster,Player(15),false) if (mana>GetUnitState(u,UNIT_STATE_MANA)) then //Unit had mana shield, return 1 and restore mana too. call SetUnitState(u,UNIT_STATE_MANA,mana) set r=1 else set r= (r-GetWidgetLife(u))*100 endif call SetWidgetLife(u,hp) return r endfunction //====================================================================================================== // Fix for the unit type bugs from blizzard, amphibious units aren't considered ground for some reason // so this considers any non flying unit as ground. // // Also heroes are resistant too, so in case UNIT_TYPE_RESISTANT is used it will return true in case the // unit is a hero too. // function CS_IsUnitType takes unit u, unittype ut returns boolean if (ut==UNIT_TYPE_GROUND) then return not(IsUnitType(u,UNIT_TYPE_FLYING)) elseif (ut==UNIT_TYPE_RESISTANT) then return IsUnitType(u,ut) or IsUnitType(u,UNIT_TYPE_HERO) endif return IsUnitType(u,ut) endfunction function GetDamageFactorByOptions takes unit hurter, unit target, integer d returns real local real r=1 if (d>=8192) then set d=d-8192 elseif (d>=4096) then if (GetWidgetLife(target)>0.405) then return 0.0 endif set d=d-4096 elseif (GetWidgetLife(target)<=0.405) then return 0.0 endif if d>=2048 then if IsUnitAlly(target,GetOwningPlayer(hurter)) then set r=r* cs_dopt_Ally_fc endif set d=d-2048 endif if d>=1024 then if CS_IsUnitType(target, cs_dopt_IgnoreUtype ) then return 0.0 endif set d=d-1024 endif if d>=512 then if GetUnitAbilityLevel(target, cs_dopt_dfab1 )>0 then set r=r*cs_dopt_dfab1_fc endif set d=d-512 endif if d>=256 then if GetUnitAbilityLevel(target, cs_dopt_dfab2 )>0 then set r=r*cs_dopt_dfab2_fc endif set d=d-256 endif if d>=128 then if GetUnitAbilityLevel(target, cs_dopt_dfab3 )>0 then set r=r*cs_dopt_dfab3_fc endif set d=d-128 endif if d>=64 then if (cs_dopt_EnemyAlly==0) and IsUnitAlly(target,GetOwningPlayer(hurter)) then return 0.0 elseif (cs_dopt_EnemyAlly==2) and IsUnitEnemy(target,GetOwningPlayer(hurter)) then return 0.0 endif set d=d-64 endif if d>=32 then set d=d-32 if not IsUnitVisible(target,GetOwningPlayer(hurter)) then return 0.0 endif endif if d>=16 then set d=d-16 endif if d>=8 then set d=d-8 if hurter==target then return 0.0 endif endif if d>=4 then set d=d-4 if not CS_IsUnitType( target,cs_dopt_OnlyUtype) then return 0.0 endif endif if d>=2 then set d=d-2 if CS_IsUnitType( target, cs_dopt_ExceptionUtype ) then set r=r* cs_dopt_ExceptionFct endif endif if d>=1 then set d=d-1 set r=r*GetDamageFactor(target,cs_dopt_Atype,cs_dopt_Dtype) endif return r endfunction //====================================================================================================================== // This used to be needed because in 1.17 UnitDamageTarget didn't consider the damagetype argument, this bug // was fixed in 1.18, and we no longer need this function, left for compatibility. // function DamageUnitByTypes takes unit hurter, unit target, real dmg, attacktype attT, damagetype dmgT returns boolean return UnitDamageTarget(hurter,target,dmg,true,false,attT,dmgT,null) endfunction //! define DamageUnitByTypes(h,t,d,a,dmt) UnitDamageTarget(h,t,d,true,false,a,dmt,null) //============================================================================================================================= function DamageUnitByOptions takes unit hurter, unit target, real dmg, integer DamageOptions returns boolean local real f=GetDamageFactorByOptions(hurter,target,DamageOptions) if (f==0) then return false endif return UnitDamageTarget(hurter,target,dmg*f,true,false,null,null,null) endfunction //============================================================================================================================= function DamageUnit takes player hurter, real damage, unit victim returns boolean call SetUnitX(cs_dmg_caster,GetUnitX(victim)) call SetUnitY(cs_dmg_caster,GetUnitY(victim)) call SetUnitOwner(cs_dmg_caster,hurter,false) call DamageUnitByTypes(cs_dmg_caster,victim,damage,cs_DefaultAttackType,cs_DefaultDamageType) call SetUnitOwner(cs_dmg_caster,Player(15),false) return GetWidgetLife(victim)<=0 // I thought UnitDamageTarget returned true when it killed the unit, but nope, it returns true when it was able to do the damage. endfunction //==================================================================================================================================================================== function UnitDamageUnitTimed_Child takes nothing returns nothing local real damage = udg_castervars[0] local real damageperiod= udg_castervars[2] local effect fx=bj_lastCreatedEffect local timer t=NewTimer() local unit hurter=udg_currenthurter local real next=0 local integer i=0 local real c local unit target=udg_currentcaster local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[4])) local attacktype attT=ConvertAttackType(R2I(udg_castervars[3])) call TimerStart(t, udg_castervars[1]-0.01, false,null) loop if TimerGetElapsed(t) >= next then exitwhen not UnitDamageTarget(hurter, target, damage,true,false, attT, dmgT,null) exitwhen GetWidgetLife(target)<=0.405 set i=i+1 set next=i*damageperiod endif exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405 call TriggerSleepAction(0) endloop call DestroyEffect(fx) call ReleaseTimer(t) set fx=null set dmgT=null set attT=null endfunction function UnitDamageUnitTimed takes unit hurter, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName, attacktype attT, damagetype dmgT returns nothing local unit c=udg_currentcaster set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName ) set udg_currentcaster=target set udg_castervars[0]=damageps set udg_castervars[1]=duration set udg_castervars[2]=damageperiod set udg_castervars[3]=CS_H2I(attT) set udg_castervars[4]=CS_H2I(dmgT) set udg_currenthurter=hurter call ExecuteFunc("UnitDamageUnitTimed_Child") set udg_currentcaster=c set c=null endfunction //============================================================================================================= // Left for compatibility // function DamageUnitTimedEx_Child takes nothing returns nothing local real damage = udg_castervars[0] local real damageperiod= udg_castervars[2] local effect fx=bj_lastCreatedEffect local timer t=NewTimer() local integer id=udg_currentabi local real next=0 local integer i=0 local real c local unit target=udg_currentcaster call TimerStart(t, udg_castervars[1]-0.01, false,null) loop if TimerGetElapsed(t) >= next then exitwhen DamageUnit( Player(id), damage, target) set i=i+1 set next=i*damageperiod endif exitwhen (TimerGetRemaining(t) <= 0) or GetWidgetLife(target)<=0.405 call TriggerSleepAction(0) endloop call DestroyEffect(fx) call ReleaseTimer(t) set fx=null endfunction function DamageUnitTimedEx takes player owner, real damageps, real damageperiod, real duration, unit target, string modelpath, string attachPointName returns nothing local unit c=udg_currentcaster set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, target,attachPointName ) set udg_currentcaster=target set udg_castervars[0]=damageps set udg_castervars[1]=duration set udg_castervars[2]=damageperiod set udg_currentabi=GetPlayerId( owner ) call ExecuteFunc("DamageUnitTimedEx_Child") set udg_currentcaster=c set c=null endfunction function DamageUnitTimed takes player owner, real damageps, real duration, unit target, string modelpath, string attachPointName returns nothing call DamageUnitTimedEx(owner , damageps, 1, duration, target, modelpath, attachPointName ) endfunction //[ function SetDamageOptions_i takes integer k, integer DamageOptions returns nothing local integer d=DamageOptions call SetArrayInt(k,0,d) //[0=value] if (d>=8192) then set d=d-8192 endif if (d>=4096) then set d=d-4096 endif if d>=2048 then call SetArrayReal(k,14, cs_dopt_Ally_fc ) //[14=allf] set d=d-2048 endif if d>=1024 then call SetArrayObject(k,13, cs_dopt_IgnoreUtype ) //[13=ign] set d=d-1024 endif if d>=512 then call SetArrayInt(k,11, cs_dopt_dfab3 ) //[11=ab3] call SetArrayReal(k,12, cs_dopt_dfab3_fc ) //[12=fc3] set d=d-512 endif if d>=256 then call SetArrayInt(k,9, cs_dopt_dfab2 ) //[9=ab2] call SetArrayReal(k,10, cs_dopt_dfab2_fc ) //[10=fc2] set d=d-256 endif if d>=128 then call SetArrayInt(k,7, cs_dopt_dfab1 ) //[7=ab1] call SetArrayReal(k,8, cs_dopt_dfab1_fc ) //[8=fc1] set d=d-128 endif //[0 integer value][1 integer attT][2 integer dmgT][3 integer excp][4 real excf][5 integer only] //[6 integer allied][7 integer ab1][8 real fc1][9 integer ab2][10 real fc2][11 integer ab3][12 real fc3] //[13 integer ign][14 real allf] if d >= 64 then set d=d-64 call SetArrayInt(k,6,cs_dopt_EnemyAlly) //[6=allied] endif if d >= 32 then set d=d-32 endif if d >= 16 then set d=d-16 endif if d >= 8 then set d=d-8 endif if d >= 4 then call SetArrayObject(k,5,cs_dopt_OnlyUtype ) //[5=only] set d=d-4 endif if d >= 2 then call SetArrayObject(k,3, cs_dopt_ExceptionUtype ) //[3=excp] call SetArrayReal(k,4,cs_dopt_ExceptionFct) //[4=excf] set d=d-2 endif if d >= 1 then call SetArrayInt(k,1, CS_H2I(cs_dopt_Atype) ) //[1=Attt] call SetArrayInt(k,2, CS_H2I(cs_dopt_Dtype) ) //[2=dmgT] endif endfunction function SetDamageOptions takes integer id, integer DamageOptions returns nothing call SetDamageOptions_i(id,DamageOptions) endfunction //! define SetDamageOptions(i,d) SetDamageOptions_i(i,d) function CreateDamageOptions takes integer DamageOptions returns integer local integer n =NewArray(15,false) //I am sure this won't access any non-initialized value call SetDamageOptions_i(n,DamageOptions) return n endfunction function DestroyDamageOptions takes integer id returns nothing call DestroyArray(id) endfunction //! define DestroyDamageOptions(i) DestroyArray(i) function LoadDamageOptions takes integer id returns integer local integer opt=GetArrayInt(id,0) //[0=value] local integer v=opt if v>=8192 then set v=v-8192 endif if v>=4096 then set v=v-4096 endif if v>=2048 then set cs_dopt_Ally_fc = GetArrayReal(id,14) //[14=allf] set v=v-2028 endif if v>=1024 then set cs_dopt_IgnoreUtype = ConvertUnitType( GetArrayInt(id,13) ) //[13=ign] set v=v-1024 endif if v>=512 then set cs_dopt_dfab3 =GetArrayInt(id,11) //[11=ab3] set cs_dopt_dfab3_fc=GetArrayReal(id,12) //[12=fc3] set v=v-512 endif if v>=256 then set cs_dopt_dfab2 =GetArrayInt(id,9) //[9=ab2] set cs_dopt_dfab2_fc=GetArrayReal(id,10) //[10=fc2] set v=v-256 endif if v>=128 then set cs_dopt_dfab1 =GetArrayInt(id,7) //[7=ab1] set cs_dopt_dfab1_fc=GetArrayReal(id,8) //[8=fc1] set v=v-128 endif if v >= 64 then set v=v-64 set cs_dopt_EnemyAlly= GetArrayInt(id,6) //[6==allied] endif if v >= 32 then set v=v-32 endif if v >= 16 then set v=v-16 endif if v >= 8 then set v=v-8 endif //[0 integer value][1 integer attT][2 integer dmgT][3 integer excp][4 real excf][5 integer only] //[6 integer allied][7 integer ab1][8 real fc1][9 integer ab2][10 real fc2][11 integer ab3][12 real fc3] //[13 integer ign][14 real allf] if v >= 4 then set cs_dopt_OnlyUtype = ConvertUnitType( GetArrayInt(id,5)) //only set v=v-4 endif if v >= 2 then set cs_dopt_ExceptionUtype= ConvertUnitType(GetArrayInt(id,3)) //excp set cs_dopt_ExceptionFct=GetArrayReal(id,4) //excf set v=v-2 endif if v >= 1 then set cs_dopt_Atype= ConvertAttackType(GetArrayInt(id,1)) //aTTt set cs_dopt_Dtype= ConvertDamageType(GetArrayInt(id,2)) //dmgT endif return opt endfunction //================================================================================================== function IsDestructableTree_withcs takes destructable d returns boolean local boolean b local boolean i=IsDestructableInvulnerable(d) call CS_MoveUnit(cs_dmg_caster,GetWidgetX(d),GetWidgetY(d)) if i then call SetDestructableInvulnerable(d,false) endif call UnitAddAbility(cs_dmg_caster,cs_DamageTreeDetectorId) set b=(IssueTargetOrder(cs_dmg_caster,"eattree",d)) call UnitRemoveAbility(cs_dmg_caster,cs_DamageTreeDetectorId) if i then call SetDestructableInvulnerable(d,true) endif return b endfunction function IsDestructableTree takes destructable d returns boolean local string k=I2S(GetDestructableTypeId(d)) local boolean b if HaveStoredBoolean(cs_cache,"trees",k) then set b=GetStoredBoolean(cs_cache,"trees",k) return b else set b=IsDestructableTree_withcs(d) call StoreBoolean(cs_cache,"trees",k,b) endif return b endfunction //=============================================================================================== function DamageDestructablesInCircleEnum takes nothing returns nothing local destructable d=GetEnumDestructable() local unit u=udg_currentcaster if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) then call SetWidgetLife(d,GetWidgetLife(d)-udg_castervars[203]) endif set udg_currentcaster=u set u=null set d=null endfunction function DamageDestructablesInCircle takes real x, real y, real radius, real dmg returns nothing local rect r=Rect(x - radius,y - radius,x + radius,y + radius) set udg_castervars[200]=x set udg_castervars[201]=y set udg_castervars[202]=radius*radius set udg_castervars[203]=dmg call EnumDestructablesInRect(r,null,function DamageDestructablesInCircleEnum) call RemoveRect(r) set r=null endfunction function DamageDestructablesInCircleLoc takes location loc, real radius, real dmg returns nothing call DamageDestructablesInCircle(GetLocationX(loc),GetLocationY(loc),radius,dmg) endfunction function DamageTreesInCircleEnum takes nothing returns nothing local destructable d=GetEnumDestructable() if (GetWidgetLife(d)>0) and not(IsDestructableInvulnerable(d)) and ((Pow(GetDestructableX(d)-udg_castervars[200],2)+Pow(GetDestructableY(d)-udg_castervars[201],2)) <= udg_castervars[202]) and (IsDestructableTree(d)) then call KillDestructable(d) endif set d=null endfunction function DamageTreesInCircle takes real x, real y, real radius returns nothing local rect r=Rect(x - radius,y - radius,x + radius,y + radius) set udg_castervars[200]=x set udg_castervars[201]=y set udg_castervars[202]=radius*radius call EnumDestructablesInRect(r,null,function DamageTreesInCircleEnum) call RemoveRect(r) set r=null endfunction function DamageTreesInCircleLoc takes location loc, real radius returns nothing call DamageTreesInCircle(GetLocationX(loc),GetLocationY(loc),radius) endfunction function DamageUnitGroupEx takes unit hurter, real damage, group targetgroup, integer DamageOptions returns nothing local group affected local unit p if bj_wantDestroyGroup then set bj_wantDestroyGroup=false set affected=targetgroup else set affected=CreateGroup() call GroupAddGroup( targetgroup, affected) endif loop set p=FirstOfGroup(affected) exitwhen p==null call DamageUnitByOptions(hurter,p,damage,DamageOptions) call GroupRemoveUnit(affected,p) endloop call DestroyGroup(affected) set affected=null set p=null endfunction function DamageUnitsInAOEEx takes unit hurter, real damage, real x, real y, real radius, boolean affectallied, integer DamageOptions returns nothing local boolexpr b=null local group aoe=CreateGroup() local integer d=DamageOptions set bj_groupEnumOwningPlayer=GetOwningPlayer(hurter) if d>=8192 then set d=d-8192 endif if d>=4096 then set d=d-4096 endif if d>=2048 then set d=d-2048 endif if d>=1024 then set d=d-1024 endif if d>=512 then set d=d-512 endif if d>=256 then set d=d-256 endif if d>=128 then set d=d-128 endif if d>=64 then if (cs_dopt_EnemyAlly==2) then set b=Condition(function CasterAOE_IsFilterAlly) elseif (cs_dopt_EnemyAlly==1) then else set b=Condition(function CasterAOE_IsFilterEnemy) endif set d=d-64 elseif not(affectallied) then set b=Condition(function CasterAOE_IsFilterEnemy) endif if d>=32 then set d=d-32 endif if d>=16 then call DamageTreesInCircle(x,y,radius) endif call CS_EnumUnitsInAOE(aoe, x,y, radius, b) set bj_wantDestroyGroup=true call DamageUnitGroupEx( hurter, damage, aoe,DamageOptions) call DestroyBoolExpr(b) set b=null set aoe=null endfunction function DamageUnitsInAOEExLoc takes unit hurter, real damage, location loc, real radius, boolean affectallied, integer DamageOptions returns nothing call DamageUnitsInAOEEx(hurter,damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied,DamageOptions) endfunction //! define DamageUnitsInAOEExLoc(h,d,l,r,a,do) DamageUnitsInAOEEx(h,d,GetLocationX(l),GetLocationY(l),r,a,do) function DamageUnitGroup takes player hurter, real damage, group targetgroup returns nothing call SetUnitOwner(cs_dmg_caster,hurter,false) call DamageUnitGroupEx(cs_dmg_caster,damage,targetgroup,0) call SetUnitOwner(cs_dmg_caster,Player(15),false) endfunction //==================================================================================================================================================================== function DamageUnitsInAOE takes player hurter, real damage, real x, real y, real radius, boolean affectallied returns nothing call SetUnitOwner(cs_dmg_caster,hurter,false) call DamageUnitsInAOEEx(cs_dmg_caster,damage,x,y,radius,affectallied,0) call SetUnitOwner(cs_dmg_caster,Player(15),false) endfunction function DamageUnitsInAOELoc takes player hurter, real damage, location loc, real radius, boolean affectallied returns nothing call DamageUnitsInAOE( hurter, damage, GetLocationX(loc), GetLocationY(loc), radius, affectallied) endfunction //! define DamageUnitsInAOELoc(h,d,l,r,a) DamageUnitsInAOEEx(h,d,GetLocationX(l),GetLocationY(l),r,a) //==================================================================================================================================================================== function AddAreaDamagerForUnit_Child takes nothing returns nothing local real D local real damageps = udg_castervars[0] local real area = udg_castervars[2] local real damageperiod = udg_castervars[3] local real excd=udg_castervars[8] local boolean affectallies = (udg_castervars[4]>=1) local boolean onlyallies = (udg_castervars[4]==2) local boolean self = (udg_castervars[5]==1) local unit hurter=udg_currenthurter local unit fire = udg_currentcaster local player owner = GetOwningPlayer(fire) local timer t = NewTimer() local real next = 0 local integer a = 0 local group inrange = CreateGroup() local string c local string art=bj_lastPlayedMusic local string attach="" local unit picked local boolean recicled=false local unittype only=null local unittype ign=null local unittype exce=null local attacktype attT local damagetype dmgT local boolean trees=(udg_castervars[11]==1) local boolean inv=(udg_castervars[12]==1) local integer a1=0 local integer a2=0 local integer a3=0 local real f1=udg_castervars[107] local real f2=udg_castervars[109] local real f3=udg_castervars[111] local real allf=udg_castervars[113] local effect array fx local integer deadcond=R2I(udg_castervars[114]) local boolean deadeval=false local integer fxn=0 set fx[0]=bj_lastCreatedEffect if f1!=1 then set a1=CS_LoadRawcodeFromReal(106) endif if f2!=1 then set a2=CS_LoadRawcodeFromReal(108) endif if f3!=1 then set a3=CS_LoadRawcodeFromReal(110) endif if udg_castervars[112]!=-1 then set ign=ConvertUnitType(R2I(udg_castervars[112])) endif if udg_castervars[6]!=-1 then set only=ConvertUnitType(R2I(udg_castervars[6])) endif if udg_castervars[7]!=-1 then set exce=ConvertUnitType(R2I(udg_castervars[7])) endif if udg_castervars[9]!=-1 then set attT=ConvertAttackType(R2I(udg_castervars[9])) else set attT=cs_DefaultAttackType endif if udg_castervars[10]!=-1 then set dmgT=ConvertDamageType(R2I(udg_castervars[10])) else set dmgT=cs_DefaultDamageType endif loop set c=SubString(art,a,a+1) exitwhen c=="!" or c=="" set attach=attach+c set a=a+1 endloop set art=SubString(art,a+1,10000) call TimerStart(t, udg_castervars[1]-0.01, false,null) set a=0 loop loop exitwhen fxn<=0 call DestroyEffect(fx[fxn]) set fx[fxn]=null set fxn=fxn-1 endloop if IsUnitInGroup( fire, udg_casters) then set recicled=true call GroupRemoveUnit( udg_casters,fire) endif exitwhen recicled if TimerGetElapsed(t) >= next then set a=a+1 set next=a*damageperiod call CS_EnumUnitsInAOE(inrange, GetUnitX(fire), GetUnitY(fire), area, null ) if trees then call DamageTreesInCircle(GetUnitX(fire), GetUnitY(fire), area) endif loop set picked=FirstOfGroup(inrange) exitwhen picked==null if (deadcond==0) then set deadeval=(GetWidgetLife(picked)>0.405) elseif(deadcond==1)then set deadeval=(GetWidgetLife(picked)<=0.405) else set deadeval=true endif if (self or picked!=hurter) and not(GetWidgetLife(picked)<=0.405) and ( ((affectallies or onlyallies) and IsUnitAlly(picked, owner)) or (not(onlyallies) and IsUnitEnemy(picked, owner)) ) and (only==null or CS_IsUnitType(picked,only)) and (ign==null or not(CS_IsUnitType(picked,ign))) then set D=damageps if (allf!=1) and IsUnitAlly(picked, owner) then set D=D*allf endif if (exce!=null) and CS_IsUnitType(picked,exce) then set D=D*excd endif if inv and not( IsUnitVisible(picked,owner)) then set D=0 endif if (a1!=0) and (GetUnitAbilityLevel(picked,a1)>0) then set D=D*f1 endif if (a2!=0) and (GetUnitAbilityLevel(picked,a2)>0) then set D=D*f2 endif if (a3!=0) and (GetUnitAbilityLevel(picked,a3)>0) then set D=D*f3 endif if D!=0 then call DamageUnitByTypes(hurter,picked,D,attT,dmgT ) if (art!="") and (art!=null) then set fxn=fxn+1 set fx[fxn]=AddSpecialEffectTarget(art,picked,attach) endif endif endif call GroupRemoveUnit(inrange,picked) endloop endif exitwhen TimerGetRemaining(t)<=0 call TriggerSleepAction(0) endloop call DestroyGroup(inrange) call DestroyEffect(fx[0]) call TriggerSleepAction(2) call RecicleCaster(fire) call ReleaseTimer(t) set inrange=null set fire=null set owner=null set fx[0]=null set picked=null set hurter=null set only=null set ign=null set exce=null set attT=null set dmgT=null endfunction function AddAreaDamagerForUnit takes unit hurter, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit local string s=bj_lastPlayedMusic local integer v=DamageOptions set bj_lastPlayedMusic=targetattach+"!"+targetart set udg_currentcaster=GetACaster() call SetUnitPosition( udg_currentcaster, x, y) set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" ) set udg_castervars[0]=damage set udg_castervars[1]=duration set udg_castervars[2]=area set udg_castervars[3]=damageperiod if(v>=8192)then set udg_castervars[114]=2 set v=v-8192 elseif (v>=4096)then set udg_castervars[114]=1 set v=v-4096 else set udg_castervars[114]=0 endif if v>=2048 then set v=v-2048 else set udg_castervars[113]=1 endif if v >= 1024 then set v=v-1024 else set udg_castervars[112]=-1 endif if v >= 512 then set v=v-512 else set udg_castervars[111]=0 endif if v >= 256 then set v=v-256 else set udg_castervars[109]=0 endif if v >= 128 then set v=v-128 else set udg_castervars[107]=0 endif if v >= 64 then set v=v-64 set udg_castervars[4]=cs_dopt_EnemyAlly else set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0) endif if v >= 32 then set udg_castervars[12]=1 set v=v-32 else set udg_castervars[12]=0 endif if v >= 16 then set udg_castervars[11]=1 set v=v-16 else set udg_castervars[11]=0 endif if v >= 8 then set udg_castervars[5]=0 set v=v-8 else set udg_castervars[5]=1 endif if v >= 4 then set udg_castervars[6]=CS_H2I(cs_dopt_OnlyUtype) set v=v-4 else set udg_castervars[6]=-1 endif if v >= 2 then set udg_castervars[7]=CS_H2I(cs_dopt_ExceptionUtype) set udg_castervars[8]=damage*cs_dopt_ExceptionFct set v=v-2 else set udg_castervars[7]=-1 set udg_castervars[8]=-1 endif if v >= 1 then set udg_castervars[9]= CS_H2I(cs_dopt_Atype) set udg_castervars[10]= CS_H2I(cs_dopt_Dtype) else set udg_castervars[9]=-1 set udg_castervars[10]=-1 endif set udg_currenthurter=hurter call SetUnitOwner( udg_currentcaster, GetOwningPlayer(hurter), true) call ExecuteFunc("AddAreaDamagerForUnit_Child") set bj_lastPlayedMusic=s return udg_currentcaster endfunction function AddAreaDamagerForUnitLoc takes unit hurter, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies, integer DamageOptions returns unit return AddAreaDamagerForUnit(hurter,modelpath,targetart,targetattach,GetLocationX(loc),GetLocationY(loc), damage , damageperiod, duration, area,affectallies, DamageOptions) endfunction function AddDamagingEffectEx takes player owner, string modelpath, string targetart, string targetattach, real x, real y, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit local string s=bj_lastPlayedMusic set bj_lastPlayedMusic=targetattach+"!"+targetart set udg_currentcaster=GetACaster() call SetUnitPosition( udg_currentcaster, x, y) set bj_lastCreatedEffect = AddSpecialEffectTarget( modelpath, udg_currentcaster,"origin" ) set udg_castervars[0]=damage set udg_castervars[1]=duration set udg_castervars[2]=area set udg_castervars[3]=damageperiod set udg_castervars[4]=IntegerTertiaryOp(affectallies,1,0) set udg_castervars[5]=1 set udg_castervars[6]=-1 set udg_castervars[7]=-1 set udg_castervars[8]=-1 set udg_castervars[9]=-1 set udg_castervars[10]=-1 set udg_castervars[107]=0 set udg_castervars[109]=0 set udg_castervars[111]=0 set udg_castervars[112]=-1 set udg_castervars[113]=1 set udg_currenthurter=udg_currentcaster call SetUnitOwner( udg_currentcaster, owner, true) call ExecuteFunc("AddAreaDamagerForUnit_Child") set bj_lastPlayedMusic=s return udg_currentcaster endfunction function AddDamagingEffectExLoc takes player owner, string modelpath, string targetart, string targetattach, location loc, real damage , real damageperiod, real duration, real area, boolean affectallies returns unit return AddDamagingEffectEx( owner, modelpath, targetart, targetattach, GetLocationX(loc), GetLocationY(loc), damage , damageperiod, duration, area, affectallies ) endfunction function AddDamagingEffect takes player owner, string modelpath, real x, real y, real damageps , real duration, real area, boolean affectallies returns unit return AddDamagingEffectEx( owner, modelpath, "", "", x, y, damageps , 1, duration, area, affectallies ) endfunction function AddDamagingEffectLoc takes player owner, string modelpath, location loc, real damageps , real duration, real area, boolean affectallies returns unit return AddDamagingEffectEx( owner, modelpath, "", "", GetLocationX(loc), GetLocationY(loc), damageps ,1, duration, area, affectallies) endfunction //============================================================================================================ function UnitMoveToAsProjectileAnySpeed_Move takes unit m, csprojectile k returns boolean local boolean tounit = k.tounit local unit tg local real x2 local real y2 local real z2 local real x1=GetUnitX(m) local real y1=GetUnitY(m) local real z1=GetUnitFlyHeight(m) local real g local real d local real od local real v local real time local integer n local boolean done=false local effect fx if tounit then set tg=k.target if (GetWidgetLife(tg)<=0.405) then set tounit=false set k.tounit=false else set x2=GetUnitX(tg) set y2=GetUnitY(tg) set z2=GetUnitFlyHeight(tg)+k.z2o set n=k.N if (n==0) then //Using the counter prevents us to save z2,x2,y2 too much times and saves speed set k.z2=z2 set k.x2=x2 // Backup stuff just in case set k.y2=y2 elseif (n==25) then set n=0 else set n=n+1 endif set k.N=n endif set tg=null endif if not(tounit) then set z2=k.z2 set x2=k.x2 set y2=k.y2 endif set g=Atan2(y2-y1,x2-x1) call SetUnitFacing(m,g*bj_RADTODEG) set v=k.speed set d= v * cs_TIMER_CYCLE set od=SquareRoot(Pow(x1-x2,2) + Pow(y1-y2,2)) if( od <=d )then call CS_MoveUnit(m , x2, y2 ) set done=true else call CS_MoveUnit(m , x1+d*Cos(g), y1+d*Sin(g) ) endif set g=k.acel set time= od / v set d=v set v=(z2-z1+0.5*g*time*time)/time //z speed if (GetUnitTypeId(m)==cs_CasterUnitId) then call SetUnitAnimationByIndex(m,R2I(Atan2(v,d)* bj_RADTODEG)+90) //Thanks infrane! endif call SetUnitFlyHeight(m,z1+v*cs_TIMER_CYCLE,0) set d=( Pow(GetUnitX(m)-x2,2) + Pow(GetUnitY(m)-y2,2) ) if (done or (d<=400)) then //So the actual distance is less than or equal to 20 set done=true set k.done=true set fx=k.fx if (fx!=null) then call SetUnitAnimationByIndex(m,91) call DestroyEffect(fx) set fx=null endif endif return done endfunction interface csmissile integer mtype=0 unit m //the missile endinterface globals constant integer cs_TYPE_COLLISIONMISSILE=2 constant integer cs_TYPE_PROJECTILE=1 endglobals struct cscollisionmissile extends csmissile integer state //state of the collision missile trigger t triggeraction ac real collision real speed real aspeed //angle speed real f //facing of collisionmissile real maxd integer ttype=0 //target type static constant integer ttype_widget=2 static constant integer ttype_point=1 static constant integer ttype_none=0 real tx //homing target x real ty //homing target y widget tw //homing target widget boolean pfx=false //periodic fx mode real pfx_current //current pfx (timer) real pfx_dur //duration of a periodic effect string pfx_path //path for the periodix fx boolean new //Was it a new collision missile or must be recycled? effect fx integer tag=0 //A tag for the user! endstruct function CollisionMissile_Destroyer takes unit m, cscollisionmissile k, trigger T returns nothing local trigger tr = T local triggeraction ta = k.ac if (k.fx!=null) then call DestroyEffect(k.fx) endif if (k.new) then call ExplodeUnitBJ(m) else call RecicleCasterAfterCastEx(m,4,0,true) endif call TriggerRemoveAction(tr,ta) //call TriggerRemoveAction(T,GetArrayTriggerAction(k,18)) //[18=triggeraction] call k.destroy() //call Hostage(CS_H2I(tr)) call DestroyTrigger(tr) //call CleanAttachedVars(T) //call DestroyTrigger(T) set tr = null set ta = null endfunction function GetTriggerCollisionMissile takes nothing returns unit return s__csmissile_m[GetCSData(GetTriggeringTrigger()) ] endfunction function CollisionMissile_Move takes unit m, cscollisionmissile k returns boolean local integer state= k.state local boolean done local real d local real F local real asp local real x local real nx local real y local real ny local integer tt local widget wd local trigger TTT if (state==2) then set TTT=k.t call TriggerExecute(TTT) set TTT=null set k.state=3 return false elseif (state==3) then call CollisionMissile_Destroyer(m,k,k.t) return true else if (state==1) then call TriggerRegisterUnitInRange(k.t,m,k.collision,null) set k.state=0 endif set d=k.speed * cs_TIMER_CYCLE set F=k.f set asp=k.aspeed set x=GetUnitX(m) set y=GetUnitY(m) if (asp!=0) then set tt=k.ttype if (tt==cscollisionmissile.ttype_point) or (tt==cscollisionmissile.ttype_widget ) then if (tt==cscollisionmissile.ttype_point) then set nx=k.tx set ny=k.ty set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE) else set wd=k.tw if (GetWidgetLife(wd)<=0.405) then set k.ttype=cscollisionmissile.ttype_none set nx=x+0.001 set ny=y+0.001 set F=F+ asp * cs_TIMER_CYCLE else set nx=GetWidgetX(wd) set ny=GetWidgetY(wd) set F=Angles_MoveAngleTowardsAngle(F,Atan2(ny-y,nx-x)*bj_RADTODEG, asp * cs_TIMER_CYCLE) endif set wd=null endif else set F=F+ asp * cs_TIMER_CYCLE endif set k.f=F call SetUnitFacing(m,F) endif set F=F*bj_DEGTORAD set nx=x+d*Cos(F) set ny=y+d*Sin(F) set d=k.maxd-d set k.maxd=d set done=(d<=0) if (not done) then if not(CS_MoveUnit(m,nx,ny)) then set done=true elseif (k.pfx) then set F= k.pfx_current+cs_TIMER_CYCLE if (F>=k.pfx_dur) then call DestroyEffect(AddSpecialEffectTarget(k.pfx_path, m, "origin" )) set k.pfx_current=0. else set k.pfx_current=F endif endif endif endif if done then call DisableTrigger(k.t) call DestroyEffect(k.fx) set k.fx=null set k.state=2 return false endif return false endfunction function CasterSystemMovementTimer takes nothing returns nothing local timer ti local integer n=cs_missilecount local integer i=1 local unit p local csmissile k loop exitwhen (i>n) set k=cs_missiles[i] if (k.mtype==cs_TYPE_COLLISIONMISSILE) then set p=k.m if not(CollisionMissile_Move(p,k)) then set i=i+1 else set cs_missiles[i]=cs_missiles[n] set n=n-1 endif elseif (k.mtype==cs_TYPE_PROJECTILE) then set p=k.m if not(UnitMoveToAsProjectileAnySpeed_Move(p,k )) then set i=i+1 else set cs_missiles[i]=cs_missiles[n] set n=n-1 endif else set i=i+1 call BJDebugMsg("Caster System: Unexpected Error (1) Wrong Array:"+I2S(k)+" ; "+I2S(k.mtype)) endif endloop if (n==0) then call PauseTimer(cs_movementtimer) set cs_movementtimer_active=false endif set cs_missilecount=n set p=null endfunction struct csprojectile extends csmissile boolean tounit //Is it directed towards a unit? unit target //if so, what target? real z2 real x2 real y2 real speed real acel boolean done=false effect fx real z2o // offset for z2, useful for flyers integer N=0 endstruct function UnitMoveToAsProjectileAnySpeed_Effect takes unit m, effect fx, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing // // The internal projectile system used by all the projectile functions // local timer t //=GetTableTimer("CasterSystem","MOVEMENT_TIMER") local string km local csprojectile k set km=I2S(CS_H2I(m)) set k=GetTableInt("MOVEMENT_TABLES",km) if (k>0) then set k.done=true endif set k=csprojectile.create() set k.m=m call StoreInteger(cs_cache,"MOVEMENT_TABLES",km,k) set cs_missilecount=cs_missilecount+1 set cs_missiles[cs_missilecount]=k if (not cs_movementtimer_active) then call TimerStart(cs_movementtimer,cs_TIMER_CYCLE,true,function CasterSystemMovementTimer) set cs_movementtimer_active=true endif set k.mtype=cs_TYPE_PROJECTILE if (target!=null) then set k.tounit=true set k.target=target set k.x2=GetUnitX(target) set k.y2=GetUnitY(target) set k.z2o=z2 else set k.tounit=false set k.x2=x2 set k.y2=y2 endif set k.z2=z2 set k.speed=speed set k.acel=arc*8000 if (fx!=null) then set k.fx=fx set fx=null endif loop exitwhen k.done call TriggerSleepAction(0) endloop call FlushStoredInteger(cs_cache,"MOVEMENT_TABLES",km) call k.destroy() endfunction function UnitMoveToAsProjectileAnySpeed takes unit m, real speed, real arc, real x2, real y2, unit target, real z2 returns nothing //Left for compat call UnitMoveToAsProjectileAnySpeed_Effect(m,null,speed,arc,x2,y2,target,z2) endfunction //======================================================================================================================== function UnitMoveToAsProjectileGen takes unit m, real arc, real x2, real y2, unit target, real z2 returns nothing // // The internal projectile system used by all the projectile functions // local real x1=GetUnitX(m) local real y1=GetUnitY(m) local real acel=arc*1600 local real speed=GetUnitMoveSpeed(m) local real z1=GetUnitFlyHeight(m) local real d local real d1 local real d2 local real t local real vel local real dif=0 local boolean tounit= (target!=null) local boolean b=false local boolean mode=false if tounit then set x2=GetUnitX(target) set y2=GetUnitY(target) set z2=GetUnitFlyHeight(target)+z2 endif set mode=(z2>z1) set d=SquareRoot(Pow(x2-x1,2)+Pow(y2-y1,2)) set d1=1000000 set d2=0 set t=d/speed if t==0 then set t=0.001 endif set vel=(z2-z1+0.5*acel*t*t)/t call SetUnitFacing( m, Atan2BJ(y2 - y1, x2 - x2) ) call IssuePointOrder( m, "move", x2,y2) set t=0 loop set d2=d1 if tounit then if (GetWidgetLife(target)<=0.405) then set tounit=false else set x2=GetUnitX(target) set y2=GetUnitY(target) endif endif set d1=SquareRoot(Pow(x2-GetUnitX(m),2)+Pow(y2-GetUnitY(m),2)) exitwhen b or d1==0 set b=(d1<=speed*(t-dif)) exitwhen (mode and b) or (GetUnitCurrentOrder(m) != OrderId("move")) if tounit then call IssuePointOrder( m, "move", x2,y2) endif set dif=t if dif==0.001 then set t=0.1 else set t= (d-d1)/speed endif set t= 2*t-dif call SetUnitFlyHeight( m, z1+(vel*t-0.5*acel*t*t), RAbsBJ( vel-acel*(t+dif)/2) ) set t=(t+dif)/2 call TriggerSleepAction(0) endloop if tounit then set x2=GetUnitX(target) set y2=GetUnitY(target) endif call SetUnitFlyHeight( m,z2,0) call CS_MoveUnit(m,x2,y2) endfunction function UnitMoveToAsProjectile takes unit m, real arc, real x2, real y2, real z2 returns nothing call UnitMoveToAsProjectileGen(m, arc,x2,y2,null,z2) endfunction //============================================================================================================ function ProjectileLaunchEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1),x1,y1 ) local effect fx=null call SetUnitScale( m, scale, scale, scale) call SetUnitVertexColor(m, red, green, blue, alpha) call SetUnitFlyHeight( m, z1, 0) set fx= AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, owner, true) if (speed<=522) then call SetUnitMoveSpeed(m, speed) call UnitMoveToAsProjectile(m, arc, x2, y2, z2) call DestroyEffect(fx) else call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed,arc,x2,y2,null,z2) endif call ExplodeUnitBJ(m) set owner=null set fx=null set m=null endfunction function ProjectileLaunchExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing call ProjectileLaunchEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc,GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2) endfunction //============================================================================================================ function ProjectileLaunch takes string modelpath, real speed, real arc,real x1, real y1, real z1, real x2, real y2, real z2 returns nothing call ProjectileLaunchEx( Player(15), modelpath, 1, 255, 255, 255, 255, speed, arc,x1,y1,z1,x2,y2,z2) endfunction function ProjectileLaunchLoc takes string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns nothing call ProjectileLaunchExLoc( Player(15), modelpath, 1,255,255,255,255,speed,arc,loc1,z1,loc2,z2) endfunction //============================================================================================================ function DamagingProjectileLaunchAOE_Child takes nothing returns nothing local unit m=udg_currentcaster local effect fx=bj_lastCreatedEffect local real x2=udg_castervars[0] local real y2=udg_castervars[1] local real aoeradius=udg_castervars[3] local real damage=udg_castervars[4] local boolean affectallied=bj_isUnitGroupInRectResult local integer V=CreateDamageOptions(R2I(udg_castervars[5])) local unit hurter=udg_currenthurter local real speed=udg_castervars[6] if (speed<=522) then call SetUnitMoveSpeed(m, speed) call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2]) call DestroyEffect(fx) else call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed,bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1],null, udg_castervars[2]) endif call DamageUnitsInAOEEx(hurter,damage,x2,y2,aoeradius,affectallied,LoadDamageOptions(V)) call DestroyDamageOptions(V) call ExplodeUnitBJ(m) set m=null set fx=null endfunction function DamagingProjectileLaunchAOE takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1) ,x1,y1) call SetUnitFlyHeight( m, z1, 0) set udg_currentcaster=m set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, GetOwningPlayer(hurter), true) set bj_meleeNearestMineDist = arc set udg_castervars[0] = x2 set udg_castervars[1] = y2 set udg_castervars[2] = z2 set udg_castervars[3] =aoeradius set udg_castervars[4] =damage set udg_castervars[5] =DamageOptions set udg_castervars[6] =speed set udg_currenthurter=hurter set bj_isUnitGroupInRectResult=affectallied call ExecuteFunc("DamagingProjectileLaunchAOE_Child") set m=null return udg_currentcaster endfunction function DamagingProjectileLaunchAOELoc takes unit hurter, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied, integer DamageOptions returns unit return DamagingProjectileLaunchAOE(hurter,modelpath,speed,arc,GetLocationX(loc1),GetLocationY(loc1),z1,GetLocationX(loc2),GetLocationY(loc2),z2, aoeradius, damage, affectallied, DamageOptions ) endfunction function ProjectileLaunchDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2, real aoeradius, real damage, boolean affectallied returns unit local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1) ,x1,y1 ) call SetUnitFlyHeight( m, z1, 0) set udg_currentcaster=m set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, owner, true) set bj_meleeNearestMineDist = arc set udg_castervars[0] = x2 set udg_castervars[1] = y2 set udg_castervars[2] = z2 set udg_castervars[3] =aoeradius set udg_castervars[4] =damage set udg_castervars[5] =0 set udg_castervars[6]= speed set bj_isUnitGroupInRectResult=affectallied set udg_currenthurter=m call ExecuteFunc("DamagingProjectileLaunchAOE_Child") set m=null return udg_currentcaster endfunction function ProjectileLaunchDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2, real aoeradius, real damage, boolean affectallied returns unit return ProjectileLaunchDamage( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2, aoeradius, damage, affectallied) endfunction //============================================================================================================ function ProjectileLaunchKill_Child takes nothing returns nothing local unit m=udg_currentcaster local effect fx=bj_lastCreatedEffect local real x2=udg_castervars[0] local real y2=udg_castervars[1] local real speed=udg_castervars[3] if (speed<=522) then call SetUnitMoveSpeed( m, speed) call UnitMoveToAsProjectile(m, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], udg_castervars[2]) call DestroyEffect( fx) else call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, bj_meleeNearestMineDist, udg_castervars[0], udg_castervars[1], null, udg_castervars[2]) endif call ExplodeUnitBJ(m) set m=null set fx=null endfunction function ProjectileLaunchKill takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, real x2, real y2, real z2 returns unit local unit m=CreateCaster( Atan2BJ(y2 - y1, x2 - x1),x1,y1 ) call SetUnitFlyHeight( m, z1, 0) set udg_currentcaster=m set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, owner, true) set bj_meleeNearestMineDist = arc set udg_castervars[0] = x2 set udg_castervars[1] = y2 set udg_castervars[2] = z2 set udg_castervars[3] = speed call ExecuteFunc("ProjectileLaunchKill_Child") set m=null return udg_currentcaster endfunction function ProjectileLaunchKillLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, location loc2, real z2 returns unit return ProjectileLaunchKill( owner, modelpath, speed, arc, GetLocationX(loc1), GetLocationY(loc1), z1, GetLocationX(loc2), GetLocationY(loc2), z2) endfunction //==================================================================================================================================================================== function UnitMoveToUnitAsProjectile takes unit m, real arc, unit target, real zoffset returns nothing call UnitMoveToAsProjectileGen(m, arc,0,0,target,zoffset) endfunction //==================================================================================================================================================================== function ProjectileLaunchToUnitEx takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset returns nothing local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 ) local effect fx=null call SetUnitFlyHeight( m, z1, 0) call SetUnitScale( m, scale, scale, scale) call SetUnitVertexColor(m, red, green, blue, alpha) set fx=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m , owner, true) if (speed<=522) then call SetUnitMoveSpeed( m, speed) call UnitMoveToUnitAsProjectile(m,arc,target, zoffset) call DestroyEffect(fx) else call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, arc,0,0,target,zoffset) endif call ExplodeUnitBJ(m) set m=null set fx=null endfunction function ProjectileLaunchToUnitExLoc takes player owner, string modelpath, real scale, integer red, integer green, integer blue, integer alpha, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing call ProjectileLaunchToUnitEx( owner, modelpath, scale, red, green, blue, alpha, speed, arc, GetLocationX(loc1),GetLocationY(loc1), z1, target, zoffset) endfunction function ProjectileLaunchToUnit takes string modelpath, real speed, real arc,real x1, real y1, real z1, unit target, real zoffset returns nothing call ProjectileLaunchToUnitEx( Player(15), modelpath, 1, 255,255,255,255,speed,arc,x1,y1,z1,target,zoffset) endfunction function ProjectileLaunchToUnitLoc takes string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset returns nothing call ProjectileLaunchToUnitExLoc( Player(15), modelpath, 1, 255,255,255,255, speed, arc, loc1, z1, target,zoffset) endfunction //==================================================================================================================================================================== function DamagingProjectileLaunchTarget_Child takes nothing returns nothing local unit m=udg_currentcaster local unit target=bj_meleeNearestMine local effect fx=bj_lastCreatedEffect local real damage=udg_castervars[4] local damagetype dmgT=ConvertDamageType(R2I(udg_castervars[6])) local attacktype attT=ConvertAttackType(R2I(udg_castervars[5])) local unit hurter=udg_currenthurter local real speed=udg_castervars[7] if (speed<=522) then call SetUnitMoveSpeed( m, speed) call UnitMoveToUnitAsProjectile(m, bj_meleeNearestMineDist, target, udg_castervars[2]) call DestroyEffect( fx) else call UnitMoveToAsProjectileAnySpeed_Effect(m,fx,speed, bj_meleeNearestMineDist,0,0,target,udg_castervars[2]) endif call DamageUnitByTypes(hurter,target,damage,attT,dmgT) call ExplodeUnitBJ(m) set m=null set hurter=null set target=null set fx=null set dmgT=null set attT=null endfunction function DamagingProjectileLaunchTarget takes unit hurter, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 ) set udg_castervars[7]=speed call SetUnitFlyHeight( m, z1, 0) set udg_currentcaster=m set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, GetOwningPlayer(hurter), true) set bj_meleeNearestMineDist = arc set udg_castervars[2]= zoffset set bj_meleeNearestMine=target set udg_castervars[4]=damage set udg_castervars[5]=CS_H2I(attT) set udg_castervars[6]=CS_H2I(dmgT) set udg_currenthurter=hurter call ExecuteFunc("DamagingProjectileLaunchTarget_Child") set m=null return udg_currentcaster endfunction function DamagingProjectileLaunchTargetLoc takes unit hurter, string modelpath, real speed, real arc, location loc, real z1, unit target, real zoffset, real damage, attacktype attT, damagetype dmgT returns unit return DamagingProjectileLaunchTarget(hurter,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc), z1, target, zoffset, damage, attT, dmgT) endfunction //! define DamagingProjectileLaunchTargetLoc(h,m,s,a,L,z1,target,zoffset,damage,att,dtt) DamagingProjectileLaunchTarget(h,m,s,a,GetLocationX(L),GetLocationY(L),z1,target,zoffset,damage,att,dtt) function ProjectileLaunchToUnitDamage takes player owner, string modelpath, real speed, real arc, real x1, real y1, real z1, unit target, real zoffset, real damage returns unit local unit m=CreateCaster( Atan2BJ(GetUnitY(target) - y1, GetUnitX(target) - x1),x1,y1 ) set udg_castervars[7]=speed call SetUnitFlyHeight( m, z1, 0) set udg_currentcaster=m set bj_lastCreatedEffect=AddSpecialEffectTarget( modelpath, m,"origin" ) call SetUnitOwner( m, owner, true) set bj_meleeNearestMineDist = arc set udg_castervars[2]= zoffset set bj_meleeNearestMine=target set udg_castervars[4]=damage set udg_castervars[5]=CS_H2I(cs_DefaultAttackType) set udg_castervars[6]=CS_H2I(cs_DefaultDamageType) set udg_currenthurter=m call ExecuteFunc("DamagingProjectileLaunchTarget_Child") set m=null return udg_currentcaster endfunction function ProjectileLaunchToUnitDamageLoc takes player owner, string modelpath, real speed, real arc, location loc1, real z1, unit target, real zoffset, real damage returns unit return ProjectileLaunchToUnitDamage( owner, modelpath, speed, arc,GetLocationX(loc1),GetLocationY(loc1),z1,target,zoffset,damage) endfunction //! define ProjectileLaunchToUnitDamageLoc(owner,modelpath,speed,arc,loc1,z1,target,zoffset,damage) ProjectileLaunchToUnitDamage(owner,modelpath,speed,arc,GetLocationX(loc),GetLocationY(loc),z1,target,zoffset,damage) //============================================================================================================================================================================== // Caster System Class: CollisionMissile // function CollisionMissile_Destroy takes unit m returns nothing local cscollisionmissile k=GetUnitUserData(m) if (k.fx!=null) then call DestroyEffect(k.fx) set k.fx=null endif //For convenience, always wait for next tic to destroy the thing. But destroy the effect so //players don't ever notice it. set k.state=2 call DisableTrigger(k.t) endfunction function CollisionMissile_Create takes string MissileModelPath, real x, real y, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit local timer t local cscollisionmissile k local trigger R local unit m set k=cscollisionmissile.create() if UseNewCaster then set m=CreateCaster(dirangle,x,y) set k.new=true else set m=GetACaster() call SetUnitFacing(m,dirangle) call SetUnitPosition(m,CS_SafeX(x),CS_SafeY(y)) set k.new=false endif set cs_missilecount=cs_missilecount+1 set cs_missiles[cs_missilecount]=k if (not cs_movementtimer_active) then call TimerStart(cs_movementtimer,cs_TIMER_CYCLE,true,function CasterSystemMovementTimer) set cs_movementtimer_active=true endif call SetUnitUserData(m,k) set k.mtype=cs_TYPE_COLLISIONMISSILE set k.speed=speed set k.aspeed=AngleSpeed set k.f=dirangle set k.maxd=MaxDist call SetUnitFlyHeight(m,height,0) set R=CreateTrigger() set k.collision=Collision set k.state=1 set k.t=R call SetCSData(R,k) set k.fx = AddSpecialEffectTarget(MissileModelPath,m,"origin") set k.m=m set k.ac=TriggerAddAction(R,OnImpact) set R=null set udg_currentcaster=m set m=null return udg_currentcaster endfunction function CollisionMissile_CreateLoc takes string MissileModelPath, location loc, real dirangle, real speed, real AngleSpeed, real MaxDist, real height, boolean UseNewCaster, real Collision, code OnImpact returns unit return CollisionMissile_Create(MissileModelPath,GetLocationX(loc),GetLocationY(loc),dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact) endfunction //! CollisionMissile_CreateLoc(MissileModelPath,loc,dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact) CollisionMissile_Create(MissileModelPath,GetLocationX(loc),GetLocationY(loc),dirangle,speed,AngleSpeed,MaxDist,height,UseNewCaster,Collision,OnImpact) //========================================================================================================================================================= function CollisionMissile_SetAngleSpeed takes unit m, real newAspeed returns nothing set cscollisionmissile(GetUnitUserData(m)).aspeed=newAspeed endfunction //========================================================================================================================================================= function CollisionMissile_SetSpeed takes unit m, real newspeed returns nothing local cscollisionmissile k= cscollisionmissile( GetUnitUserData(m) ) set k.speed=newspeed endfunction //========================================================================================================================================================= function CollisionMissile_SetTargetPoint takes unit m, real tx, real ty returns nothing local cscollisionmissile k= cscollisionmissile( GetUnitUserData(m) ) set k.tx=tx set k.ty=ty set k.ttype=cscollisionmissile.ttype_point endfunction function CollisionMissile_SetTargetPointLoc takes unit m, location tloc returns nothing call CollisionMissile_SetTargetPoint(m,GetLocationX(tloc),GetLocationY(tloc)) endfunction //! define CollisionMissile_SetTargetPointLoc(m,l) CollisionMissile_SetTargetPoint(m,GetLocationX(l),GetLocationY(l)) //========================================================================================================================================================= function CollisionMissile_SetTarget takes unit m, widget Target returns nothing local cscollisionmissile k= GetUnitUserData(m) set k.tw=Target set k.ttype=cscollisionmissile.ttype_widget endfunction //========================================================================================================================================================= function CollisionMissile_ForgetTarget takes unit m returns nothing set cscollisionmissile(GetUnitUserData(m)).ttype=cscollisionmissile.ttype_none endfunction //========================================================================================================================================================= function CollisionMissile_SetDirAngle takes unit m, real f returns nothing set cscollisionmissile(GetUnitUserData(m)).f=f call SetUnitFacing(m,f) endfunction //========================================================================================================================================================= function CollisionMissile_ResetMaxDist takes unit m, real maxdist returns nothing set cscollisionmissile( GetUnitUserData(m) ).maxd = maxdist endfunction //========================================================================================================================================================= function CollisionMissile_PeriodicFX takes unit m, string fx, real dur returns nothing local cscollisionmissile k= cscollisionmissile(GetUnitUserData(m)) set k.pfx=true set k.pfx_path=fx set k.pfx_dur=dur set k.pfx_current=0. endfunction //========================================================================================================================================================= function CollisionMissile_SetTag takes unit m, integer tag returns nothing set cscollisionmissile(GetUnitUserData(m)).tag=tag endfunction //========================================================================================================================================================= function CollisionMissile_GetTag takes unit m returns integer return cscollisionmissile(GetUnitUserData(m)).tag endfunction //============================================================================================================================================================================== // Caster System Class: Damager // function Damager_SetAbility takes unit Damager, integer abilid, integer l returns nothing local string k=GetAttachmentTable(Damager) local integer i if (GetTableBoolean(k,"CS_IsDamager")) then set i=GetTableInt(k,"CS_abil") if (i!=0) then call UnitRemoveAbility(Damager,i) endif call UnitAddAbility(Damager,abilid) call SetUnitAbilityLevel(Damager,abilid,l) call SetTableInt(k,"CS_abil",abilid) endif endfunction function Damager_Removage takes unit u, timer t, group g returns nothing local string k=GetAttachmentTable(u) if (t!=null) then call CleanAttachedVars(t) call ReleaseTimer(t) endif call GroupRemoveUnit(g,u) call DestroyEffect( GetTableEffect(k,"CS_fx") ) call RecicleCasterAfterCastEx(u,4,GetTableInt(k,"CS_abil"),false) call ClearTable(k) endfunction function Damager_Remove takes unit Damager returns nothing local string k=GetAttachmentTable(Damager) local timer dg local group g if (GetTableBoolean(k,"CS_IsDamager")) then set g=GetTableGroup(I2S( GetTableInt(k,"CS_DG") ),"G") if (IsUnitInGroup(Damager,g)) then call Damager_Removage(Damager,GetTableTimer(k,"CS_t"),g) endif endif set g=null set dg=null endfunction function Damager_Expire takes nothing returns nothing local timer t=GetExpiredTimer() local unit u=GetAttachedUnit(t,"u") call Damager_Removage(u,t, GetAttachedGroup( GetAttachedObject(u,"CS_DG") ,"G") ) set u=null endfunction function Damager_SetLifeSpan takes unit Damager, real lifespan returns nothing local timer t if (GetAttachedBoolean(Damager,"CS_IsDamager")) then set t=GetAttachedTimer(Damager,"CS_t") if (lifespan==0) then call PauseTimer(t) else call TimerStart(t,lifespan,false, function Damager_Expire) endif set t=null endif endfunction //============================================================================================================ // Caster System Class: DamagerGroup // function DamagerGroup_Destroy takes timer DamagerGroup returns nothing local string k=I2S(CS_H2I(DamagerGroup)) local group g=GetTableGroup(k,"G") local unit p call DestroyDamageOptions(GetStoredInteger(cs_cache,k,"dop") ) call CS_KillTimer( GetTableTimer(k,"lifespan") ) loop set p=FirstOfGroup(g) exitwhen (p==null) call Damager_Removage(p, GetAttachedTimer(p,"CS_t") ,g) endloop call DestroyGroup(g) call FlushStoredMission(cs_cache,k) call ReleaseTimer(DamagerGroup) set g=null endfunction function DamagerGroup_Enum takes nothing returns nothing call GroupAddUnit(bj_groupAddGroupDest, GetFilterUnit() ) endfunction function DamagerGroup_DoDamage takes nothing returns nothing local timer t=GetExpiredTimer() local string k=I2S(CS_H2I(t)) local group g=CreateGroup() local group a=CS_CopyGroup(GetTableGroup(k,"G")) local group arg=CreateGroup() local unit p local unit u=GetTableUnit(k,"hur") local real x=GetStoredReal(cs_cache,k,"are") local real dm local integer d local boolean trees=GetStoredBoolean(cs_cache,k,"trees") local boolexpr bex=Condition(function DamagerGroup_Enum) set bj_groupAddGroupDest=g if (FirstOfGroup(a)!=null) then loop set p=FirstOfGroup(a) exitwhen (p==null) call GroupRemoveUnit(a,p) call CS_EnumUnitsInAOE(arg,GetUnitX(p),GetUnitY(p),x,bex) if trees then call DamageTreesInCircle(GetUnitX(p),GetUnitY(p),x) endif endloop if (FirstOfGroup(g)!=null) then set d=LoadDamageOptions( GetStoredInteger(cs_cache,k,"dop") ) set dm=GetStoredReal(cs_cache,k,"dmg") loop set p=FirstOfGroup(g) exitwhen (p==null) set x=GetDamageFactorByOptions(u,p,d) if (x!=0) then call UnitDamageTarget(u,p,dm*x,true,false,null,null,null) endif call GroupRemoveUnit(g,p) endloop endif elseif GetStoredBoolean(cs_cache,k,"autodestruct") then call DamagerGroup_Destroy(t) endif call DestroyBoolExpr(bex) call DestroyGroup(g) call DestroyGroup(arg) call DestroyGroup(a) set bex=null set t=null set g=null set arg=null set a=null set u=null endfunction function DamagerGroup_Create takes unit hurter, real damage, real damageperiod, real area, integer DamageOptions returns timer local timer t=NewTimer() local string k=I2S(CS_H2I(t)) if (damageperiod<0.01) then set damageperiod=0.01 endif call StoreInteger(cs_cache,k,"dop",CreateDamageOptions(DamageOptions)) call StoreInteger(cs_cache,k,"hur",CS_H2I(hurter)) call StoreReal(cs_cache,k,"dmg",damage) call StoreReal(cs_cache,k,"are",area) call StoreInteger(cs_cache,k,"G",CS_H2I(CreateGroup())) if IsDamageOptionIncluded(DamageOptions, DamageTrees() ) then call StoreBoolean(cs_cache,k,"trees", true ) endif call TimerStart(t,damageperiod,true,function DamagerGroup_DoDamage) return t //Since the timer is a recyclable one, it won't be destroyed, then there is no need to set it to null //then we can just return it endfunction function DamagerGroup_Update takes timer DamagerGroup, unit hurter, real damage, real damageperiod, real area, integer DamageOptions returns nothing local integer i local string k=GetAttachmentTable(DamagerGroup) local unit p=GetTableUnit(k,"hur") local player ow local group g if (damageperiod<0.01) then set damageperiod=0.01 endif if (p!=hurter) then set g=CS_CopyGroup( GetTableGroup(k,"G") ) call SetTableObject(k,"hur",hurter) set ow=GetOwningPlayer(hurter) loop set p=FirstOfGroup(g) exitwhen (p==null) call GroupRemoveUnit(g,p) call SetUnitOwner(p,ow,true) endloop call DestroyGroup(g) set g=null set ow=null endif call SetTableBoolean(k,"trees",IsDamageOptionIncluded(DamageOptions, DamageTrees() ) ) call SetDamageOptions(GetTableInt(k,"dop") , DamageOptions ) call SetTableReal(k,"dmg",damage) call SetTableReal(k,"are",area) call TimerStart(DamagerGroup,damageperiod,true,function DamagerGroup_DoDamage) set p=null endfunction function DamagerGroup_AddDamager takes timer DamagerGroup, string modelpath, real x, real y, real LifeSpan returns unit local unit c=GetACaster() local string k=GetAttachmentTable(c) local string dk=GetAttachmentTable(DamagerGroup) local timer t=NewTimer() call SetUnitPosition(c,x,y) call SetTableObject(k,"CS_fx",AddSpecialEffectTarget( modelpath,c,"origin") ) call SetTableObject(k,"CS_t", t) call SetTableObject(k,"CS_DG", DamagerGroup) call AttachObject(t,"u", c) if (LifeSpan>0) then call TimerStart(t,LifeSpan,false, function Damager_Expire) endif call SetUnitOwner(c,GetOwningPlayer(GetTableUnit(dk,"hur")),true) call GroupAddUnit(GetTableGroup(dk,"G"),c) call SetTableBoolean(k,"CS_IsDamager",true) set udg_currentcaster=c set c=null return udg_currentcaster endfunction function DamagerGroup_AddDamagerLoc takes timer DamagerGroup, string modelpath, location loc, real LifeSpan returns unit return DamagerGroup_AddDamager(DamagerGroup,modelpath,GetLocationX(loc),GetLocationY(loc),LifeSpan) endfunction function DamagerGroup_OnLifeSpanExpire takes nothing returns nothing call DamagerGroup_Destroy( GetAttachedTimer(GetExpiredTimer() , "t") ) endfunction function DamagerGroup_SetLifeSpan takes timer DamagerGroup, real lifespan returns nothing local string k=GetAttachmentTable(DamagerGroup) local timer t if (HaveSetField(k,"lifespan",bj_GAMECACHE_INTEGER)) then set t=GetTableTimer(k,"lifespan") else set t=NewTimer() call SetTableObject(k,"lifespan",t) set k=GetAttachmentTable(t) call AttachObject(t,"t",DamagerGroup) endif call TimerStart(t,lifespan,false, function DamagerGroup_OnLifeSpanExpire) set t=null endfunction function DamagerGroup_AutoDestruct takes timer DamagerGroup, boolean auto returns nothing call AttachBoolean(DamagerGroup,"autodestruct",auto) endfunction //************************************************************************************************** //* //* Caster System Special Events: //* //* //************************************************************************************************** //================================================================================================== // Event: OnAbilityLearn // function Event_OnLearn1 takes nothing returns nothing local integer s=GetLearnedSkill() local string k=I2S(s) if HaveStoredString( cs_cache, "events_onlearn",k) then call ExecuteFunc( GetStoredString( cs_cache, "events_onlearn",k) ) endif endfunction function Event_OnLearn2 takes nothing returns nothing local integer s=GetLearnedSkill() local string k=I2S(s) if HaveStoredString( cs_cache, "events_onlearn",k) then call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(GetTriggerUnit())) call StoreInteger(cs_cache,"events_variables","current",s) call ExecuteFunc( GetStoredString( cs_cache, "events_onlearn",k) ) endif endfunction function InitLearnEvent takes gamecache g, integer i returns nothing local trigger t=CreateTrigger() local integer j=0 loop call TriggerRegisterPlayerUnitEvent(t, Player(j),EVENT_PLAYER_HERO_SKILL, null) set j=j+1 exitwhen j==bj_MAX_PLAYER_SLOTS endloop if (i==1) then call StoreInteger(g,"Events_ProbablyTemp","learntrig",CS_H2I(t)) call StoreInteger(g,"Events_ProbablyTemp","learntriga",CS_H2I(TriggerAddAction(t, function Event_OnLearn1))) else call TriggerAddAction(t, function Event_OnLearn2) endif call StoreInteger(g,"eventhandlers","learn",i) set t=null endfunction function OnAbilityLearn takes integer abilid, string funcname returns nothing if (not HaveStoredInteger(cs_cache,"eventhandlers","learn")) then call InitLearnEvent(cs_cache,1) endif call StoreString(cs_cache,"events_onlearn", I2S(abilid), funcname) endfunction //================================================================================================== // Event: OnAbilityGet // function GetAbilityAcquiringUnit takes nothing returns unit return GetStoredInteger(cs_cache,"events_variables","unit") return null endfunction function GetAcquiredAbilityId takes nothing returns integer return GetStoredInteger(cs_cache,"events_variables","current") endfunction ///! define GetAcquiredAbilityId() GetStoredInteger(cs_cache,"events_variables","current") probably later function UnitAddAbility_ConsiderEvent takes unit whichUnit, integer abilid, integer level returns nothing local string k=I2S(abilid) call UnitAddAbility(whichUnit,abilid) call SetUnitAbilityLevel(whichUnit,abilid,level) if (HaveStoredString(cs_cache,"events_onlearn",k)) then call StoreInteger(cs_cache,"events_variables","units",CS_H2I(whichUnit)) call StoreInteger(cs_cache,"events_variables","current",abilid) call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",k)) endif endfunction function Event_OnPassive_Browse takes unit u, string k returns nothing local integer n=GetStoredInteger(cs_cache,"events_passives","n") local integer un=0 local integer i=1 local integer s loop exitwhen (i>n) set s=GetStoredInteger(cs_cache,"events_passives",I2S(i)) if (GetUnitAbilityLevel(u,s)>0) then if (un==0) then set un=1 call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u)) else set un=un+1 endif call StoreInteger(cs_cache,"events_unit_passive"+I2S(un),k,s) call StoreInteger(cs_cache,"events_variables","current",s) call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",I2S(s))) endif set i=i+1 endloop if (un==0) then set un=-1 endif call StoreInteger(cs_cache,"events_unit_passives",k,un) endfunction function Event_OnPassive_Do takes unit u, string k, integer n returns nothing local integer i=1 local integer s call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u)) loop exitwhen (i>n) set s=GetStoredInteger(cs_cache,"events_unit_passive"+I2S(i),k) if (GetUnitAbilityLevel(u,s)>0) then call StoreInteger(cs_cache,"events_variables","current",s) call ExecuteFunc(GetStoredString(cs_cache,"events_onlearn",I2S(s))) endif set i=i+1 endloop endfunction function Event_OnPassive_EnterRect takes nothing returns nothing local unit u=GetTriggerUnit() local string k=I2S(GetUnitTypeId(u)) local integer n=GetStoredInteger(cs_cache,"events_unit_passives",k) if (n>0) then call Event_OnPassive_Do(u,k,n) elseif (n==0) then call Event_OnPassive_Browse(u,k) endif set u=null endfunction function Event_OnPassive_NoCasters takes nothing returns boolean return (GetUnitTypeId(GetTriggerUnit())!=cs_CasterUnitId) endfunction function Event_OnPassive_InitEnum takes nothing returns nothing local trigger t local integer n=GetStoredInteger(cs_cache,"events_passives","n") local integer i=1 local integer array p local string array s local unit u local group a=CreateGroup() local boolean saved call ReleaseTimer(GetExpiredTimer()) loop exitwhen (i>n) set p[i]=GetStoredInteger(cs_cache,"events_passives",I2S(i)) set s[i]=GetStoredString(cs_cache,"events_onlearn", I2S(p[i])) set i=i+1 endloop call GroupEnumUnitsInRect(a,bj_mapInitialPlayableArea,null) loop set u=FirstOfGroup(a) exitwhen (u==null) set i=1 set saved=false loop exitwhen (i>n) if (GetUnitAbilityLevel(u,p[i])>0) then if (not saved) then set saved=true call StoreInteger(cs_cache,"events_variables","unit",CS_H2I(u)) endif call StoreInteger(cs_cache,"events_variables","current",p[i]) call ExecuteFunc(s[i]) endif set i=i+1 endloop call GroupRemoveUnit(a,u) endloop set t=CreateTrigger() call TriggerRegisterEnterRectSimple(t,bj_mapInitialPlayableArea) call TriggerAddAction(t,function Event_OnPassive_EnterRect) call TriggerAddCondition(t,Condition(function Event_OnPassive_NoCasters)) call DestroyGroup(a) set t=null set a=null endfunction function InitPassiveEvent takes nothing returns nothing local trigger t local triggeraction a call TimerStart(NewTimer(),0,false,function Event_OnPassive_InitEnum) call StoreInteger(cs_cache,"eventhandlers","passives",1) if (not HaveStoredInteger(cs_cache,"eventhandlers","learn")) then call InitLearnEvent(cs_cache,2) else set t=GetTableTrigger("Events_ProbablyTemp","learntrig") set a=GetTableTriggerAction("Events_ProbablyTemp","learntriga") call TriggerRemoveAction(t,a ) call FlushStoredMission(cs_cache,"Events_ProbablyTemp") call TriggerAddAction(t, function Event_OnLearn2) call StoreInteger(cs_cache,"eventhandlers","learn",2) set t=null set a=null endif endfunction function OnAbilityGet takes integer abilid, string funcname returns nothing local integer n=GetStoredInteger(cs_cache,"events_passives","n")+1 if (not HaveStoredInteger(cs_cache,"eventhandlers","passives")) then call InitPassiveEvent() endif call StoreString( cs_cache,"events_onlearn", I2S(abilid), funcname) call StoreInteger(cs_cache,"events_passives","n",n) call StoreInteger(cs_cache,"events_passives",I2S(n),abilid) endfunction //================================================================================================== // Event: OnAbilityEffect // function Event_OnEffect takes nothing returns nothing local string k=I2S(GetSpellAbilityId()) if HaveStoredString(cs_cache, "events_oneffect",k) then call ExecuteFunc( GetStoredString(cs_cache, "events_oneffect",k)) endif endfunction function InitEffectEvent takes gamecache g returns nothing local trigger t=CreateTrigger() local integer i = 0 loop call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT, null) set i=i+1 exitwhen i==bj_MAX_PLAYER_SLOTS endloop call TriggerAddAction(t,function Event_OnEffect) call StoreInteger(g,"eventhandlers","effect",1) set t=null endfunction function OnAbilityEffect takes integer abilid, string funcname returns nothing if (not HaveStoredInteger(cs_cache,"eventhandlers","effect")) then call InitEffectEvent(cs_cache) endif call StoreString(cs_cache,"events_oneffect",I2S(abilid),funcname) endfunction //================================================================================================== // Event: OnAbilityCast // function Event_OnCast takes nothing returns nothing local string k=I2S(GetSpellAbilityId()) if HaveStoredString(cs_cache, "events_oncast",k) then call ExecuteFunc( GetStoredString(cs_cache, "events_oncast",k)) endif endfunction function InitCastEvent takes nothing returns nothing local trigger t=CreateTrigger() local integer i = 0 loop call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_CAST, null) set i=i+1 exitwhen i==bj_MAX_PLAYER_SLOTS endloop call TriggerAddAction(t,function Event_OnCast) call StoreInteger(cs_cache,"eventhandlers","cast",1) set t=null endfunction function OnAbilityPreCast takes integer abilid, string funcname returns nothing if (not HaveStoredInteger(cs_cache,"eventhandlers","cast")) then call InitCastEvent() endif call StoreString(cs_cache,"events_oncast",I2S(abilid),funcname) endfunction //================================================================================================== // Event: OnAbilityEndCast // function Event_OnEndCast takes nothing returns nothing local string k=I2S(GetSpellAbilityId()) if HaveStoredString(cs_cache, "events_onendcast",k) then call ExecuteFunc( GetStoredString(cs_cache, "events_onendcast",k)) endif endfunction function InitEndCastEvent takes nothing returns nothing local trigger t=CreateTrigger() local integer i = 0 loop call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_SPELL_ENDCAST, null) set i=i+1 exitwhen i==bj_MAX_PLAYER_SLOTS endloop call TriggerAddAction(t,function Event_OnEndCast) call StoreInteger(cs_cache,"eventhandlers","endcast",1) set t=null endfunction function OnAbilityEndCast takes integer abilid, string funcname returns nothing if (not HaveStoredInteger(cs_cache,"eventhandlers","endcast")) then call InitEndCastEvent() endif call StoreString(cs_cache,"events_onendcast",I2S(abilid),funcname) endfunction //================================================================================================== // Spell Helpers // function IsPointWater takes real x, real y returns boolean return IsTerrainPathable(x,y,PATHING_TYPE_WALKABILITY) and not(IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING)) endfunction function IsPointWaterLoc takes location loc returns boolean return IsPointWater(GetLocationX(loc),GetLocationY(loc)) endfunction //================================================================================================== function IsUnitSpellImmune takes unit u returns boolean return IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE) endfunction function IsUnitImmuneToPhisical takes unit u returns boolean return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_DEMOLITION)==0) endfunction function IsUnitInvulnerable takes unit u returns boolean return (GetDamageFactor(u,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_UNIVERSAL)==0) endfunction //## Utility functions ## //==================================================================================================== // Mimic an interface error message // ForPlayer : The player to show the error // msg : The error // function CS_Error takes player ForPlayer, string msg returns nothing local sound error=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10) if (GetLocalPlayer() == ForPlayer) then if (msg!="") and (msg!=null) then call ClearTextMessages() call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" ) endif call StartSound( error ) endif call KillSoundWhenDone( error) set error=null endfunction //## Safe item hiding system ## //=============================== // Hides an item, it keeps it safe while leaving other units unable to use it // (unless an (attached) variable / table field points to it and user does // something with it) - THIS IS HIGHLY DISCOURAGED // // * Don't use it with tomes that increase hero stats // * Make triggers with item acquire/lose events ignore when a // Caster is triggering unit. // function CS_HideItem takes item i returns integer local unit s local group gr=GetTableGroup("CSItemStorage","gr") local integer k=NewTableIndex() local string ks=I2S(k) if (gr==null) then set gr=CreateGroup() call StoreInteger(cs_cache,"CSItemStorage","gr",CS_H2I(gr)) endif set s=FirstOfGroup(gr) if (s==null) then set s=CreateCaster(0,0,0) call UnitAddAbility(s,cs_DummyInventory_Id) if (UnitInventorySize(s)