• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[System] Instance DD

Level 25
Joined
Jun 5, 2008
Messages
2,572
Just wanted to share with you guys an system i wrote for my needs.

I didn't know where to put it for suggestions/comments so i guessed this is as good place as any.

Anyhow here is the code, please note i am not up to speed with current WC3 scripts as i started using jass a long time ago, then stopped and am only kind of using it for personal needs only.

I will probably refine it more since i grow quite fond of it. (add recycling triggers and more stuff)

Enjoy, and please do comment if you like the idea.
(Works by extending damageInstance by a normal struct, rewriting onDamageTaken/Dealt methods then calling SaveInstance(<struct>, <unit>))

JASS:
library InstanceDD initializer Init

globals
    private             trigger     EVENT_RESPONSE = CreateTrigger()
    private             trigger     RECYCLE_TRIG = CreateTrigger()
    
    private             hashtable   Dx
    
                        group       INSTANCE_GROUP = CreateGroup()
    private             group       ENUM_GROUP = CreateGroup()
    private             group       SAFETY_GROUP = CreateGroup()
endglobals

struct damageInstance

    stub method onDamageTaken takes unit source, unit target, real damage returns real
        return damage
    endmethod
    
    stub method onDamageDealt takes unit source, unit target, real damage returns real
        return damage
    endmethod

endstruct

private struct dd
    
    unit u
    integer stack
    
    method  release takes nothing returns nothing
        local integer i = 1
        local damageInstance t
        loop
            exitwhen i > .stack
            set t = LoadInteger(Dx, GetHandleId(.u), i)
            call t.destroy()
            set i = i +1
        endloop
        set .u = null
        call .destroy()
    endmethod
    
    method run takes unit source, unit target, real damage returns nothing
        local integer i = 1
        local integer max
        local real oldDmg = damage
        local real newDmg = damage
        local damageInstance t
        local dd other
        if IsUnitInGroup(target, SAFETY_GROUP) == false then
        loop
            exitwhen i > .stack
            set t = LoadInteger(Dx, GetHandleId(target), i)
            set newDmg = t.onDamageTaken(source, target, newDmg)
            set i = i +1
        endloop
        set other = LoadInteger(Dx, GetHandleId(source),0)
        set i = 1
        loop
            exitwhen i > other.stack
            set t = LoadInteger(Dx, GetHandleId(source), i)
            set newDmg = t.onDamageDealt(source, target, newDmg)
            set i = i +1
        endloop
        call GroupAddUnit(SAFETY_GROUP, target)
        call UnitDamageTarget(source, target, newDmg - oldDmg , true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
        call GroupRemoveUnit(SAFETY_GROUP, target)
        endif
    endmethod
    
    method addInstance takes damageInstance h returns nothing
        call SaveInteger(Dx, GetHandleId(this.u), this.stack, h)
        set this.stack = this.stack + 1
    endmethod

endstruct

function SaveDamageInstance takes damageInstance d, unit u returns nothing
    local dd dmg = LoadInteger(Dx, GetHandleId(u),0)
    if dmg.u == null then
        set dmg = dd.create()
        set dmg.u = u
        set dmg.stack = 1
        call SaveInteger(Dx, GetHandleId(u),0,dmg)
    endif
    call dmg.addInstance(d)
endfunction

function CreateInstance takes unit u returns nothing
    local dd data = dd.create()
    set data.u = u
    set data.stack = 1
    call SaveInteger(Dx, GetHandleId(u),0,data)
endfunction

private function returnTrue takes nothing returns boolean
    return true
endfunction

private function runDD takes nothing returns boolean
    local dd data = LoadInteger(Dx, GetHandleId(GetTriggerUnit()),0)
    if data.u != null then
        call data.run(GetEventDamageSource(),GetTriggerUnit(),GetEventDamage())
    else
        call data.release()
    endif
    return false
endfunction

private function AddToEvent takes nothing returns boolean
    if IsUnitInGroup(GetTriggerUnit(), INSTANCE_GROUP) == false then
        call TriggerRegisterUnitEvent(EVENT_RESPONSE, GetTriggerUnit(), EVENT_UNIT_DAMAGED)
        call CreateInstance(GetTriggerUnit())
        call GroupAddUnit(INSTANCE_GROUP, GetTriggerUnit())
    endif
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local group g = CreateGroup()
    local rect r = GetPlayableMapRect()
    local region reg = CreateRegion()
    local unit u
    set Dx = InitHashtable()
    call RegionAddRect(reg, r)
    call GroupEnumUnitsInRect(g, r,function returnTrue)
    set u = FirstOfGroup(g)
    loop
        exitwhen u == null
        call TriggerRegisterUnitEvent(EVENT_RESPONSE, u, EVENT_UNIT_DAMAGED)
        call CreateInstance(u)
        call GroupAddUnit(INSTANCE_GROUP, u)
        call GroupRemoveUnit(g,u)
        set u = FirstOfGroup(g)
    endloop
    call TriggerRegisterEnterRegion(t, reg, function returnTrue)
    call TriggerAddCondition(EVENT_RESPONSE, function runDD)
    call TriggerAddCondition(t, function AddToEvent)
    call DestroyGroup(g)
    call RemoveRect(r)
    set g = null
    set r = null
endfunction
endlibrary
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
if you're adding the damaged/source unit to the same trigger (EVENT_RESPONSE), then
the total damage to all units within that trigger will be executed...
that's why in DD, there is a trigger index to every unit that has entered and in the map...

Could you elaborate?

DamageEvent & DamageModifiers

How is your library superior to that one? Why would I want to use this?

It's not. I posted this script for suggestions/comments. If nothing, i want to use it rather than damage event, it doesn't need to be accepted, i never asked for that.

If you could lend suggestions/ideas you are welcome to do so.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Then i would suggest this thread be moved to a different forum. More specifically, one that is not a forum for resources to be approved and accepted into the database.

So what is it? Do you want this to be approved, in which case i still want to know how this library improves on the ones before it, or do you not, in which case this thread would be in the wrong place?
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
Could you elaborate?
Forget it, coz you're not adding the same unit(the damaged unit) to the EVENT_RESPONSE twice...I remember that I created one
long time ago in GUI and its pretty bad coz Im adding the same unit to the trigger on each attack that's why damage dealt is doubled...

anyway, here's what I think;

JASS:
library InstanceDD initializer Init

globals
    private             trigger     EVENT_RESPONSE = CreateTrigger()
    private             trigger     RECYCLE_TRIG = CreateTrigger()
    
    private             hashtable   Dx = InitHashtable()
    
                        group       INSTANCE_GROUP = CreateGroup()
    private             group       ENUM_GROUP = CreateGroup()
    private             group       SAFETY_GROUP = CreateGroup()
endglobals

struct damageInstance

    stub method onDamageTaken takes unit source, unit target, real damage returns real        
        return damage
    endmethod
    
    stub method onDamageDealt takes unit source, unit target, real damage returns real
        return damage
    endmethod

endstruct

private struct dd
    
    unit u
    integer stack
    
    method release takes nothing returns nothing
        local integer i = 1
        local damageInstance t
        loop
            exitwhen i > .stack
            set t = LoadInteger(Dx, GetHandleId(.u), i)
            call t.destroy()
            set i = i +1
        endloop
        set .u = null
        call .destroy()
    endmethod
    
    method run takes unit source, unit target, real damage returns nothing
        local integer i = 1
        local integer max
        local real oldDmg = damage
        local real newDmg = damage
        local damageInstance t
        local dd other
        //if IsUnitInGroup(target, SAFETY_GROUP) == false then
        loop
            exitwhen i > .stack
            set t = LoadInteger(Dx, GetHandleId(target), i)
            set newDmg = t.onDamageTaken(source, target, newDmg)
            set i = i +1
        endloop
        set other = LoadInteger(Dx, GetHandleId(source),0)
        set i = 1
        loop
            exitwhen i > other.stack
            set t = LoadInteger(Dx, GetHandleId(source), i)
            set newDmg = t.onDamageDealt(source, target, newDmg)
            set i = i +1
        endloop
        //call GroupAddUnit(SAFETY_GROUP, target)
        //call UnitDamageTarget(source, target, newDmg-oldDmg , true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
        //call GroupRemoveUnit(SAFETY_GROUP, target)
        //endif
    endmethod
    
    method addInstance takes damageInstance h returns nothing
        call SaveInteger(Dx, GetHandleId(this.u), this.stack, h)
        set this.stack = this.stack + 1
    endmethod

endstruct

function SaveDamageInstance takes damageInstance d, unit u returns nothing
    local dd dmg = LoadInteger(Dx, GetHandleId(u),0)
    if dmg.u == null then
        set dmg = dd.create()
        set dmg.u = u
        set dmg.stack = 1
        call SaveInteger(Dx, GetHandleId(u),0,dmg)
    endif
    call dmg.addInstance(d)
endfunction

function CreateInstance takes unit u returns nothing
    local dd data = dd.create()
    set data.u = u
    set data.stack = 1
    call SaveInteger(Dx, GetHandleId(u),0,data)
endfunction

//private function returnTrue takes nothing returns boolean
  //  return true
//endfunction

private function runDD takes nothing returns boolean
    local dd data = LoadInteger(Dx, GetHandleId(GetTriggerUnit()),0)
    if data.u != null then
        call data.run(GetEventDamageSource(),GetTriggerUnit(),GetEventDamage())
    else
        call data.release()
    endif
    return false
endfunction

private function AddToEvent takes nothing returns boolean
    local unit u = GetTriggerUnit()
    if not IsUnitInGroup(u, INSTANCE_GROUP)then
        call TriggerRegisterUnitEvent(EVENT_RESPONSE, u, EVENT_UNIT_DAMAGED)
        call CreateInstance(u)
        call GroupAddUnit(INSTANCE_GROUP, u)
    endif
    set u = null
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    //local group g = CreateGroup()
    //local rect r = GetPlayableMapRect()
    local region reg = CreateRegion()
    local unit u
    call RegionAddRect(reg, bj_mapInitialPlayableArea)
    call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea,null)
    loop
        set u = FirstOfGroup(bj_lastCreatedGroup)
        exitwhen u == null
        call TriggerRegisterUnitEvent(EVENT_RESPONSE, u, EVENT_UNIT_DAMAGED)
        call CreateInstance(u)
        call GroupAddUnit(INSTANCE_GROUP, u)
        call GroupRemoveUnit(bj_lastCreatedGroup,u)
        //set u = FirstOfGroup(g)
    endloop
    call TriggerRegisterEnterRegion(t, reg, null)//nulfunction returnTrue)
    call TriggerAddCondition(EVENT_RESPONSE, function runDD)
    call TriggerAddCondition(t, function AddToEvent)
    //call DestroyGroup(g)
    //call RemoveRect(r)
    //set g = null
endfunction
endlibrary
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
So what is it? Do you want this to be approved, in which case i still want to know how this library improves on the ones before it, or do you not, in which case this thread would be in the wrong place?

Atm i just want opinions / ideas and this seemed like an appropriate forum since a lot of experienced people tend to post here.

I don't see why this couldn't sit a bit more in here where i can get some hopefully constructive criticism and advices from you guys... then if the end product isn't that great just graveyard it, it was originally made for personal use anyway.

If it's still an issue, i will ask someone to move the thread.

Peace out.
 
Top