• 🏆 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!

Why Shouldn't Respawn Work

Status
Not open for further replies.
Level 17
Joined
Nov 13, 2006
Messages
1,814
So each unit in the group respawns individually from each of the other units in the group?

easiest way if in object editor u set the respawen duration foe each unit, then dont need unit group and u can habdle with a simple timer or wait,

wait (dieing unit point value)

a bit plus work in object editer buit less work for triggers in game
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Okay well sounds simple enough. I'll have something for you soon.

By the way. I'm going to use AutoIndex for now because it doesn't look like you're on. If I need to change a few things that shouldn't be a problem.

Yeah, thats because i was probably sleeping at 4 am.

I am totally unfamiliar with AutoIndex, but as long as it doesn't lag with big maps or interfere with unit indexers, im fine i guess

easiest way if in object editor u set the respawen duration foe each unit, then dont need unit group and u can habdle with a simple timer or wait,

wait (dieing unit point value)

a bit plus work in object editer buit less work for triggers in game

. . . what?

e/ looked up AutoIndex and i only found one link but it calls SetUnitUserData once so im afraid that it would interfere
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I can change it after to use the same unit indexer that you use.

I'm still finishing up some work for some classes (been working all day in Java) and I've still got to finish up part of an assembly language script. I did get a little bit of work done on this yesterday though shortly before I went to bed.
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
1st of all Illidans911 u must understandm array dont make any problem, when your array reach the 8000+ size, then that problem but mainly because something dont work well.

example bribe unit indexer recycle the custom values, its mean in normal case never reach the limit because when a unit die, his bone are decayed then his custom value will be transfered to a new unit, so belive me when u reach even 5000+ moving unit on ur map ur map will be already nightmare but not because your array size is high, just because too many order etc i can give a example, also can give example when with 100+ array still not laggy anything.

why i told this?
because if u want make it faster your code array solution faster than hashtable, also far easier to use, i doubt in same time on your map u plan more than 8k unit...

have alot way to do your respawn and i think better use variables instead do 3-4 function call each time for load variables but you choose.

i made few example to you:

http://www.hiveworkshop.com/forums/...eutral-hostile-variations-212816/#post2111053
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
what.

im sorry, but your engilish is quite bad i cant understand a word of that, and the tutorial is basically what i did

@Berb im just using Bribe's indexer
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay. I apologize the last few days have been pretty busy for me. Anyway I'll download Bribe's indexer (I thought it was Nestharus that had one) and try to get that to work. I'll also try to use other resources found on this site for things like Lists and what-not.

I have a question though. How exactly are you determining which units should respawn and where? Are you going to place them in the editor or are you trying to do it during the game at some point?
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Bribe has a unit indexer and so does Nesth, but i dont have a JASS resource that uses Nesth's and i have a few that use the GUI one so i just stick with bribe's
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I've got a significant portion of it done. I'll probably finish it up tomorrow.

JASS:
library respawn initializer init requires respawnunit, respawntype
globals
    //config: (some setup constants)
    public constant real DEFAULT_FACING     = 0.00
    public constant player RESPAWN_PLAYER   = Player(12) //neutral hostile?
    
    //some other stuff:
    private Table reftable 
    
endglobals


//**********************************************************************************************
//* respawn
//*
//*
struct respawn
    respawnunit runit //this is automatically deallocated
    respawntype rtype
    real x
    real y
    
    real cooldown   = 0.00
    boolean pending = false
    
    static method create takes real x, real y, respawntype rtype returns thistype
      local thistype r = allocate()
        set r.rtype = rtype
        set r.x = x
        set r.y = y     //when a respawn is created there is no associated unit unless
        return (r)      //one is provided or "spawn" is called.
    endmethod
    
    method toString takes nothing returns string
        return GetUnitName(runit.me) + ", an ID of " + /*
            */ I2S(rtype.id) + " and category " + rtype.rcat.toString()
    endmethod
    
    //spawn: respawns a unit-type at special coordinates if the type is active.
    method spawn takes player for returns nothing
      local unit u 
        if (rtype.active) then
            set u = CreateUnit(for, rtype.id, x, y, DEFAULT_FACING)
            call reftable.remove(runit)
            set runit = respawnunit[u] //get the object for the unit
            set reftable[runit] = this
            set u = null
        endif
    endmethod
    
    //setunit: sets the spawn-unit in-case it already exists.
    method setunit takes unit u returns nothing
      local respawnunit conv = respawnunit[u]
        if (conv != 0) then
            call reftable.remove(runit)
            set runit = conv
            set reftable[conv] = this
        endif
    endmethod
    
    //lookup: tries to look the specified respawn-unit up in the reftable.
    //  --returns a pointer to the respawn that this unit belongs to.
    static method lookup takes respawnunit ru returns thistype
        if (reftable.has(ru)) then
            return (reftable[ru])
        endif
        return (0)
    endmethod

endstruct

//**********************************************************************************************
//* initialization
//*
//*
public function init takes nothing returns nothing
    set reftable = Table.create()
endfunction
endlibrary
JASS:
library respawngroup requires respawn, respawntimer, List


//**********************************************************************************
//* respawngroup code:
//*
//*
struct respawngroup

    //==============================================================
    // Members:
    // ----
    list members //the list of respawns in group
    static Table reftable //unique referencing

    static constant real PROXIMITY      = 200.00
    static constant real PROXIMITY_SQ   = 40000.00 //200^2
    
    respawntimer array rtimer [respawncategory.CATEGORIES]
    
    //==============================================================
    // Constructor/Destructor:
    // ----
    static method create takes nothing returns thistype
      local thistype rg = allocate()
      local integer i = 0
        loop
            exitwhen (i == respawncategory.CATEGORIES)
            set rg.rtimer[i] = respawntimer.create(rg, respawncategory[i])
            set i = i + 1
        endloop //create the timers pointing to this group
        set rg.members = list.create()
        return (rg)
    endmethod
    method onDestroy takes nothing returns nothing
        call members.destroy()
    endmethod
    
    //toString: returns string representation of object.
    method toString takes nothing returns string
      local respawn elem
      local string result = ""
      local integer it = 0
        call members.iteratef()
        loop
            set elem = members.iterate()
            set it = it + 1
            exitwhen (elem == -1)
            set result = result + "[" + I2S(elem) + "]" + elem.toString() + "\n"
        endloop
        return (result)
    endmethod
    
    
    //add: adds a respawn to the group at the front of list.
    method add takes respawn r returns nothing
        call members.insertf(r)
        set reftable[r] = this
    endmethod
    
    
    //==============================================================
    // Utility:
    // ----
    method check takes respawn r returns boolean
      local respawn elem
        call members.iteratef()
        loop
            set elem = members.iterate()
            exitwhen (elem == -1)
            if (((elem.x-r.x)*(elem.x-r.y)+(elem.y-r.y)*(elem.y-r.y)) < PROXIMITY_SQ) then
                return (true)
            endif
        endloop
        return (false)
    endmethod
    method findCategory takes respawn r returns list    
      local respawn elem
      local list ret = list.create()
        call members.iteratef()
        loop
            set elem = members.iterate()
            exitwhen (elem == -1)
            if (elem.rtype.rcat == r.rtype.rcat) then
                call ret.insertf(elem) //insert element to return list
            endif
        endloop
        return (ret) //return the generated list
    endmethod
    static method findGroup takes respawn r returns thistype
        if (reftable.has(r)) then
            return (reftable[r])
        endif
        return (0) //cannot be found
    endmethod
    static method operator [] takes respawn r returns thistype
        return (reftable[r])
    endmethod //this is faster and inline friendly for final draft
    
    
    //==============================================================
    // Initialization:
    // ----
    static method onInit takes nothing returns nothing
        set reftable = Table.create()
    endmethod
    
endstruct
endlibrary
JASS:
library respawntimer
struct respawntimer 
    respawncategory rcat
    respawngroup rgroup
    timer tmr
    boolean active
    
    static method create takes respawngroup grp, respawncategory category returns thistype
      local thistype rt = allocate()
        set rt.rcat = category
        set rt.rgroup = grp
        set rt.tmr = NewTimer()
        call SetTimerData(rt.tmr, rt)
        set rt.active = false
        return (rt)
    endmethod
endstruct
endlibrary
JASS:
library respawnunit
//indexed object reference to a unit with some data members for
//respawning specific types of units.
struct respawnunit

    implement AutoCreate
    implement AutoDestroy
    
    //only create for units that match one of the types as a "respawn"
    static method createFilter takes unit u returns boolean
        return (respawntype.find(GetUnitTypeId(u)) != 0)
    endmethod
endstruct

endlibrary
JASS:
library respawntype requires respawncategory
struct respawntype extends array
    //respawntype data:
    respawncategory rcat
    integer id
    boolean active
    
    static integer objc = 0
    static Table reftable
    
    //find: finds a "respawntype" associated with a specified ID.
    static method find takes integer id returns thistype
        if (reftable.has(id)) then
            return (reftable[id])
        endif
        return (0) //not found
    endmethod
    
    //new: adds a new type to the stack array with specified values.
    static method new takes integer id, respawncategory rcat returns nothing
        set thistype[objc].active = true
        set thistype[objc].id = id
        set thistype[objc].rcat = rcat
        set reftable[id] = objc
        set objc = objc + 1
    endmethod
    
    //initialize our types: (only debug ones for now)
    static method onInit takes nothing returns nothing
        set reftable = Table.create()
        //initialize some types:
        call new('hfoo', respawncategory.SEC15)
        call new('hpea', respawncategory.SEC10)
        call new('nftr', respawncategory.SEC10)
    endmethod
endstruct
endlibrary
JASS:
library respawncategory
struct respawncategory extends array
    static constant integer SEC10       = 0
    static constant integer SEC15       = 1
    static constant integer SEC30       = 2
    static constant integer SEC45       = 3
    static constant integer CATEGORIES  = 4
    
    real timeout
    
    //represent a CATEGORY as a string based on the timeout.
    method toString takes nothing returns string
        return "CATEGORY[" + I2S(R2I(timeout)) + "]"
    endmethod
    
    //initialize our respawn categories:
    static method onInit takes nothing returns nothing
        set thistype[SEC10].timeout = 10.0
        set thistype[SEC15].timeout = 15.0
        set thistype[SEC30].timeout = 30.0
        set thistype[SEC45].timeout = 45.0
    endmethod
endstruct
endlibrary
JASS:
library respawnsys initializer init requires respawn
globals
    //system dependent variables:
    private respawngroup array sysGroup
    private integer sysGroupCount = 0
    
endglobals

//**********************************************************************************************
//* utility
//*
//*
//newGroup: 
//  --creates a new group and adds the specified respawn to it
private function newGroup takes nothing returns respawngroup
    set sysGroup[sysGroupCount] = respawngroup.create()
    set sysGroupCount = sysGroupCount + 1
    return (sysGroup[sysGroupCount - 1])
endfunction

// checkGroups:
//  --checks to see if a respawn 'r' is within the boundaries of
//  a previously created group. if so we can add to that group.
//  --returns the array index in "sysGroup" of the group.
private function checkGroups takes respawn r returns integer
  local integer i = 0
    loop
        exitwhen (i == sysGroupCount)
        if (sysGroup[i].check(r)) then
            return (i)
        endif //return the index of group
        set i = i + 1
    endloop
    return (-1) //no nearby groups
endfunction



//**********************************************************************************************
//* main
//*
//*
private function onRespawn takes nothing returns nothing
  local respawntimer exp = respawntimer(GetTimerData(GetExpiredTimer()))
  local respawngroup grp
  local respawncategory cat
  local respawn elem
    if (exp == 0) then
        debug call BJDebugMsg("Non-respawn-unit has died. No action.")
        return
    endif //return if the dying unit is not a respawn
    set grp = exp.rgroup
    set cat = exp.rcat
  
    call grp.members.iteratef()
    loop
        set elem = grp.members.iterate()
        exitwhen (elem == -1)
        //iterate group and spawn units if pending and same category.
        if ((elem.pending) and (elem.rtype.rcat == cat)) then
            call elem.spawn(respawn_RESPAWN_PLAYER)
        endif
    endloop
endfunction
private function onDeath takes nothing returns boolean
  local respawnunit u = respawnunit[GetTriggerUnit()]
  local respawn r
  local respawngroup grp 
  local respawntimer rtmr
  local respawn elem

    if (u != 0) then //only check respawn-able units
        set r = respawn.lookup(u)
        set grp = respawngroup.findGroup(r)
    
        //the timer we are operating with:
        set rtmr = grp.rtimer[r.rtype.rcat]
        
        //start the timer (ignore previous arrangements for respawns)
        call TimerStart(rtmr.tmr, r.rtype.rcat.timeout, false, function onRespawn)
        set r.pending = true
    endif
    return (false)
endfunction


//**********************************************************************************************
//* initialization
//*
//*
public function init takes nothing returns nothing
  local group all = CreateGroup()
  local unit first
  local trigger t = CreateTrigger()
  local respawn r
  local respawntype rtyp
  local respawngroup rgrp
  local integer i = 0
  
    call GroupEnumUnitsOfPlayer(all, respawn_RESPAWN_PLAYER, null)
    loop
        set first = FirstOfGroup(all)
        exitwhen (first == null)
        
        set rtyp = respawntype.find(GetUnitTypeId(first))
        if (rtyp != 0) then
            set r = respawn.create(GetUnitX(first), GetUnitY(first), rtyp) 
            call r.setunit(first)
            set rgrp = sysGroup[checkGroups(r)] //check for any eligable groups.
            if (rgrp == 0) then
                set rgrp = newGroup()
            endif //get new group off stack array
            call rgrp.add(r) 
        endif //add respawn to group found/created
        call GroupRemoveUnit(all, first)
    endloop
    call DestroyGroup(all)
    set all = null
    set first = null
    
    //register trigger/actions:
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(t, Filter(function onDeath))
    
endfunction


endlibrary

I still have to transfer everything over to use Bribe's indexer.

Right now, as you can see from the system code, it just enumerates all neutral hostiles and stores their location/ID when Warcraft is loaded. While its doing that it partitions them into groups and such. Anyway, more later.

--Okay, pretty much done. Worked out a few bugs but everything seems to be going smoothly now.
--Uploaded a test-map. For now, the test-map labels your groups with text-tags so you know which units are a part of which group (this was mainly for previous debugging).

If you want to add a respawn unit-type then go to the "respawntype" code and at the bottom there is an initialization where 'hpea', 'hfoo' and 'nftr' are already added (to give you an idea of how to add types).

If you want to add a category, just go to the "respawncategory" code and make a new constant for it. You'll also have to give it a timeout.
 

Attachments

  • respawn.w3x
    68.9 KB · Views: 31
Last edited:
Level 19
Joined
Aug 8, 2007
Messages
2,765
private constant boolean UseUnitUserData = true <--- should be set to false, because it looks like you haven't yet transfered to bribe's

anyway, I'll play with it for a bit and return my thoughts/thanks/etc once i test it out a bit

e/ ohai
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Please. My JassHelper doesnt like autoindex for some reason

"Unhandled Code Exception
//! external ObjectMerger w3a Adef lvdt anam "Leave Detect" aart "" arac 0

Warcraft mpqs could not be opened"

Also get this error from your main respawn trig

"Syntax Error, unexpected: "for"?"

(i get both these errors in both my map and the attached demo)
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
set u = CreateUnit(for, rtype.id, x, y, respawn_DEFAULT_FACING)


under method spawn in "Respawn"
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Code said:
JASS:
    method spawn takes player for returns nothing
      local unit u 
        if (rtype.active) then
            set u = CreateUnit(for, rtype.id, x, y, DEFAULT_FACING)
            call reftable.remove(runit)
            set runit = respawnunit[u] //get the object for the unit
            set reftable[runit] = this
            set u = null
            set pending = false
        endif
    endmethod

It takes a parameter for. You can see it clearly.

I'm thinking you don't have an up-to-date JNGP. Go to your editor and at the top it'll say JassHelper. Click "About JassHelper" and it will show you the version number. This is the version number that I am using: 0.A.2.B
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Version : 2012-02-10

anyway, yes i saw that. I think its yelling because "for" is an operator (idk the correct word, its one of those words like loop) changing it to for2 worked but i get a different error lol

Undeclared variable "puts"

set puts=puts + GetUnitName((s__respawnunit_AutoData___meunit[(s__respawn_runit[elem])])) + ", " // INLINED!!

<< annoyance

e/ removing debug on that local fixed it. i sitll get that "on external call" error tho
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Version : 2012-02-10

Oh. There's a newer one than the one I'm using. Let me download it, and get it to work. He says it should be backwards compatible but clearly it isn't.

for wasn't a keyword up until this update. Let me get you a working version for this update.

--man, what a step in the wrong direction for JassHelper. It breaks way too much.

Right now, with debug mode on it works properly. Without debug mode, AutoIndex fails. Strange that wc3c.net is breaking compatibility with their own resources.

Okay. Updated.
 

Attachments

  • respawn.w3x
    65.8 KB · Views: 44
Level 18
Joined
Jan 21, 2006
Messages
2,552
It should be ready now. I set UseUnitUserData to false now which fixed most of the problems.

i sitll get that "on external call" error tho

That's not an error. It's a warning. I don't even know why a warning is shown for this because it worked perfectly with the "older" JassHelper.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
nah theres a difference between the warning and the error, and thats the error. ill look at the map in a sec
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Okay, after getting some more opportunities to test it, it works with the text tags over unit groups but when they die nada
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
What do you mean, "when they die nada"?

I've got it open in my editor now and they seem to be respawning, and I am currently using the same version of JassHelper as you are.

Okay just played around with the system for a little bit. Seems like when I comment out the external call in AutoIndex nothing works. I'm guessing that without this the entire library goes to shit. I follow the instructions that are given, including closing and reopening the map and disabling the external call but all of this results in the map not working correctly. If the external call is allowed, then there is a warning given but everything seems to function properly.
 
Last edited:
Level 19
Joined
Aug 8, 2007
Messages
2,765
That might be the problem. I'm just allowing the error to go (completely ignoring it) and i get the problem

when i say "nada" i mean nothing happens, they dont respawn
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Right I get that effect when I disable the external call. Under all circumstances when the external call is disabled it seems to not work. Honestly I don't even think I need a unit indexer, so I'm going to try to take it out completely and see what happens.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Well I use an indexer so you can still use custom values.

But, if your going for an indexer, stop trying to make AutoIndex work because its probably too much work, more than switching to Bribe's

also, spilled a litre of water on my keyboard and it still works. chuck norris powa
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
But, if your going for an indexer, stop trying to make AutoIndex work because its probably too much work, more than switching to Bribe's

The problem with Bribe's is that it has extremely limited functionality, and it is for a GUI interface not a JASS interface. These two things make it extremely unappealing to use in a JASS script.

Not to mention this already works on my computer. I honestly don't know what is going wrong on yours and clearly there is an inconsistency somewhere but before I even submitted it to you I had it working, so it's not an issue of what libraries work and don't work. It's an issues of what libraries you are able to get to work. Everything on my end is fine.

also, spilled a litre of water on my keyboard and it still works. chuck norris powa

You would either have to have a bucket or an enormous glass to dispense a litre of water so quickly that you spill the entire thing on your keyboard.

On a different note, I spilled MILK all over my MacBook Pro 2006 keyboard. Suffice to say it's pretty much a paraplegic now.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay. Removed AutoIndex. Here's the new version. Tell me if you have any problems but from testing it seems to work without giving that external call message.

The only thing hindered (other than instead of using custom datas, it uses a table) is the destruction of respawnunit types. These are only created by the system though, when a unit is spawned (or an initial unit is set), so recycling the IDs is just done right before a new instance is created. This means there should only ever be a static amount of these objects on a map.

I still have to add unit-type disabling. That isn't really a big problem though. Couple of lines of code.
 

Attachments

  • respawn.w3x
    40.9 KB · Views: 43
Level 19
Joined
Aug 8, 2007
Messages
2,765
I'll look at it when i get a chance. Mainly becase (yew key is broken)... i.. spoke too soon. "fneral msic"
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
(boosting topic for berb)

Coolio, it works for all that i can tell. I haven't had much time to test the group functionality, but single unit respawning works. Ty alot!

Probably, with some touchups, you should send it to the spells section :)
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
After three days of drying, my keyboard works fine lol. My V key on my secondary keyset is still sticky, though


Consider it yours exclusive.

(and anyone else who wants to download it from this thread)

Anyway, thank you so much for spending your time for coding this! You're going on my list of super-helpers, next to nestherus (cant spell his name) and magtheridon. :)

+rep+cred+whatev

e/ doesnt even allow me to rep u ;)
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
woops, found a problem. (not sure if its a me problem or system because i havent tested the demo map)
After a unit respawns and u kill it again, it dosen't respawn again
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Ok, i think its a problem with adding incorrect unit ids. It turns out that the units just weren't respawning, they werent respwaning once and than not anymore. I deleted all unit types except one and thhey respawned fine.

So, basically, adding an invalid id will crash the entire system? o_O
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Ok, i think its a problem with adding incorrect unit ids. It turns out that the units just weren't respawning, they werent respwaning once and than not anymore. I deleted all unit types except one and thhey respawned fine.

So, basically, adding an invalid id will crash the entire system? o_O

Well the type is just stored as an integer, so it won't crash the system. The problem will probably be caused when a unit is trying to be created with an ID that doesn't exist, but that is entirely dependent on the behavior of CreateUnit when it is passed invalid parameters.

I hope you're not expecting that you can enter 'hfo0' and expect the system to know you want 'hfoo' that would be very silly.

--Just tested by invalidating the 'hfoo' raw-code with 'hfo0' and it worked as expected, not respawning any of the Footman but it still respawned the other types of units who's IDs were given valid.
 
Status
Not open for further replies.
Top