Well, progress on the map has been going good, but hasn't moved forward as far as I had expected by this time. The main reason for that is that I started learning vJASS so that I could become fairly independent as far as requiring someone to code for me. Thankfully I've been able to learn at a reasonably good pace, and I've started discovering how horrible most of the code in my map really is. That's what happens when you get 3 or 4 different people coding the core of your map over a year -_-
Anyway, so I've been spending time cleaning up, reorganizing, optimizing and in some cases, just plain remaking a lot of the stuff in my map that was originally already "finished".
Here is an example of something I did. I had a semi-working Generator tower before, but it wasn't exactly to my liking. At the time, however, I was lacking the skills to be able to do it myself, but now I can!
So this is the first tower in my map that I coded entirely myself. And I must say, I'm quite pleased with the results.
And here is the code for the tower:
It ended up becoming quite long. I took the screenshot a little zoomed out so you could easily see everything. The blue circle thingy you see around the Generator is created whenever you have the generator selected, and destroyed when you deselect the generator. It is meant to easily let you determine visually the limits of how far away you can place your link tower.
You can't really appriciate the coolness of the Generator tower until you see it in action. If anyone would like to try it out, let me know and I'll hook you up
I'm currently rewriting the Vacuum tower. It ended up breaking due to the retarded coder who used GetUserUnitData and SetUserUnitData. Some other systems in my map ended up breaking that, and thus the tower no longer worked. As of right now, I got the tower working correctly, and I just need to add in its upgrades and such.
Anyway, so I've been spending time cleaning up, reorganizing, optimizing and in some cases, just plain remaking a lot of the stuff in my map that was originally already "finished".
Here is an example of something I did. I had a semi-working Generator tower before, but it wasn't exactly to my liking. At the time, however, I was lacking the skills to be able to do it myself, but now I can!
So this is the first tower in my map that I coded entirely myself. And I must say, I'm quite pleased with the results.
And here is the code for the tower:
JASS:
//Generator Tower by Zaraf
scope GeneratorTower initializer Init
globals
private constant string CIRCLE_SFX = "Abilities\\Weapons\\SpiritOfVengeanceMissile\\SpiritOfVengeanceMissile.mdl" //Special effect that the range circle is made up of
private constant string UNIT_SFX_HIT = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
private constant integer PASSIVE_ID = 'A00Q' //raw code of the passive dummy ability that just is meant to keep track of the ability level.
private constant integer LINK_ABILITY = 'A03O' //raw code of the link ability.
private constant integer DESTROY_LINK = 'A046' //raw code of the destroy ability that destroys the links.
private constant integer DUMMY_SPELL = 'A016' //still need to see if I really need this ability or not.
private constant integer DAZE_DUMMY_ID = 'h03V' //still need to see if I really need this ability or not.
private constant attacktype A_TYPE = ATTACK_TYPE_CHAOS // Attack type of damage dealt by electricity to creeps.
private constant damagetype D_TYPE = DAMAGE_TYPE_UNIVERSAL // Damage type of damage dealt by electricity to creeps.
private constant weapontype W_TYPE = WEAPON_TYPE_WHOKNOWS // Weapon type of damage dealt by electricity to creeps.
private constant real EFFECT_HEIGHT = 100.00 //The height above ground that the lightning effect appears.
private constant string EFFECT_TYPE = "FORK" //The code of the type of lightning effect that appears.
private constant real TIMER_PERIOD = 2.00 //The speed at which the color of the lightning changes.
private constant real DAMAGE_PERIOD = 0.10 //The speed at which the lightning is checked to see if units are nearby and to damage them.
private constant string MESSAGE1 = "\nCannot build the Link Tower outside of range." //error message that appears
private constant string MESSAGE2 = "\nCannot build Link Tower too close to the Generator Tower." //error message that appears
private constant real MIN_DISTANCE = 128.00 //Minimum distance at which you cannot build a link tower
private constant real ANGLE_INCREMENT = 10.0 //Make sure this is divisible into 360 WITHOUT a remainder
endglobals
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private struct Generator
unit u //the generator tower
unit c //the link tower
unit d //daze casting dummy unit
player p //owner of generator
integer id //player id of owner
integer lvl //level of the base generator ability
integer cc = 1 //color counter, keeps track of the color array slot to use
real xu //x position of generator
real yu //y position of generator
real xc //x position of link tower
real yc //y position of link tower
effect array circ [100] //Array used to create and destroy the range circle
lightning e //lightning effect that is created
boolean bh = false //Builder Hit - checks if the builder has been dazed
boolean cool = false //DestroyLinkCoolDown - checks if the cooldown is happening or not
boolean link = false //LinkActive - checks if the link is established or not
endstruct
globals
private Generator array GeneratorStruct
private integer FilterPlayerId //The variable used to feed the player id to the filter function
private boolexpr DamageFilter
private string array LightningSFX
endglobals
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function Range takes integer lvl returns real
return 300.0 + (150.0 * lvl)
endfunction
private function Damage takes integer lvl returns real
return 0.0 + (1.0 * lvl)
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function Cond takes nothing returns boolean
local boolean a = GetOwningPlayer(GetTriggerUnit()) == GetTriggerPlayer()
local boolean b = (GetUnitTypeId(GetTriggerUnit()) == GENERATOR_TOWER_ID)
local boolean c = (GetUnitTypeId(GetTriggerUnit()) == GENERATOR_2_TOWER_ID)
local boolean d = (GetUnitTypeId(GetTriggerUnit()) == GENERATOR_3_TOWER_ID)
return a and (b or c or d)
endfunction
private function UpgradeCondition takes nothing returns boolean
return (GetUnitLevel(BuilderChosen[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))+1]) >= 30)
endfunction
private function LinkTowerCond takes nothing returns boolean
return GetSpellAbilityId() == LINK_ABILITY
endfunction
private function LinkTowerCheck takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == GENERATOR_LINK_TOWER_ID
endfunction
private function DestroyLinkCheck takes nothing returns boolean
return (GetSpellAbilityId() == DESTROY_LINK) or (GetSpellAbilityId() == SELL_ID) or (GetSpellAbilityId() == DEMOLISH_ID)
endfunction
private function FilterTargets takes unit filter returns boolean
return IsUnitType(filter,UNIT_TYPE_STRUCTURE) == false and (GetWidgetLife(filter) > 0.406) and IsUnitType(filter,UNIT_TYPE_FLYING) == false
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function DamageFilterActions takes nothing returns boolean
local Generator g = GeneratorStruct[FilterPlayerId]
local integer n = GetRandomInt(0,100)
if FilterTargets(GetFilterUnit()) then
if IsUnitInRangeOfSegment(GetFilterUnit(), g.xu, g.yu, g.xc, g.yc, 40.0) == true then
if GetFilterUnit() == BuilderChosen[g.id+1] then //If your builder touches the electricity, he gets dazed.
if g.bh == false then
set g.bh = true
set g.d = CreateUnit(Player(11), DAZE_DUMMY_ID, g.xu, g.yu, 0)
call UnitApplyTimedLife(g.d, 'BTLF', 1.)
call UnitAddAbility(g.d, DUMMY_SPELL)
call SetUnitAbilityLevel(g.d, DUMMY_SPELL, g.lvl)
call IssueTargetOrder(g.d, "slow", GetFilterUnit())
call DestroyEffect(AddSpecialEffectTarget(UNIT_SFX_HIT, GetFilterUnit(), "chest"))
endif
else
call UnitDamageTarget(g.u, GetFilterUnit(), Damage(g.lvl), false, false, A_TYPE, D_TYPE, W_TYPE)
if n > 90 then
call DestroyEffect(AddSpecialEffectTarget(UNIT_SFX_HIT, GetFilterUnit(), "chest"))
endif
endif
endif
endif
return false
endfunction
private function GeneratorDamage takes nothing returns nothing
local Generator g = Generator(GetTimerData(GetExpiredTimer()))
set FilterPlayerId = g.id
call GroupEnumUnitsInRangeOfSegment(ENUM_GROUP, g.xu, g.yu, g.xc, g.yc, 1.0, DamageFilter)
if g.link == false then
call ReleaseTimer(GetExpiredTimer())
// call BJDebugMsg("Timer is being released")
endif
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function ChangeLightningColor takes nothing returns nothing
local Generator g = Generator(GetTimerData(GetExpiredTimer()))
local integer i = g.cc
local integer n = GetRandomInt(1,100)
if g.link == false then
call ReleaseTimer(GetExpiredTimer())
// call BJDebugMsg("Timer is being released")
else
if n > 95 then
set n = GetRandomInt(0,2)
call DestroyEffect(AddSpecialEffect(LightningSFX[n], GetUnitX(g.u), GetUnitY(g.u)))
call DestroyEffect(AddSpecialEffect(LightningSFX[n], GetUnitX(g.c), GetUnitY(g.c)))
endif
call SetLightningColor(g.e, RedColor[g.cc], GreenColor[g.cc], BlueColor[g.cc], 1.0)
if g.cc == 51 then
set g.cc = 1
else
set g.cc = g.cc + 1
endif
set g.bh = false
endif
endfunction
private function CreateLink takes Generator g returns nothing
local timer t = NewTimer()
local timer damagetimer = NewTimer()
local integer n = GetRandomInt(0,2)
local real zu
local real zc
set g.xu = GetUnitX(g.u)
set g.yu = GetUnitY(g.u)
set g.xc = GetUnitX(g.c)
set g.yc = GetUnitY(g.c)
set zu = GetPointZ(g.xu, g.yu) + EFFECT_HEIGHT
set zc = GetPointZ(g.xc, g.yc) + EFFECT_HEIGHT
call DestroyEffect(AddSpecialEffect(LightningSFX[n], g.xu, g.yu))
call DestroyEffect(AddSpecialEffect(LightningSFX[n], g.xc, g.yc))
set g.e = AddLightningEx(EFFECT_TYPE, false, g.xu, g.yu, zu, g.xc, g.yc, zc)
call SetLightningColor(g.e, 1.0, 0.0, 0.0, 1.0)
set g.link = true
call SetTimerData(t, g)
call TimerStart(t, TIMER_PERIOD, true, function ChangeLightningColor)
call SetTimerData(damagetimer, g)
call TimerStart(damagetimer, DAMAGE_PERIOD, true, function GeneratorDamage)
set t = null
set damagetimer = null
endfunction
private function BreakLink takes Generator g returns nothing
set g.link = false
call DestroyLightning(g.e)
call KillUnit(g.c)
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function SelectActions takes Generator g returns nothing //These actions happen when you select the tower. It creates the range ring around the tower.
local integer n = 0
local rect r = PlayerArea[POS[g.id+1]]
local real x
local real y
local real offset = 50.0
local real angle = 0.0
loop
exitwhen n > (360.0/ANGLE_INCREMENT)
if g.circ[n] != null then
call DestroyEffect(g.circ[n])
set g.circ[n] = null
endif
set x = g.xu + Range(g.lvl) * Cos( (angle + ANGLE_INCREMENT * n) * bj_DEGTORAD)
set y = g.yu + Range(g.lvl) * Sin( (angle + ANGLE_INCREMENT * n) * bj_DEGTORAD)
if x <= GetRectMinX(r) then
set x = GetRectMinX(r) + offset
endif
if x >= GetRectMaxX(r) then
set x = GetRectMaxX(r) - offset
endif
if y <= GetRectMinY(r) then
set y = GetRectMinY(r) + offset
endif
if y >= GetRectMaxY(r) then
set y = GetRectMaxY(r) - offset
endif
set g.circ[n] = AddSpecialEffect(CIRCLE_SFX, x, y)
set n = n + 1
endloop
endfunction
private function SelectEvent takes nothing returns nothing
local Generator g = GeneratorStruct[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
call SelectActions(g)
endfunction
private function DeselectActions takes Generator g returns nothing //These actions happen when you deselect the tower. It destroys the range ring around the tower.
local integer n = 0
loop
exitwhen n > (360.0/ANGLE_INCREMENT)
call DestroyEffect(g.circ[n])
set g.circ[n] = null
set n = n + 1
endloop
endfunction
private function DeselectEvent takes nothing returns nothing
local Generator g = GeneratorStruct[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
call DeselectActions(g)
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function LinkTowerBuild takes nothing returns nothing //This is the ability to build the link tower
local Generator g = GeneratorStruct[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
local location trgt = GetSpellTargetLoc()
local real tx = GetLocationX(trgt)
local real ty = GetLocationY(trgt)
local real dx = tx - g.xu
local real dy = ty - g.yu
local real Dist = SquareRoot(dx * dx + dy * dy)
local rect r = PlayerArea[POS[g.id+1]]
if tx <= GetRectMinX(r) or tx >= GetRectMaxX(r) or ty <= GetRectMinY(r) or ty >= GetRectMaxY(r) then
call SetUnitPosition(g.u, g.xu, g.yu) //This is meant to stop the tower's ability from working...cancelling the link tower creation ability.
call SimError(g.p, MESSAGE1)
elseif Dist > Range(g.lvl) then
call SetUnitPosition(g.u, g.xu, g.yu) //This is meant to stop the tower's ability from working...cancelling the link tower creation ability.
call SimError(g.p, MESSAGE1)
elseif Dist < MIN_DISTANCE then
call SetUnitPosition(g.u, g.xu, g.yu) //This is meant to stop the tower's ability from working...cancelling the link tower creation ability.
call SimError(g.p, MESSAGE2)
endif
call RemoveLocation(trgt)
set trgt = null
endfunction
private function LinkTowerConstruction takes nothing returns nothing //This is the detection of the actual finished construction of the link tower
local Generator g = GeneratorStruct[GetPlayerId(GetOwningPlayer(GetConstructedStructure()))]
set g.c = GetConstructedStructure()
set g.xu = GetUnitX(g.c)
set g.yu = GetUnitY(g.c)
set g.cool = true //This is set to true so that the first time the generator uses the destroy link ability, that it does nothing.
call UnitAddAbility(g.u, DESTROY_LINK)
call SetUnitAbilityLevel(g.u, DESTROY_LINK, g.lvl)
call UnitRemoveAbility(g.u, LINK_ABILITY)
call IssueImmediateOrder(g.u, "tranquility") //This orders the Generator to use the Destroy Link ability so that it starts the cooldown.
call CreateLink(g)
endfunction
private function DestroyLinkCast takes nothing returns nothing
local Generator g = GeneratorStruct[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
if ( (GetSpellAbilityId() == SELL_ID) or (GetSpellAbilityId() == DEMOLISH_ID) ) and (g.lvl > 0) then
call DeselectActions(g)
call BreakLink(g)
call SellActions()
call g.destroy()
// call BJDebugMsg("Struct destroyed")
elseif g.cool == false then
call BreakLink(g)
call UnitAddAbility(g.u, LINK_ABILITY)
call SetUnitAbilityLevel(g.u, LINK_ABILITY, g.lvl)
call UnitRemoveAbility(g.u, DESTROY_LINK)
else
set g.cool = false
endif
endfunction
private function GeneratorUpgrade takes nothing returns nothing
local integer id = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
local integer i = GetUnitTypeId(GetTriggerUnit())
local Generator g
if (i == GENERATOR_TOWER_ID) then
set GeneratorStruct[id] = Generator.create()
set g = GeneratorStruct[id]
set g.u = GetTriggerUnit()
set g.p = GetOwningPlayer(g.u)
set g.id = GetPlayerId(g.p)
set g.lvl = GetUnitAbilityLevel(g.u, PASSIVE_ID)
set g.xu = GetUnitX(g.u)
set g.yu = GetUnitY(g.u)
call SelectActions(g)
elseif (i == GENERATOR_2_TOWER_ID) or (i == GENERATOR_3_TOWER_ID) then
set g = GeneratorStruct[id]
call IncUnitAbilityLevel(GetTriggerUnit(), PASSIVE_ID)
set g.lvl = GetUnitAbilityLevel(GetTriggerUnit(), PASSIVE_ID)
call SelectActions(g)
call DestroyLinkCast()
endif
endfunction
//*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~
private function Init takes nothing returns nothing
local integer n = 0
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
local trigger t3 = CreateTrigger()
local trigger t4 = CreateTrigger()
local trigger t5 = CreateTrigger()
local trigger t6 = CreateTrigger()
loop
exitwhen n > 7
call TriggerRegisterPlayerUnitEvent(t1, Player(n), EVENT_PLAYER_UNIT_SELECTED, null)
call TriggerRegisterPlayerUnitEvent(t2, Player(n), EVENT_PLAYER_UNIT_DESELECTED, null)
call TriggerRegisterPlayerUnitEvent(t3, Player(n), EVENT_PLAYER_UNIT_SPELL_CAST, null)
call TriggerRegisterPlayerUnitEvent(t4, Player(n), EVENT_PLAYER_UNIT_UPGRADE_FINISH, null)
call TriggerRegisterPlayerUnitEvent(t5, Player(n), EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, null)
call TriggerRegisterPlayerUnitEvent(t6, Player(n), EVENT_PLAYER_UNIT_SPELL_CAST, null)
set n = n + 1
endloop
call TriggerAddCondition(t1, Condition(function Cond))
call TriggerAddCondition(t2, Condition(function Cond))
call TriggerAddCondition(t3, Condition(function LinkTowerCond))
call TriggerAddCondition(t4, Condition(function UpgradeCondition))
call TriggerAddCondition(t5, Condition(function LinkTowerCheck))
call TriggerAddCondition(t6, Condition(function DestroyLinkCheck))
call TriggerAddAction(t1, function SelectEvent)
call TriggerAddAction(t2, function DeselectEvent)
call TriggerAddAction(t3, function LinkTowerBuild)
call TriggerAddAction(t4, function GeneratorUpgrade)
call TriggerAddAction(t5, function LinkTowerConstruction)
call TriggerAddAction(t6, function DestroyLinkCast)
set DamageFilter = Condition(function DamageFilterActions)
set LightningSFX[0] = "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
set LightningSFX[1] = "Abilities\\Spells\\Items\\AIlb\\AIlbSpecialArt.mdl"
set LightningSFX[2] = "Abilities\\Weapons\\Bolt\\BoltImpact.mdl"
endfunction
endscope
It ended up becoming quite long. I took the screenshot a little zoomed out so you could easily see everything. The blue circle thingy you see around the Generator is created whenever you have the generator selected, and destroyed when you deselect the generator. It is meant to easily let you determine visually the limits of how far away you can place your link tower.
You can't really appriciate the coolness of the Generator tower until you see it in action. If anyone would like to try it out, let me know and I'll hook you up
I'm currently rewriting the Vacuum tower. It ended up breaking due to the retarded coder who used GetUserUnitData and SetUserUnitData. Some other systems in my map ended up breaking that, and thus the tower no longer worked. As of right now, I got the tower working correctly, and I just need to add in its upgrades and such.