System BuffStruct

So if someone has [ljass]'A000'[/LJASS] in their map and you overwrite it, they can't get it back unless it's backed up, and there's no warning it will be overwritten, so it's ... bad.
Whilst I agree on principle, it's in the config section for that very reason... it is not difficult to change. Also, I don't see how any script could detect this (especially not correctly) since I can have two buffs with the same name, one positive and one negative, which are different objects. Keeping in mind that buffs made by BuffStruct are never removed, but are purposefully overwritten every time you save, what if you change a buff slightly? I don't believe a script can do this right for BuffStruct.

I also agree with Blade, but admit it's not perfect.

Edit:
And there is absolutely no documentation on that link. Sorry, it is unhelpful as it describes nothing about how it works or what it does.
 
Well, LUA_GET_VAR_OBJECT retrieves values by variables rather than by value, so you can label your values. If you have 2 of the same buff with +-, then make one like BUFF_POS and other BUFF_NEG.

As it says in the link, it essentially lets you do this
[ljass]constant integer UNITS_PEASANT='hpea'[/ljass]

Where the UNITS_PEASANT is a 100% dynamic variables (the values is generated by lua and the variable is imported into the map).

Getting a dynamic variable is pretty easy-
function getvarobject(base, objtype, varname, import)

getvarobject returns the id generated for the specific variable given a base id, object type, variable name, and whether or not the variable should be imported into the map.

For example, to get that UNITS_PEASANT (w/ some unknown id)

id = getvarobject("hpea", "units", "UNITS_PEASANT", true)

that would return a unique id for an object based on the peasant. It would also import a variable called UNITS_PEASANT that has the id in it. If you were to use this function on a variable that already exists-

id = getvarobject("hpea", "units", "UNITS_PEASANT", true)
id = getvarobject("hpea", "units", "UNITS_PEASANT", true)

It would return the same id each time as it first looks up the variable for the specific map before generating a new id. This means that you ids are safe.

It keeps a persistent table in the background for each map that catalogs all of the generated ids and their variables, meaning you will never have a collision and deleting a script/objects from the map is safe.

getvarobjectname(value) will retrieve the variable name of a value. Now this could receive an update to retrieve a variable given a value and an object type since values between object types don't collide, but eh ;D. So yes, this makes it so 0 ids collide, even between object types.


getvarobjectvalue(objectname) retrieves the value given a variable


When finished generating objects, you call function updateobjects() to update the table.

Example from UnitIndexer
JASS:

//! externalblock extension=lua ObjectMerger $FILENAME$
    //place the file header
    //! runtextmacro LUA_FILE_HEADER()

    //import the script
    //! i dofile("GetVarObject")
    
    //get the dynamic object id and import it under ABILITIES_UNIT_INDEXER var
    //! i local id = getvarobject("Adef", "abilities", "ABILITIES_UNIT_INDEXER", true)
    
    //create the object
    //! i createobject("Adef", id)
    //! i makechange(current, "anam", "Unit Indexing")
    //! i makechange(current, "ansf", "(Unit Indexing)")
    //! i makechange(current, "aart", "")
    //! i makechange(current, "arac", "0")
    
    //update the persistent table for the map
    //! i updateobjects()
//! endexternalblock
 
Too bad the bug with the bufficon removal on multiple buff instances of same type has not been fixed, is there some kind of inofficial fix somewhere? Otherwise im really thinking about fixing it, should be less work then writing a similar system from scratch.
 
Ahh.. busy on my project *_*.. if I recall correctly, it wasn't trivial because you can't nest text macros, so I'd have had to use a hashtable to do the attachment, instead of AIDS... don't recall exactly... but I wanted to make AIDS a module, and I don't know if it was possible... so I should have just used a hashtable... zz...

There was some other thing, you could just use the original buff which was on the unit or something instead of adding it twice to the unit, and reference count it, so you didn't need the fix... which often makes more sense... so long ago... lol

More keen to work on my current project. :)
 
There should be a way to refresh the buff duration, get the remaining time of the buff, increase buff duration.
And more event responses maybe? Such as onSpellCast, onSelection, onKill, onXXX ...
 
As far as i remember this system doesnt even handle the duration of buffs (except the destroyeTimed), but you can code that yourself.

The problem i see about an integer that just counts the current instances on the unit via struct member is: This way you have only 1 instance of the buff + some information about how often its applied. If you want your buffs to have different values (like a buff that increases the targets damage dependent on the casters intelligence) you cannot store this information in one instance.

Imo, an easy solution would be:
Whenever a buff is removed you just loop through all buffs of the unit and search for other instances of that bufftype. The solution is O(n), but seriously, how many buffs do you usually have on a single unit? Im not sure how your data structure looks like, maybe you find a way you can skip some buffs (like only loop through buffs with same alignment).
 
There should be a way to refresh the buff duration, get the remaining time of the buff, increase buff duration.
And more event responses maybe? Such as onSpellCast, onSelection, onKill, onXXX ...
See: SpellStruct.
I used the systems in conjunction. SpellStruct would create/destroy BuffStructs, using its own timed methods, it's super easy, but SpellStruct was before its time, it seems.

That way you can control your buffs soooo readily and in any way you want. Use Status for status effects, wrap them into BuffStructs, and apply/remove them using SpellStruct. Feel the power!

Seriously, read the two demonstrations. SpellStruct = mapping on easy mode. It wraps all the nasties of WC3.

Protip: combine Damage into BuffStruct for some real OP mapping powerz.

In a handful of lines you can make something like a channeled ability that reduces all damage received by the target by 90% or something, with an icon on the buff tray and everything. And you can make other abilities dispel or steal the buff! :D
 
SpellStruct rocks, I must admit it. Each spell (except passive ones) is based on a SpellStruct (plus some data holder, dummy array structs, where needed), and hell yea, creating a spell is super easy and the output is super efficient. <3 J4L libraries.
 
Too bad the bug with the bufficon removal on multiple buff instances of same type has not been fixed, is there some kind of inofficial fix somewhere? Otherwise im really thinking about fixing it, should be less work then writing a similar system from scratch.

I just made a workaround for multi-instancing by having a separate BuffManager struct to count instances.
 
Is there a way to destroy/remove/dispel a buff without triggering the preDestroy event? Like in the Return example, if the Return buff is dispelled wouldn't dispelling make the unit move to their original position? Seems like that would not be the intended effect of a dispel.

Or would the right way to make a dispellable Return be to create a timer when the buff is created, when the timer expires make the unit move back to its original position and destroy the buff. Instead of relying on the destroy to cause the effect and a dispel would destroy the buff and end the timer before the unit gets moved back to its original position?
 
This is how I would do it. I would have all the stuff that happen when the spell ends in the preDestroy function or w/e. At the end of the timer and for the dispel, just check if the unit has the buff or not. That way, you can avoid the problem of doing the things twice and whatnot.

If that is not what you meant then explain a bit more and maybe I can offer a solution.
 
I know this hasn't been posted in for a while but I'm having a bug using it, the wrong buffs are being appplied. It doesn't actually effect the function of the spells but the wrong buff icon shows in the status tray which is a little annoying. The ability, intended buff and actually applied buff respectively are below.
Code:
//TESH.scrollpos=9
//TESH.alwaysfold=0
//! runtextmacro DurationBuff("HungryPseudopods")
scope HungryPseudopods initializer Init
globals
    private integer array Pods
    private constant integer ABILID = 'A0HP'
    private constant string PROJID = "HungryPseudopods"
    private constant string PODSON = "immolation"
    private constant string PODSOFF = "unimmolation"
endglobals

private struct Data
    unit caster
    boolean on
endstruct

private function Core takes nothing returns boolean
    local Data d = TT_GetData()
    local unit u = null
    local integer level = GetUnitAbilityLevel(d.caster,ABILID)
    local Projectile p
    if GetUnitAbilityLevel(d.caster,'B017') > 0 and d.on == true then
        set P = GetOwningPlayer(d.caster)
        call GroupEnumUnitsInRange(G2,GetUnitX(d.caster),GetUnitY(d.caster),450,Condition(function EnemyAliveFilter))
        loop
            set u = FirstOfGroup(G2)
            exitwhen u == null
            set p = Projectile.create()
            call p.ProjectileSetId(PROJID)
            call p.ProjectileSetModel("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayDamage.mdl",50,50,50,255,0.8)
            call p.ProjectileTargetHoming(d.caster,GetUnitX(d.caster),GetUnitY(d.caster),20,u,35)
            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayDamage.mdl",Projectile_HitUnit,"chest"))
            call GroupRemoveUnit(G2,u)
        endloop
    else
        set Pods[GetUnitId(d.caster)] = 0
        call d.destroy()
        return true
    endif
    return false
endfunction

private function ConditionsOn takes nothing returns boolean
    return OrderId2String(GetIssuedOrderId()) == PODSON
endfunction

private function ActionsOn takes nothing returns nothing
    local Data d = Data.create()
    set d.caster = GetOrderedUnit()
    set Pods[GetUnitId(d.caster)] = d
    set d.on = true
    call TT_StartEx(function Core,d,1)
endfunction

private function ConditionsOff takes nothing returns boolean
    return OrderId2String(GetIssuedOrderId()) == PODSOFF
endfunction

private function ActionsOff takes nothing returns nothing
    local Data d = Pods[GetUnitId(GetOrderedUnit())]
    set Pods[GetUnitId(GetOrderedUnit())] = 0
    set d.on = false
endfunction

private function HitConditions takes nothing returns boolean
    return Projectile_Id == PROJID
endfunction

private function HitActions takes nothing returns nothing
    local HungryPseudopods buf
    local unit BuffCaster = Projectile_Source
    local unit BuffTarget = Projectile_HitUnit
    set BuffAbilId = ABILID
//    call buf.create(BuffTarget).destroyTimed(1.5)
    call AddBuffHungryPseudopods(BuffCaster,BuffTarget,2,true)
    call Damage_Physical(BuffCaster,BuffTarget,GetUnitAbilityLevel(BuffCaster,ABILID)*2-1+0.1*GetHeroAgi(BuffCaster,true),DARKNESS,false,false)
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathandDecay\\DeathandDecayDamage.mdl",BuffTarget,"chest"))
    set BuffCaster = null
    set BuffTarget = null
endfunction

private function Init takes nothing returns nothing
    local trigger Trig = CreateTrigger()
    local trigger Trig2 = CreateTrigger()
    local trigger Hit = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(Trig,EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(Trig,Condition(function ConditionsOn))
    call TriggerAddAction(Trig,function ActionsOn)
    call TriggerRegisterAnyUnitEventBJ(Trig2,EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerAddCondition(Trig2,Condition(function ConditionsOff))
    call TriggerAddAction(Trig2,function ActionsOff)
    call TriggerRegisterEventProjectileHit(Hit)
    call TriggerAddCondition(Hit,Condition(function HitConditions))
    call TriggerAddAction(Hit,function HitActions)
endfunction

endscope
Code:
//! runtextmacro BuffType("HungryPseudopods")
    //! runtextmacro SetBuffName("Hungry Pseudopods")
    //! runtextmacro SetBuffAlignment("NEGATIVE")
    //! runtextmacro SetBuffTooltip("Being dissolved by pseudopods.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\PassiveButtons\\PASBTNPoisonSting.blp")
//! runtextmacro BuffStruct()
    unit caster
    unit target
    integer abilId
    integer armor
    method onCreate takes nothing returns nothing
        set this.abilId = BuffAbilId
        set this.caster = BuffCaster
        set this.target = BuffTarget
    endmethod
    method onApply takes nothing returns nothing
        set armor = GetUnitAbilityLevel(this.caster,this.abilId)*1
        call Status[this.unit].modArmorBonus(-armor)
   
    endmethod
    method onRemove takes nothing returns nothing
        call Status[this.unit].modArmorBonus(armor)
    endmethod
//! runtextmacro EndBuff()
Code:
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! runtextmacro BuffType("CalamitousGaze")
    //! runtextmacro SetBuffName("Calamitous Gaze")
    //! runtextmacro SetBuffAlignment("NEGATIVE")
    //! runtextmacro SetBuffTooltip("Bad luck gets you hurt.")
    //! runtextmacro SetBuffIcon("ReplaceableTextures\\CommandButtons\\BTNEyeofblood.blp")
//! runtextmacro BuffStruct()
    unit caster
    unit target
    integer attackSpeed
    method onCreate takes nothing returns nothing
        set this.caster = BuffCaster
        set this.target = BuffTarget
    endmethod
//! runtextmacro EndBuff()
However I have noticed that each buff being applied is one lower in the buffstruct section than the intended buff. So for example in the attached image Frazzle is applying Crystal Cage.
 

Attachments

  • buffs section.png
    buffs section.png
    26.9 KB · Views: 511
Is it possible that you have accidentally created an additional buffstruct somewhere in your code? I haven't ever used this library so I can't really tell what's the error, but I think your best shot is to go through the original JASS code.
 
I got it sorted out, my Jass Newgen didn't want to run text macros because of an extra folder in my warcraft install for modding UI. I just directed it to a different warcraft install cleaned of extra folders and everything worked fine.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Varine Varine:
    I would be there for days, even with my camera set up slides can take a long time, and if they want perfect captures I really need to use my scanners that are professionally made for that. My camera rig works well for what it is, but for enlargements and things it's not as good.
  • Varine Varine:
    I've only had a couple clients with that so far, though. I don't have a website or anything yet though.
  • Varine Varine:
    Console repair can be worthwhile, but it's also not a thing I can do at scale in my house. I just don't have room for the equipment. I need an office that I can segregate out for archival and then electronic restoration.
  • Varine Varine:
    But in order for that to be real, I need more time, and for more time I need to work less, and to work less I need a different job, and for a different job I need more money to fall back on so that I can make enough to just pay like, rent and utilities and use my savings to find these projects
    +1
  • Varine Varine:
    Another couple years. I just need to take it slow and it'll get there.
  • jonas jonas:
    any chance to get that stolen money back?
  • jonas jonas:
    Maybe you can do console repair just as a side thing, especially if there's so much competition business might be slow. Or do you need a lot of special equipment for that?
  • jonas jonas:
    I recently bought a used sauna and the preowner told me some component is broken, I took a look and it was just a burnt fuse, really cheap to fix. I was real proud of my self since I usually have two left hands for this kinda stuff :p
  • tom_mai78101 tom_mai78101:
    I am still playing Shapez 2. What an awful thing to happen, Varine, and hopefully everything has been sorted out soon. Always use multi-factor authentication whenever you have the opportunity to do so.
    +1
  • Varine Varine:
    I think all of the money is accounted for now, and all the cards have been changed out, so I think for the most part it's taken care of now. Just need to go through and make sure all of my accounts are secured again, it's just time consuming.
  • Varine Varine:
    And yeah everything has 2 factor turned on now, or at least everything I can think of at the moment.
  • Varine Varine:
    The consoles don't need too much equipment that I don't already have. I would like to get a reflow oven, but I don't really want to buy one so I'm thinking about modifying a toaster oven I have to make something that will work for what I'm doing.
  • Varine Varine:
    I have the soldering irons and reflow and all that, but without an oven it's kind of hard to build mod chips and things like that. I made a handful of them with a hot air station, but it's a pain.
  • Varine Varine:
    The only thing I'm not really set up for is BGA rework. I've done it before a little bit, but not reliably, and that equipment is wildly expensive. You need X-rays and shit.
  • Varine Varine:
    I also have a couple 3D printers. I'm not super good with those and need to get an enclosure built, but they'll be useful for some aesthetic mods I've been thinking about. At least I can use them to do designs and then just have someone else print out the parts for me once I know they work.
  • Varine Varine:
    I also use them to make adapters for all my camera shit, but that's also an on the side thing for now. Lens adapters get really expensive.
  • Varine Varine:
    I've been trying to do some little art pieces as well, but I'm not much an engineer so they haven't gone great. I got some new things showing up to try and play with
  • Varine Varine:
    I want to build this tesserect kind of thing with mirrors, and I've been trying to make this like black hole diorama. In my head it looks really cool, but I kind of thought I could form polarizing lenses into a sphere but I tend to just destroy them every time I try.
  • Varine Varine:
    So I got a new idea, but I'm not sure how to make it work like I want without being able to get a polarizer curved. I think they are made out of PVA typically, and I thought I could just heat it up a little bit to soften the film, but that clearly isn't working. So I'm going to try a few other things, I'm thinking if I put a mirror film over the polarizing film I might get something cool. I have some polarized LED's as well, and I think if I make a central light source I can use the mirrors combined with the polarizers to make that central light APPEAR black. I have next week off so I'm going to spend some time trying to figure it out
  • Varine Varine:
    The tesserect works, at least. I just need to figure out how to be able to assemble it, but I think I have a pretty good idea of how to go about it. Or at least a prototype of it. I'll post some pictures next week
  • jonas jonas:
    That last bit sounds like the last entry in a scientist's journal in a destroyed research facility in a post-apocalyptic video game
  • Varine Varine:
    lol it's not that exciting
  • Varine Varine:
    Shiny tho
  • Varine Varine:
    Basically it's a cube with a two way mirror on the inside, and then a smaller cube suspended in that with a mirrors on the outside of it. Kind of like those infinity pictures where they use two mirrors to go forever. Only it's twelve mirrors
  • Varine Varine:
    And the tiniest LED strip I could find

      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