Guest cohadar Posted December 11, 2007 Hi there peoplez. I was asked by Karawasa to make a more optimized version of onDamage system for EleTD. EleTD is currently using old emjlr3's Damage Detection engine. I will for starters make a more optimized version of that engine. When that version in implemented in EleTD we can proceed for further optimizations. What are further optimizations? Well it is like this: I can optimize generic onDamage system only to a limited amount, but to get it to full potential changing some other EleTD code would be needed. For example: current system registers damage events for units that enter the map, this is bad because you don't really need damage events for all units that enter the map. You don't need it for towers and you don't need it for dummy units, and unit enters region event is also adding to lag. So solution for this would be to register damage events when units are spawned, so this would require modifying spawn trigger. Also optimizing spells that use damage engine by using triggerconditions instead of registering function names as strings. But we will talk about that when we get there. See ya tomorrow. Go to top Share this post Link to post
Guest cohadar Posted December 11, 2007 lol, tnx. Replacing OnDamage system is a dangerous job, especially because it is vitally important to game armor/damage types. Beta testing needs to be extremely detailed, I hope you are up to it. Go to top Share this post Link to post
Guest Sancdar Posted December 11, 2007 Man, a good OnDamage system would be beneficial to a ton of custom maps. Without one, any decently sized map just chokes as you start adding neat custom abilities. Go to top Share this post Link to post
Guest emjlr3 Posted December 11, 2007 the lag has nothing to do with the number of triggers, the units its registering for, or the units it is not the only thing you can do to make it noticeably better is to have less functions run, period, this whole less triggers, not using GC for the one thing that I do, is not going to make any different, period how my method is old, I don't understand, as far as DDS's go, its the only way I have every seen them done, and how Also optimizing spells that use damage engine by using triggerconditions instead of registering function names as strings. will do anything, I have no idea, and why executefunc would be any slower then this is odd to me.... the only reason its slow is that for every unit who is damaged, it has to run all OnDamage triggers, coming up with a different method for that is the only thing that will make any difference, period Man, a good OnDamage system would be beneficial to a ton of custom maps. Without one, any decently sized map just chokes as you start adding neat custom abilities. guess you never heard of DotA Go to top Share this post Link to post
Guest Sancdar Posted December 12, 2007 the only reason its slow is that for every unit who is damaged, it has to run all OnDamage triggers, coming up with a different method for that is the only thing that will make any difference, periodMan, a good OnDamage system would be beneficial to a ton of custom maps. Without one, any decently sized map just chokes as you start adding neat custom abilities. guess you never heard of DotA I thought that was what he was talking about. As for DotA, it doesn't count as much as you think because it doesn't have that many units on the map at once, most TDs outstrip it. A better comparison would be EotA, and I think they were running into problems in this area. Go to top Share this post Link to post
Guest cohadar Posted December 12, 2007 the only thing you can do to make it noticeably better is to have less functions run, period, this whole less triggers, not using GC for the one thing that I do, is not going to make any different, period It will make a small difference, but small differences multiply with increase of unit numbers. And using UnitUserData over GC is like 10 times faster how my method is old, I don't understand, as far as DDS's go, its the only way I have every seen them done, and how There is always a better way. That is why systems have versions. >>Also optimizing spells that use damage engine by using triggerconditions instead of registering function names as strings. will do anything, I have no idea, and why executefunc would be any slower then this is odd to me.... It is slower because jass virtual machine has to do hashing from string function name to function handle, the more functions are in map this hashing is slower. When you use action handles directly you avoid that overhead So basically instead of this: public function Attacks takes string funcName returns nothing //used for attack damage set AttackCount = AttackCount + 1 set AttackFunction[AttackCount] = funcNameendfunction we will be using this: public function Attacks takes code funcName returns nothing //used for attack damage call TriggerAddAction(Attack_trig, funcName)endfunction This will not only save that unnecessary function name hashing but will replace jass looping with native looping inside trigger. the only reason its slow is that for every unit who is damaged, it has to run all OnDamage triggers, coming up with a different method for that is the only thing that will make any difference, period Almost true, I agree that it would be better if there is direct unit-type -> damage function hashing, that would save a LOT of speed, but it requires to change ALL spells that currently use damage system. I decided to optimize what we currently have before I make such a drastic step in changing how damage is handled in entire map. Like I said those few "small speed" improvements multiply with unit number and difference will be noticeable enough. I expected you to have more faith in me emjlr3 ... -------------------- progress report: * PUI installed in map, all triggers that were using UnitUserData directly converted to use PUI. (PUI can be used from GUI btw, lolz) * Done a first set of optimization on attack system - replaced gamecache with PUI * fixed a bug - attack system was not working for preplaced units, (witch noone noticed because there are no preplaced units that use it in EleTD) * Small improvements on some triggers. -------------------- Map was shortly debugged by Karawasa and me, it was working ok. Second set of optimization is scheduled for later this day. Go to top Share this post Link to post
0rb3r Posted December 12, 2007 Hi and first of all welcome to the forum cohadar. Also optimizing spells that use damage engine by using triggerconditions instead of registering function names as strings. Is that onDamage system going to make it possible that skill/ability-damage will be affected by armor type of the attacked unit and the game difficulty? (Maybe this point is already solved, I dont remember right now, but I remember that most skills of 3.0 where armor ignoring and didnt take into consideration the game difficulties armor increase) Go to top Share this post Link to post
Karawasa Posted December 12, 2007 Is that onDamage system going to make it possible that skill/ability-damage will be affected by armor type of the attacked unit and the game difficulty? (Maybe this point is already solved, I dont remember right now, but I remember that most skills of 3.0 where armor ignoring and didnt take into consideration the game difficulties armor increase) All of the triggered spells that do damage (i.e. any spell that isn't from WarCraft 3 ladder) is affected by armor and armor type. So yes, that problem has been solved for the most part. There are a total of 6 towers that ignore armor in 4.0 currently (beta5), and I intend to reduce this number to 3. Moved to Programmer's Corner Go to top Share this post Link to post
Guest cohadar Posted December 12, 2007 Is that onDamage system going to make it possible that skill/ability-damage will be affected by armor type of the attacked unit and the game difficulty? It was possible before, it will only be more easier now. Go to top Share this post Link to post
Guest emjlr3 Posted December 12, 2007 And using UnitUserData over GC is like 10 times faster i dont know about 10, maybe 2 or 3, and if that is a different of, say, 1/1000th of a second, whenever a unit dies or enters the map units enter map every .35s/player so say 10 every .35s, which will save us 1/100th of a sec in game every second when units are spawned, and that is giving it a little, noticeable....doubtful and units die a good bit slower then that, no doubt fixed a bug - attack system was not working for preplaced units, it was written for Ele TD, preplaced unit attack detection is uneeded as far as adding triggeractions, you will either need to have 1 trigger for spell damage and another for physical, or edit all onDamage triggers to detect in themselves the physical or magical damage, as well as to make sure the damage taken is greater then .01 or so It was possible before, it will only be more easier now. how so? Go to top Share this post Link to post
Guest 1mpulse Posted December 12, 2007 i dont really understand why anything needs to be changed..... but thats just me Go to top Share this post Link to post
Guest emjlr3 Posted December 12, 2007 apparently on Karawasa's crap computer at his parents house, it gets laggy for him so he figures, if it lags for him, it may lag for someone else somewhere Go to top Share this post Link to post
Guest cohadar Posted December 12, 2007 No need to be negative emjlr3. Here a figured a way how to make direct unit -> onDamage function calls to avoid calling all registered functions. public function Attacks takes integer index, string funcName returns nothing if AttackFunction[index] != null then call BJDebugMsg("Error: Damage functions " + funcName + " and " + AttackFunction[index] + " have same index - " + I2S(index)) else set AttackFunction[index] = funcName endifendfunction private function Damaged takes nothing returns boolean local integer index if Enabled then set U = GetTriggerUnit() if GetEventDamage()>.1 then set index = PUI_DamageIndex[GetUnitUserData(U)] if GetUnitAbilityLevel(U, BUFF_ORB) > 0 then call UnitRemoveAbility(U, BUFF_ORB) call ExecuteFunc(AttackFunction[index]) else call ExecuteFunc(SpellFunction[index]) endif endif endif return falseendfunction Go to top Share this post Link to post
Cisz Posted December 12, 2007 It lags on my machine too. The creeps don't come out in a straight line, they stutter on spawning or take a break on the road.. Go to top Share this post Link to post
Guest emjlr3 Posted December 12, 2007 I rewrote the spawning and units enter spawn region triggers, that should be resolved through them, hopefully ^^ Go to top Share this post Link to post
Guest cohadar Posted December 13, 2007 I rewrote the spawning and units enter spawn region triggers, that should be resolved through them, hopefully ^^ Yeah I was wondering if that was the case. Could you post new spawn triggers here? Go to top Share this post Link to post
Guest emjlr3 Posted December 13, 2007 Karawasa may have edited them a bit, but these are what I gave him, keep in mind, if you have the map, they should be in it under the catagory Level function Trig_Spawn_Conditions takes nothing returns boolean return IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO) == false and GetUnitTypeId(GetTriggerUnit()) != 'u000'endfunctionfunction Trig_Spawn_Actions takes nothing returns nothing local unit u = GetTriggerUnit() local integer i = 0 if GetUnitTypeId(u) == 'n00K' or GetUnitTypeId(u) == 'n00J' or GetUnitTypeId(u) == 'n023' or GetUnitTypeId(u) == 'n024' then call KillUnit(u) call RemoveUnit( u ) endif loop exitwhen i > 7 if RectContainsUnit(udg_Region_Spawn[i], u) == true then call SetUnitInvulnerable( u, true ) call SetUnitAbilityLevel(u,'A00V',udg_Difficulty[i]) call SetUnitAbilityLevel(u,'A01R',udg_Level) if udg_Extreme_Mode_On == true then call UnitAddAbility(u,'A03N') call UnitAddAbility(u,'A00I') endif if IsUnitType(GetTriggerUnit(), UNIT_TYPE_UNDEAD) == true then call TriggerRegisterUnitLifeEvent( gg_trg_Undead_Reincarnate, u, LESS_THAN_OR_EQUAL, 0.00 ) endif if IsUnitType(GetTriggerUnit(), UNIT_TYPE_MECHANICAL) == true then call TriggerRegisterUnitManaEvent( gg_trg_Mechanical_Activate, u, GREATER_THAN_OR_EQUAL, 12.00 ) call SetUnitState(u,UNIT_STATE_MANA,GetRandomReal(0.,12.)) endif set udg_Temp_Point = GetRectCenter(udg_Region_Leak[i]) call IssuePointOrderLoc(u,"move",udg_Temp_Point) call RemoveLocation(udg_Temp_Point) endif set i = i + 1 endloop call PolledWait2( 1.00 ) call SetUnitInvulnerable( u, false ) set u = nullendfunction//===========================================================================function InitTrig_Spawn takes nothing returns nothing set gg_trg_Spawn = CreateTrigger( ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Red ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Blue ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Green ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Orange ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Pink ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Purple ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Teal ) call TriggerRegisterEnterRectSimple( gg_trg_Spawn, gg_rct_Spawn_Yellow ) call TriggerAddCondition( gg_trg_Spawn, Condition( function Trig_Spawn_Conditions ) ) call TriggerAddAction( gg_trg_Spawn, function Trig_Spawn_Actions )endfunction function Trig_Start_Level_Func004Func003Func003002001002 takes nothing returns boolean return GetUnitUserData(GetFilterUnit()) == GetConvertedPlayerId(GetEnumPlayer()) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) and GetWidgetLife(GetFilterUnit())>.405endfunctionfunction Trig_Start_Level_Func004Func002002001 takes nothing returns boolean return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )endfunctionfunction Trig_Start_Level_Func004Func003A takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local group g = CreateGroup() set udg_Level_Name = GetObjectName(udg_Spawns[udg_Level - 1]) call DisplayTimedTextToPlayer( GetEnumPlayer(),0.,0., 5.00, ( "Level " + ( I2S(udg_Level) + ( ": " + ( udg_Level_Name + ( " " + ( udg_Extra + ( " - " + ( I2S(( 15 + ( ( udg_Difficulty[id] + 0 ) * 3 ) )) + " spawns" ) ) ) ) ) ) ) ) ) call GroupEnumUnitsOfPlayer(g,ConvertedPlayer( ( id / 2 ) + 9 ),Condition(function Trig_Start_Level_Func004Func003Func003002001002)) set udg_Creeps_Left[id] = CountUnitsInGroup(g) set udg_Creeps_Left[id] = udg_Creeps_Left[id]+(15+(udg_Difficulty[id]*3)) call DestroyGroup(g) set g = nullendfunctionfunction Trig_Start_Level_Func005Func004Func002002001 takes nothing returns boolean return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )endfunctionfunction Trig_Start_Level_Func005Func004Func003A takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local unit u local real hp if udg_Spawn_Loop > 15 - (udg_Difficulty[id] * 3) then set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id]) set u = CreateUnitAtLoc(ConvertedPlayer( ( id / 2 ) + 9 ),'n00I',udg_Temp_Point,270.) call RemoveLocation(udg_Temp_Point) call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) ) set hp = (udg_Difficulty[id]*.125)+.50 call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp) set u = null endifendfunction function Start_Level_Ronalds takes nothing returns nothing set udg_Spawn_Loop = udg_Spawn_Loop + 1 if udg_Spawn_Loop>30. then call EndTimer(GetExpiredTimer()) return endif set udg_Player_Group = GetPlayersMatching(Condition(function Trig_Start_Level_Func005Func004Func002002001)) call ForForce( udg_Player_Group, function Trig_Start_Level_Func005Func004Func003A ) call DestroyForce(udg_Player_Group)endfunctionfunction Trig_Start_Level_Func005Func005Func002002001 takes nothing returns boolean return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )endfunctionfunction Trig_Start_Level_Func005Func005Func003A takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local unit u local real hp if udg_Spawn_Loop > 15 - (udg_Difficulty[id] * 3) then set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id]) set u = CreateUnitAtLoc(ConvertedPlayer( ( id / 2 ) + 9 ),udg_Spawns[udg_Level - 1],udg_Temp_Point,270.) call RemoveLocation(udg_Temp_Point) call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) ) call UnitAddAbility(u,udg_Spawn_HP[udg_Level - 1]) set hp = (udg_Difficulty[id]*.125)+.50 call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp) set u = null endifendfunctionfunction Start_Level_Spawns takes nothing returns nothing set udg_Spawn_Loop = udg_Spawn_Loop + 1 if udg_Spawn_Loop>30. then call EndTimer(GetExpiredTimer()) return endif set udg_Player_Group = GetPlayersMatching(Condition(function Trig_Start_Level_Func005Func005Func002002001)) call ForForce( udg_Player_Group, function Trig_Start_Level_Func005Func005Func003A ) call DestroyForce(udg_Player_Group)endfunctionfunction Trig_Start_Level_Actions takes nothing returns nothing local timer t set udg_Between_Levels = false set udg_Level = udg_Level + 1 set udg_Extra = ( "(" + ( udg_Level_Desc[( udg_Level - 1 )] + ")" ) ) if udg_Level < 61 then set udg_Player_Group = GetPlayersMatching(Condition(function Trig_Start_Level_Func004Func002002001)) call ForForce( udg_Player_Group, function Trig_Start_Level_Func004Func003A ) call DestroyForce(udg_Player_Group) endif if udg_Level < 61 then set udg_Spawn_Loop = 1 set t = GetTimer() call TimerStart(t,.35,true,function Start_Level_Spawns) else call DisplayTextToForce( bj_FORCE_ALL_PLAYERS, "The Ronald round starts now. Good luck!" ) call TriggerExecute( gg_trg_Create_Leaderboard ) call PauseTimer(udg_Income_Timer) set udg_Spawn_Loop = 1 set t = GetTimer() call TimerStart(t,.35,true,function Start_Level_Ronalds) endifendfunction//===========================================================================function InitTrig_Start_Level takes nothing returns nothing set gg_trg_Start_Level = CreateTrigger( ) call TriggerRegisterTimerExpireEventBJ( gg_trg_Start_Level, udg_Between_Levels_Timer ) call TriggerAddAction( gg_trg_Start_Level, function Trig_Start_Level_Actions )endfunction Start Level is a bit confusing, it was though for me too, ROFL Go to top Share this post Link to post
Guest cohadar Posted December 13, 2007 How about now? scope StartLevelglobals private constant integer UID_RONALD = 'n00I' private constant real SPAWN_PERIOD = 0.4endglobals//===========================================================================function CreepFilter takes nothing returns boolean return udg_CreepOwner[GetUnitUserData(GetFilterUnit())] == GetEnumPlayer() and IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) == false and IsUnitAliveBJ(GetFilterUnit()) == trueendfunction//===========================================================================function CountCreeps takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local group g = CreateGroup() set udg_Level_Name = GetObjectName(udg_Spawns[udg_Level - 1]) call DisplayTimedTextToPlayer( GetEnumPlayer(),0.,0., 5.00, ( "Level " + ( I2S(udg_Level) + ( ": " + ( udg_Level_Name + ( " " + ( udg_Extra + ( " - " + ( I2S(30) + " Spawns" ) ) ) ) ) ) ) ) ) call GroupEnumUnitsOfPlayer(g,ConvertedPlayer( ( id / 2 ) + 9 ),Condition(function CreepFilter)) set udg_Creeps_Left[id] = CountUnitsInGroup(g) set udg_Creeps_Left[id] = udg_Creeps_Left[id]+(30) call DestroyGroup(g) set g = nullendfunction//===========================================================================function AlivePlayerFilter takes nothing returns boolean return ( udg_Player_Lives[GetPlayerId(GetFilterPlayer())] > 0 )endfunction//===========================================================================function SpawnRonald takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local unit u local real hp if udg_Spawn_Loop > 0 then set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id]) set u = CreateUnitAtLoc(ConvertedPlayer( ( id / 2 ) + 9 ),UID_RONALD,udg_Temp_Point,270.) call RemoveLocation(udg_Temp_Point) //call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) ) set udg_CreepOwner[GetUnitIndex(u)] = GetEnumPlayer() set hp = ((udg_Difficulty[id]-1)*.125)+.50 call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp) set u = null endifendfunction//===========================================================================function Start_Level_Ronalds takes nothing returns nothing set udg_Spawn_Loop = udg_Spawn_Loop + 1 if udg_Spawn_Loop>31. then call EndTimer(GetExpiredTimer()) return endif set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter)) call ForForce( udg_Player_Group, function SpawnRonald ) call DestroyForce(udg_Player_Group)endfunction//===========================================================================function SpawnCreep takes nothing returns nothing local integer id = GetPlayerId(GetEnumPlayer()) local unit u local real hp if udg_Spawn_Loop > 0 then set udg_Temp_Point = GetRectCenter(udg_Region_Spawn[id]) set u = CreateUnitAtLoc(ConvertedPlayer( ( id / 2 ) + 9 ),udg_Spawns[udg_Level - 1],udg_Temp_Point,270.) call RemoveLocation(udg_Temp_Point) //call SetUnitUserData( u, GetConvertedPlayerId(GetEnumPlayer()) ) set udg_CreepOwner[GetUnitIndex(u)] = GetEnumPlayer() call UnitAddAbility(u,udg_Spawn_HP[udg_Level - 1]) set hp = ((udg_Difficulty[id]-1)*.125)+.50 call SetWidgetLife(u,GetUnitState(u,UNIT_STATE_MAX_LIFE)*hp) set u = null endifendfunction//===========================================================================function Start_Level_Spawns takes nothing returns nothing set udg_Spawn_Loop = udg_Spawn_Loop + 1 if udg_Spawn_Loop>31. then call EndTimer(GetExpiredTimer()) return endif set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter)) call ForForce( udg_Player_Group, function SpawnCreep ) call DestroyForce(udg_Player_Group)endfunction//===========================================================================function Trig_Start_Level_Actions takes nothing returns nothing local timer t set udg_Between_Levels = false set udg_Level = udg_Level + 1 set udg_Extra = ( "(" + ( udg_Level_Desc[( udg_Level - 1 )] + ")" ) ) if udg_Level < 61 then set udg_Player_Group = GetPlayersMatching(Condition(function AlivePlayerFilter)) call ForForce( udg_Player_Group, function CountCreeps ) call DestroyForce(udg_Player_Group) endif if udg_Level < 61 then set udg_Spawn_Loop = 1 set t = GetTimer() call TimerStart(t,SPAWN_PERIOD,true,function Start_Level_Spawns) else call DisplayTextToForce( bj_FORCE_ALL_PLAYERS, "The Ronald round starts now. Good luck!" ) call TriggerExecute( gg_trg_Create_Leaderboard ) call PauseTimer(udg_Income_Timer) set udg_Spawn_Loop = 1 set t = GetTimer() call TimerStart(t,SPAWN_PERIOD,true,function Start_Level_Ronalds) endifendfunction//===========================================================================public function InitTrig takes nothing returns nothing local trigger trig = CreateTrigger() call TriggerRegisterTimerExpireEventBJ( trig, udg_Between_Levels_Timer ) call TriggerAddAction( trig, function Trig_Start_Level_Actions )endfunctionendscope Go to top Share this post Link to post
Cisz Posted December 13, 2007 I can feel a disturbance in the force, like two coders working on the same project.. Go to top Share this post Link to post
Guest cohadar Posted December 14, 2007 PROGRESS REPORT: IT WORKS !!!! Observe the beauty of new Damage Trigger handler private function Damaged takes nothing returns boolean local integer i if Enabled then set U = GetTriggerUnit() if GetEventDamage()>.1 then // functions that trigger for specific attack if GetUnitAbilityLevel(U, BUFF_ORB) > 0 then call UnitRemoveAbility(U, BUFF_ORB) set i = PUI_AttackIndex[GetUnitUserData(GetEventDamageSource())] if i != 0 then debug call BJDebugMsg(AttackFunction[i]) call ExecuteFunc(AttackFunction[i]) else debug call BJDebugMsg("ERROR: PUI_AttackIndex not registered for tower: " + GetUnitName(GetEventDamageSource())) endif endif call TriggerExecute(OnDamage_trig) endif endif return falseendfunction BEFORE/NOW: Before sys used to add Orb ability to ALL towers. Now it is only added to towers that actually use Damage sys Before all 11 damage abilities were executed when unit was damaged and each ability had to check if it is the right one to run Now system knows exactly witch function to call so only one function will be executed Before there was no difference between damage triggers Now there are separate functions for registering attacks (used by 25 towers/11 abilities) and for registering actions that need to be run for every damage event. (currently used only by penitence) STATUS: Currently only 6 towers are "plugged in" into new system Death,Doom,Damnation - Sporadic Damage Flame,Solar,Sun - Penitence 19 towers to go. Plugging is done like this: if id == TOWER_FLAME or id == TOWER_SOLAR or id == TOWER_SUN then set PUI_AttackIndex[GetUnitIndex(U)] = PENITENCE if GetUnitAbilityLevel(U, AID_ORB) <= 0 then call UnitAddAbility(U, AID_ORB) call UnitMakeAbilityPermanent(U,true,AID_ORB) endif endif PS: Karawasa complete those tower codes ffs. Go to top Share this post Link to post
Karawasa Posted December 14, 2007 PS: Karawasa complete those tower codes ffs. You will have it tomorrow. Do note that I am at work tomorrow until the afternoon. Go to top Share this post Link to post
Guest emjlr3 Posted December 14, 2007 will be interested to see the final product, and the fps gain if I am not mistaken, Kara you said it ran at 34 fps before or something? still do not quite understand what you are doing there on another note, the new Dialog system has been incorporated into the map for testing, works fairly well, but there are still a few kinks to work out, but once its done, this shall be a huge advancement for the map Go to top Share this post Link to post