Interesting Ability Trouble

emjlr3

Change can be a good thing
Reaction score
395
attempting to make an ability, "Prism", that can do some unique things

it is used by towers, and you can connect to other towers, through channeling, and add bonus damage above and beyond your own to it, and can cancel at any time

so say this tower clicks on that tower, it will channel and add X damage to it

now this can be done by any number of towers, to any number of other towers

this in itself is easy, add damage ability to target if it does not have it, else increase the level by 1, when the casting tower stops channeling, remove the added ability if it is at level 1, or decrease the level by 1

here is where it gets interesting

I want to be able to stack these buffs around ,from tower to tower

for instance, you have 4 towers

tower 1 channels on tower 2, and adds the bonus, tower 2 then channels on tower 3, thus adding two bonuses, tower 3 then channels on tower 4, adding 3 bonuses, and tower 4 ending pu having the only bonuses

then for instance, tower 2 stops channeling, therefore tower 2 should have 1 bonus, and tower 4 should have 1 bonus

complicated enough?

here is the catch, I tried to develop a method to go about tracking these additions and subtractions to amek them stackable from tower to tower, and was unsuccesful

anyoe have any suggestions of how to go about doing so, or possibly an example of such?

ty
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
If one tower can cast Prism on multiple targets, but Prism is a channelling spell...
 

phyrex1an

Staff Member and irregular helper
Reaction score
447
Sounds as each tower is a node in a dual linked list, when a tower stops channeling just traverse "upwards" in the list of that tower and collect the bonuses, then traverse "downwards" in the list and remove bonus while also collecting the bonuses for those towers, finally split the list in two by ejecting the "current" tower.

Edit: And 5 seconds later I understand that a tower can be targeted by more than one tower at once :) Then a tower would be a node in a tree.
 

Sooda

Diversity enchants
Reaction score
318
> then for instance, tower 2 stops channeling, therefore tower 2 should have 1 bonus, and tower 4 should have 1 bonus

You mean Tower 4 gets 1 bonus less aka 3 bonuses ? If you would target with Tower 1 Tower 2 and with Tower 2 Tower 1 it would mean infinite loop :rolleyes:
Here comes the problem. It' s like electric current or something if something gets bonus then would that Tower channel damage increase ? Then it would cause still one big infinite loop if last tower would start to channel back to it' s 'web'. Though it would suck if you have to manually each time again channel if Tower damage increases.
 

emjlr3

Change can be a good thing
Reaction score
395
Sounds as each tower is a node in a dual linked list, when a tower stops channeling just traverse "upwards" in the list of that tower and collect the bonuses, then traverse "downwards" in the list and remove bonus while also collecting the bonuses for those towers, finally split the list in two by ejecting the "current" tower.

Edit: And 5 seconds later I understand that a tower can be targeted by more than one tower at once :) Then a tower would be a node in a tree.

wha...???

> then for instance, tower 2 stops channeling, therefore tower 2 should have 1 bonus, and tower 4 should have 1 bonus

You mean Tower 4 gets 1 bonus less aka 3 bonuses ? If you would target with Tower 1 Tower 2 and with Tower 2 Tower 1 it would mean infinite loop :rolleyes:
Here comes the problem. It' s like electric current or something if something gets bonus then would that Tower channel damage increase ? Then it would cause still one big infinite loop if last tower would start to channel back to it' s 'web'. Though it would suck if you have to manually each time again channel if Tower damage increases.

you cannot target towers already channeling, that would be dumb
 

emjlr3

Change can be a good thing
Reaction score
395
thats kind of common sense

why would u target a tower that is channeling and cannot attack?

i know some idiots would, so I have a check for it
 

2-P

I will work hard tomorrow
Reaction score
325
I made the spell with the towers using mana to store the "prism energy". Don't know if using mana (or custom unit value, since that should work the same way) is ok for you. =/
Well, maybe it helps.

JASS:
function CondPrism takes nothing returns boolean
  return GetSpellAbilityId() == 'A000'
endfunction

function CondPrismChannel takes nothing returns boolean
  return OrderId2String(GetUnitCurrentOrder(GetSpellTargetUnit())) != "voodoo"
endfunction

function PrismChannel takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetCSData(t)
local unit caster = GetArrayUnit(i, 0)
local unit target = GetArrayUnit(i, 1)
local string order = OrderId2String(GetUnitCurrentOrder(caster))
local real manaold = GetArrayReal(i, 2)
local real manacaster = GetUnitState(caster, UNIT_STATE_MANA)
local real manatarget = GetUnitState(target, UNIT_STATE_MANA)

  if order != "voodoo" then
    call SetUnitState(target, UNIT_STATE_MANA, manatarget - manaold - 1)
    call SetUnitAbilityLevel(target, 'A003', R2I(GetUnitState(target, UNIT_STATE_MANA)))   
    call UnitRemoveAbility(caster, 'A001')
    call UnitAddAbility(caster, 'A000')
    call PauseTimer(t)
    call DestroyArray(i)
    call ReleaseTimer(t)
  endif
  
  if manaold != manacaster then
    call SetUnitState(target, UNIT_STATE_MANA, manatarget - manaold + manacaster)
    call SetUnitAbilityLevel(target, 'A003', R2I(GetUnitState(target, UNIT_STATE_MANA)))
    call SetUnitAbilityLevel(caster, 'A003', R2I(GetUnitState(caster, UNIT_STATE_MANA)))        
  endif

  if GetUnitState(target, UNIT_STATE_MANA) == 0 then
    call UnitRemoveAbility(target, 'A003')
  endif

  call SetArrayReal(i, 2, manacaster)
  call SetCSData(t, i)

  set t = null
  set caster = null
  set target = null

endfunction

function Prism takes nothing returns nothing
local timer t = NewTimer()
local integer i = NewArray(3, false)
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local real manacaster = GetUnitState(caster, UNIT_STATE_MANA)
local real manatarget = GetUnitState(target, UNIT_STATE_MANA)

  call SetUnitState(target, UNIT_STATE_MANA, manatarget + manacaster + 1)
  call UnitAddAbility(target, 'A003')
  call SetUnitAbilityLevel(target, 'A003', R2I(GetUnitState(target, UNIT_STATE_MANA)))

  call UnitRemoveAbility(caster, 'A000')
  call UnitAddAbility(caster, 'A001')
  call IssueImmediateOrder(caster, "voodoo")
  
  call SetArrayObject(i, 0, caster)
  call SetArrayObject(i, 1, target)
  call SetArrayReal(i, 2, manacaster)
  call SetCSData(t, i)
  call TimerStart(t, 0.05, true, function PrismChannel)

  set t = null
  set caster = null
  set target = null

endfunction

//===========================================================================
function InitTrig_Prism takes nothing returns nothing
    set gg_trg_Prism = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Prism, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Prism, Condition(function CondPrism))
    call TriggerAddCondition(gg_trg_Prism, Condition(function CondPrismChannel))    
    call TriggerAddAction(gg_trg_Prism, function Prism)
endfunction
 

Attachments

  • PrismTower.w3x
    57 KB · Views: 169

Sooda

Diversity enchants
Reaction score
318
> now this can be done by any number of towers, to any number of other towers

Yeah, found out why I posted that. Because of that sentence. Common sense isn' t so common you know ?
 

Weyrling

New Member
Reaction score
25
You could make them continously lose mana, and make the channel a mana drain that adds mana to a targeted tower, and increases in level when targeted upon, then you could make a leveled auto-cast attack that requires mana.
 
W

wantok

Guest
How about something like this?

JASS:
struct PRISM
    integer linked = 1 //this number will increase as more towers channel into this tower
    unit target = null //the tower this unit is currently channeling into
    unit thistower
endstruct

//Attach one of these structs to each of the tower units directly after its created. I'm assuming the unit's custom value was used in this case.

function powerup takes nothing returns nothing  //call this function when one tower starts channeling on another
    local unit u = GetTriggerUnit()
    local PRISM dat1 = PRISM(GetUnitUserData(u))
    local PRISM prism1 = dat1// this just stores the original struct to refer back to later
    local PRISM prism2 
    local PRISM dat2
    local integer addedlinks
    
    set dat1.target = GetSpellTargetUnit()
    set dat2 = PRISM(GetUnitUserData(dat1.target))//this gets the struct attached to the tower that is being targeted
    set prism2 = dat2// stores the original struct to refer to later
    loop
          // this loop is to make sure that the towers are not forming an infinite loop
          // of increasing power. It cycles through the target's target's target...etc 
          //until the next target is either null or the original triggering tower.
        exitwhen dat2.target == null
        if dat2.target == u then
            call BJDebugMsg("You can't make a loop, you crazy bastard!")
            set prism1.target = null  //reset the triggering tower's target to null since it was changed above
            return
        endif
        set dat1 = dat2
        set dat2 = PRISM(GetUnitUserData(dat1.target))
    endloop
    //now it's time to add the bonuses
    set dat1 = prism1
    set dat2 = prism2
    set addedlinks = dat1.linked  //this is the number of towers currently linked to the triggering tower (including the triggering tower).
    set dat2.linked = dat2.linked + addedlinks  //so we add that number to the targeted tower.
    //increase ability level of the targeted tower here based on its .linked value
    loop  //if the targeted tower is not channeling into another tower, it ends here.
            //if it is channeling however, the bonus is passed along down the line until we reach a tower with no target.
        exitwhen dat2.target == null
        set dat1 = dat2
        set dat2 = PRISM(GetUnitUserData(dat1.target))
        set dat2.linked= dat2.linked + addedlinks
        //increase ability level here
    endloop
    set u = null
endfunction

function powerdown takes nothing returns nothing  //to be called when a tower stops channeling
    local PRISM dat1 = PRISM(GetUnitUserData(GetTriggerUnit()))
    local PRISM dat2
    local integer removedlinks = dat1.linked
    set dat2 = PRISM(GetUnitUserData(dat1.target))
    set dat2.linked = dat2.linked - removedlinks //removes the bonus from the previously targetted tower
    //decrease ability level
    set dat1.target = null
    loop //remove the bonuses from any other towers that may be further down the line
        exitwhen dat2.target == null
        set dat1 = dat2
        set dat2 = PRISM(GetUnitUserData(dat1.target)
        set dat2.linked= dat2.linked - removedlinks
        //decrease ability level
    endloop
endfunction


This should allow people to target towers that are already channeling as well since it detects if they make them all connect in a loop.
 

emjlr3

Change can be a good thing
Reaction score
395
a little documentation would be nice guys, its a little hard for me to comprehend what you are doing
 
W

wantok

Guest
I added some comments to mine. Hopefully it's understandable now.
 

emjlr3

Change can be a good thing
Reaction score
395
how exactly is something like

PRISM(GetUnitUserData(u))

working?

whenever I made a struct, I would use structname.create()

that seems to be a different method, not real sure how that works, nor have I used it

that part confuses me a bit

in anycase, I am not 100% sure if this works how I want it, and am still a bit confused with how it works

it seems as though you are adding abilities to every linked tower, when only the final tower in a link should have the bonuses

however, this does give me a little idea of possibly how to do it myself, if I were to ever get around to it...
 
W

wantok

Guest
PRISM(GetUnitUserData(u)) is not creating a new struct. I assumed the necessary structs had already been created and attached using custom value to the towers at the time of their (the towers) creation.

PRISM(some integer here) just typecasts the integer into the type of the PRISM struct. I don't believe it is required that you do it this way.

local PRISM dat = GetUnitUserData(u) should work as well.

As for not adding the bonuses to every tower; I misunderstood you I guess, but that should be easy enough to change.
 

Karawasa

Element Tower Defense
Reaction score
38
Sounds as each tower is a node in a dual linked list, when a tower stops channeling just traverse "upwards" in the list of that tower and collect the bonuses, then traverse "downwards" in the list and remove bonus while also collecting the bonuses for those towers, finally split the list in two by ejecting the "current" tower.

Edit: And 5 seconds later I understand that a tower can be targeted by more than one tower at once :) Then a tower would be a node in a tree.

I would appreciate if you could elaborate for emjlr3, so that he can successfully code this.
 

phyrex1an

Staff Member and irregular helper
Reaction score
447
Dunno where I got the Tree idea from, with some thinking I realized that a tower doesn't really have to know what other towers are increasing it's power so a tree is overkill.

addBonus and removeBonus obviously should to something more than just increasing selfBonus.

JASS:
struct Prism
     private Prism target  = 0
     private unit prismUnit // Isn't used atm, you want to use this in add/removeBonus
     private integer selfBonus = 0 // What bonus this Prism has
     private integer giveBonus = 1 // What bonus it gives, this should probably change with level...

     public static method new takes unit whichUnit returns Prism
            local Prism p = Prism.create()
            p.prismUnit = whichUnit
            return p
     endmethod

     public method addBonus takes integer bonus returns nothing
           set this.selfBonus = this.selfBonus + bonus
           if this.target != 0 then
               call this.target.addBonus(bonus)
          endif    
     endmethod

     public method removeBonus takes integer bonus returns nothing
           set this.selfBonus = this.selfBonus - bonus
           if this.target != 0 then
               call this.target.removeBonus(bonus)
           endif
     endmethod

     // Assumes that you don't already have a target
     public method castPrismOn takes Prism whatPrism returns nothing
           call whatPrism.addBonus(this.selfBonus + this.giveBonus)
           set this.target  = whatPrism            
     endmethod

     // Assumes that you have a target
     public method stopChannelPrism takes nothing returns nothing
            call this.target.removeBonus(this.selfBonus + this.giveBonus)
            set this.target = 0
     endmethod
endstruct

If my thinking isn't completely off then this should be enough.
 

Karawasa

Element Tower Defense
Reaction score
38
phyrex1an,

emjlr3 is busy the next few days, and so does not have time to look into this. There is some urgency to getting this coded, so I humbly ask a favor. Would you be willing to provide your expertise with nodes and modify the trigger we currently have? Would be much appreciated, as it would save a great deal of time.

JASS:
//Implementation: *create and active unit ally targetable ability to be detected when cast
//                *copy over my damage dummy ability for the tower and this trigger
//                *configure options given and check it up! 
//Documentation: Works well, neat ability I think.  You may want to add effects to the ability data
//               so users can see something when cast, or between the target and caster towers, like
//               channel lightning. 

scope Prism

globals
    //config. options:
    private constant integer tower1_id = 'h001' //rwcode of level 1 tower
    private constant integer tower2_id = 'h000' //rawcode of level 2 tower
    private constant integer abil_id = 'A001' //rawcode of ability
    private constant integer dum1_id = 'A002' //rawcode of dummy damage level 1 ability
    private constant integer dum2_id = 'A003' //rawcode of dummy damage level 2 ability 
    private constant integer max = 25 //max level of added damage ability
    private constant string wrong1 = "You may only cast this on Level 1 Reflection Towers." //simerror for level 1 towers
    private constant string wrong2 = "You may only cast this on Level 2 Reflection Towers." //simerror for level 2 towers
    
    //needed variables:
    private sound SimError = null
endglobals
private function get_abil takes unit tower returns integer
    if GetUnitTypeId(tower)==tower1_id then
        return dum1_id
    else
        return dum2_id
    endif
endfunction
private struct data
    unit targ
endstruct


function Trig_Prism_Conditions takes nothing returns boolean     
    return GetSpellAbilityId()==abil_id 
endfunction  
function Prism_SimError takes player ForPlayer, string msg returns nothing
    if SimError==null then
        set SimError=CreateSoundFromLabel( "InterfaceError",false,false,false,10,10)
    endif
    if (GetLocalPlayer() == ForPlayer) then
        call ClearTextMessages()
        call DisplayTimedTextToPlayer( ForPlayer, 0.52, -1.00, 2.00, "|cffffcc00"+msg+"|r" )
        call StartSound( SimError )
    endif
endfunction
function Prism_End takes nothing returns boolean
    local trigger trig = GetTriggeringTrigger()
    local data dat = GetData(trig)
    local integer lvl = GetUnitAbilityLevel(dat.targ,get_abil(dat.targ))
    
    if lvl==1 then
        call UnitRemoveAbility(dat.targ,get_abil(dat.targ))
    else
        call SetUnitAbilityLevel(dat.targ,get_abil(dat.targ),lvl-1)
    endif
    call dat.destroy()
    call DestroyTrigger(trig)
    
    set trig = null
    return false
endfunction
function Trig_Prism_Actions takes nothing returns nothing
    local unit cast = GetTriggerUnit()
    local unit targ = GetSpellTargetUnit() 
    local trigger trig = CreateTrigger()
    local integer lvl = GetUnitAbilityLevel(targ,get_abil(targ))
    local data dat = data.create()
    
    call TriggerRegisterUnitEvent(trig,cast,EVENT_UNIT_SPELL_ENDCAST)
    call TriggerAddCondition(trig,Condition(function Prism_End))
    set dat.targ = targ
    call SetData(trig,dat)
    
    if lvl==0 then
        call UnitAddAbility(targ,get_abil(targ))
    elseif lvl<max then
        call SetUnitAbilityLevel(targ,get_abil(targ),lvl+1)
    endif   
    
    set cast = null
    set targ = null
    set trig = null
endfunction      
function Prism_Check takes nothing returns boolean
    local unit u = GetTriggerUnit()
    
    if GetUnitTypeId(u)==tower1_id and GetUnitTypeId(GetSpellTargetUnit())!=tower1_id then
        call PauseUnit(u,true)
        call IssueImmediateOrder(u,"stop")
        call PauseUnit(u,false)
        call Prism_SimError(GetOwningPlayer(u),wrong1)
        set u = null
        return false
    elseif GetUnitTypeId(u)==tower2_id and GetUnitTypeId(GetSpellTargetUnit())!=tower2_id then
        call PauseUnit(u,true)
        call IssueImmediateOrder(u,"stop")
        call PauseUnit(u,false)
        call Prism_SimError(GetOwningPlayer(u),wrong2)
        set u = null
        return false
    endif

    return false
endfunction 

endscope

//==== Init Trigger Prism ====
function InitTrig_Prism takes nothing returns nothing
    local trigger trig = CreateTrigger()
    
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition(trig, Condition(function Prism_Check))
    
    set gg_trg_Prism = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Prism,EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition(gg_trg_Prism, Condition(function Trig_Prism_Conditions))
    call TriggerAddAction(gg_trg_Prism, function Trig_Prism_Actions)
    
    set trig = null
endfunction
 

emjlr3

Change can be a good thing
Reaction score
395
currently, the tower that you link to gets the bonus, and the bonuses do not transfer to the last of a link, nor get sent back if a part of a link is broken

we need it updated, and I still dont get how to do it, do transfer bonuses around as links grow, to the last tower in a series, and to trasnfer the bonuses back to the last in a series if a part of the current series is broken
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top