• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Corpse Resource System

Status
Not open for further replies.
JASS:
function AddCorpseData takes integer Spn,integer RoS,integer max,integer Cid,real Rad returns nothing
    // Takes a unit type (Spn) and adds the given spawner data about it; Seconds to spawn a corpse (RoS), maximum corpses (max), the unit type of the corpse (Cid), and how far away the corpses are spawned (Rad).
    call SaveInteger(udg_CorpseTable,Spn,0,RoS)
    call SaveInteger(udg_CorpseTable,Spn,1,max)
    call SaveInteger(udg_CorpseTable,Spn,2,Cid)
    call SaveReal(udg_CorpseTable,Spn,3,Rad)
    call SaveReal(udg_CorpseTable,Spn,4,360.0/I2R(max))
endfunction

function AddCorpseCost takes integer Bld,integer num returns nothing
    // Takes a unit type (Bld) adds a corpse cost (num) to it.
    call SaveInteger(udg_CorpseTable,Bld,10,num)
endfunction

function AddCorpseSpawner takes unit Spn returns nothing
    // Takes a unit (Spn) and turns it into a corpse spawner, provided spawner data exists for its unit type.
    local integer hid=GetHandleId(Spn)
    local integer uid=GetUnitTypeId(Spn)
    if LoadInteger(udg_CorpseTable,uid,1)>0then
        call SaveGroupHandle(udg_CorpseTable,hid,0,CreateGroup())
        call SaveInteger(udg_CorpseTable,hid,1,0)
        call SaveInteger(udg_CorpseTable,hid,2,LoadInteger(udg_CorpseTable,uid,0))
        call GroupAddUnit(udg_Corpses,Spn)
    endif
endfunction

function NewCorpse takes unit Spn returns nothing
    // Takes a corpse spawner (Spn) and creates another corpse for it, provided it doesn't go over the maximum number of corpses. Resets the time to spawn a new corpse.
    local integer uid=GetUnitTypeId(Spn)
    local integer hid=GetHandleId(Spn)
    local player own=GetOwningPlayer(Spn)
    local unit cps=null // Possible corpse to be made.
    local integer num=LoadInteger(udg_CorpseTable,hid,1)
    local real ang=R2I(num)*LoadReal(udg_CorpseTable,uid,4)*bj_DEGTORAD
    local real rad=LoadReal(udg_CorpseTable,uid,3)
    if num<LoadInteger(udg_CorpseTable,uid,1)then
        // Make a new corpse!
        set cps=CreateCorpse(own,LoadInteger(udg_CorpseTable,uid,2),GetWidgetX(Spn)+rad*Cos(ang),GetWidgetY(Spn)+rad*Sin(ang),ang*bj_RADTODEG)
        call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",cps,"origin"))
        call GroupAddUnit(LoadGroupHandle(udg_CorpseTable,hid,0),cps)
        call SaveInteger(udg_CorpseTable,hid,1,num+1)
        call SaveInteger(udg_CorpseTable,hid,2,LoadInteger(udg_CorpseTable,uid,0))
        // Make corpse permanent.
        call SetUnitBlendTime(cps,0)
        call SetUnitAnimation(cps,"decay bone")
        call UnitSuspendDecay(cps,true)
        set cps=null
    endif
    set own=null
endfunction

function CorpseCount takes player P returns integer
    // Loops over all corpse spawners owned by the given player (P) and returns the number of corpses he or she owns.
    local unit Spn=null
    local integer Num=0
    local group G=CreateGroup()
    local player Own=null
    call GroupAddGroup(udg_Corpses,G)
    loop
        set Spn=FirstOfGroup(G)
        exitwhen Spn==null
        call GroupRemoveUnit(G,Spn)
        set Own=GetOwningPlayer(Spn)
        if Own==P then
            set Num=Num+LoadInteger(udg_CorpseTable,GetHandleId(Spn),1)
        endif
        set Own=null
        set Spn=null
    endloop
    call DestroyGroup(G)
    set G=null
    return Num
endfunction

function RemoveCorpseSpawner takes unit Spn returns nothing
    // Takes a corpse spawner (Spn) and removes all corpse spawner handling from it; clearing it's data entry and corpses.
    local integer hid=GetHandleId(Spn)
    local integer uid=GetUnitTypeId(Spn)
    local group G=LoadGroupHandle(udg_CorpseTable,hid,0)
    local unit cps=null
    loop
        set cps=FirstOfGroup(G)
        exitwhen cps==null
        call GroupRemoveUnit(G,cps)
        call SetUnitBlendTime(cps,.15)
        call UnitSuspendDecay(cps,false)
        set cps=null
    endloop
    call GroupRemoveUnit(udg_Corpses,Spn)
    call DestroyGroup(G)
    set G=null
    call SaveGroupHandle(udg_CorpseTable,hid,0,null)
    call FlushChildHashtable(udg_CorpseTable,hid)
endfunction

function SpendCorpse takes integer amt,player P returns boolean
    // Spends a number of corpses (amt) for player (P), and returns true if there was enough corpses, or false if not enough. Spent corpses (if returns true) are removed from their spawners.
    local group G=null
    local group Spn=null
    local unit spn=null
    local unit cps=null
    local player Own=null
    local integer hid
    if amt>CorpseCount(P)then
        return false
    elseif amt<1then
        return true
    endif
    set G=CreateGroup()
    call GroupAddGroup(udg_Corpses,G)
    loop
        set spn=FirstOfGroup(G)
        exitwhen spn==null
        call GroupRemoveUnit(G,spn)
        set Own=GetOwningPlayer(spn)
        if Own==P then
            set hid=GetHandleId(spn)
            set Spn=LoadGroupHandle(udg_CorpseTable,hid,0)
            loop
                set cps=FirstOfGroup(Spn)
                exitwhen cps==null or amt==0
                call GroupRemoveUnit(Spn,cps)
                call DestroyEffect(AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl",GetWidgetX(cps),GetWidgetY(cps)))
                call RemoveUnit(cps)
                call SaveInteger(udg_CorpseTable,hid,1,LoadInteger(udg_CorpseTable,hid,1)-1)
                set cps=null
                set amt=amt-1
            endloop
            set Spn=null
        endif
        set Own=null
        set spn=null
    endloop
    call DestroyGroup(G)
    set G=null
    return true
endfunction

function CorpseTick takes nothing returns nothing
    // Loops over all corpse spawners and checks to see if they to be removed (because they died), or checks if they are due to spawn a corpse.
    local group G=CreateGroup()
    local unit Spn=null
    local integer I
    local boolean Run=false
    call GroupAddGroup(udg_Corpses,G)
    loop
        set Spn=FirstOfGroup(G)
        exitwhen Spn==null
        set Run=true
        call GroupRemoveUnit(G,Spn)
        if GetWidgetLife(Spn)<.405then
            call RemoveCorpseSpawner(Spn)
        else
            set I=LoadInteger(udg_CorpseTable,GetHandleId(Spn),2)-1
            if I<=0 then
                call NewCorpse(Spn)
            else
                call SaveInteger(udg_CorpseTable,GetHandleId(Spn),2,I)
            endif
        endif
        set Spn=null
    endloop
    call DestroyGroup(G)
    set G=null
endfunction

function InitTrig_Corpses takes nothing returns nothing
    set gg_trg_Corpses=CreateTrigger()
    call TriggerRegisterTimerExpireEvent(gg_trg_Corpses,udg_CorpseTimer)
    call TriggerAddCondition(gg_trg_Corpses,Condition(function CorpseTick))
    call TimerStart(udg_CorpseTimer,1,true,null)
    set udg_CorpseTable=InitHashtable()
    call AddCorpseData('h000',1,3,'hpea',128)
    call AddCorpseData('h001',1,5,'hpea',128)
    call AddCorpseData('h002',1,7,'hpea',128)
    call AddCorpseCost('h001',2)
    call AddCorpseCost('h002',3)
endfunction

So the issue is, given this code, that my corpses don't decay properly when the spawner is destroyed, or the corpses of a spawner sometimes decay?

Any insight appreciated.
 
Status
Not open for further replies.
Top