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.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +1
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top