HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Remaking Zombie Wall in GUI

07-16-2008, 03:26 AM#1
Kyrbi0
After seeing the awexomeness that was the Diablo 3 trailer, I felt impassioned into remaking the Witch Doctor's "Zombie Wall" ability for Wc3; it would fit perfectly on one of my custom Troll heroes.

However, I am (still) only using GUI. I was just going to go with a modified Serpent Ward that places ~20 of these attacking, non-moving zombies, effectively blocking an area. Yet, that's not a literal "wall".

So basically, does anyone know if it's possible to make a wall of units (like, perpendicular to the target point from the casting hero) in GUI? (Or really simple JASS, although I'd prefer to keep my maps clean.)
07-16-2008, 08:02 AM#2
Alexander244
As it is fairly much just maths, I would strongly suggest using JASS (GUI maths is painful)

The maths is something like this:

Click image for larger version

Name:	Untitled.jpg
Views:	54
Size:	13.1 KB
ID:	35752

Dist = length of zombie line

The centre of the line:
LineCentreX = target X
LineCentreY = target Y

The length of the line in x/y components:
X1 = Cos(theta + PI/2)*Dist
Y1 = Sin(theta + PI/2)*Dist

One set of line end co-ordinates:
End1X = LineCentreX + (X1/2)
End1Y = LineCentreY + (Y1/2)

The zombie creation interval:
Xinterval = X1 / (number of zombies - 1)
Yinterval = Y1 / (number of zombies - 1)

Starting at the end of the line; loop subtracting the interval each time, and create a zombie at said co-ordinate.

Edit: Here's an example, as you're new to JASS. It can be improved, but hopefully it gives you the general idea.
Collapse JASS:
scope ZombieWall initializer Init

    globals
        private constant integer ABILITY_ID = 'AOsh'
        private constant integer UNIT_TYPE_ID = 'hpea'
    endglobals
    
    private constant function WallLength takes integer lvl returns real
        return 600.+lvl*100.
    endfunction
    
    private constant function NumberOfZombies takes integer lvl returns integer
        return 5+lvl
    endfunction
    
    //===========================================================================
    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID
    endfunction

    private function Actions takes nothing returns nothing
        local location l = GetSpellTargetLoc()
        local unit u = GetSpellAbilityUnit()
        local player p = GetOwningPlayer(u)
        local integer i = 0
        local integer lvl = GetUnitAbilityLevel(u, ABILITY_ID)
        local integer n = NumberOfZombies(lvl)
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real tx = GetLocationX(l)
        local real ty = GetLocationY(l)
        local real angle = Atan2(ty-y, tx-x)
        local real d = WallLength(lvl)
        set x = Cos(angle+bj_PI/2)*d
        set y = Sin(angle+bj_PI/2)*d
        set tx = tx+x/2
        set ty = ty+y/2
        set x = x/(n-1)
        set y = y/(n-1)
        
        loop
            exitwhen i >= n
            call CreateUnit(p, UNIT_TYPE_ID, tx, ty, angle*bj_RADTODEG)
            set tx = tx-x
            set ty = ty-y
            set i = i + 1
        endloop
        
        call RemoveLocation(l)
        set l = null
        set u = null
    endfunction

    //===========================================================================
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i+1
            exitwhen i > 15
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        call TriggerAddAction(t, function Actions)
    endfunction

endscope
Attached Images
File type: jpgUntitled.jpg (13.1 KB)
07-16-2008, 09:35 AM#3
Anitarf
Quote:
Originally Posted by Kyrbi0
(Or really simple JASS, although I'd prefer to keep my maps clean.)
Then why are you using GUI, it's as unclean as you can get.

Alexander244, that looks good, except you don't get any zombies at the end points of the wall, I'm not sure if that's intended or not, but to get zombies there you'd need to use x/(n-1) instead of x/(n+1) and move the CreateUnit function two lines up.

By the way, there's nothing wrong with using TriggerRegisterAnyUnitEventBJ. There are a few BJs out there that are actually useful.
07-16-2008, 09:44 AM#4
Alexander244
Quote:
Alexander244, that looks good, except you don't get any zombies at the end points of the wall, I'm not sure if that's intended or not, but to get zombies there you'd need to use x/(n-1) instead of x/(n+1) and move the CreateUnit function two lines up.
I was using n+1 so it supports single walls. I suppose for practical use n-1 would be better though. *Goes to update*

Quote:
By the way, there's nothing wrong with using TriggerRegisterAnyUnitEventBJ. There are a few BJs out there that are actually useful.
I do it like that so I can take out any players I don't need to track. Don't know how much benefit that gives, but still.
07-16-2008, 10:33 AM#5
azwraith_ftL
I have a wall spell at TheHelper.net. It does the same you want, you may want to look at it ^^ It's JASS. Maybe you'll need only the creation of the units, the rest you can delete.

Link: http://www.thehelper.net/forums/showthread.php?t=85113
07-16-2008, 06:58 PM#6
Kyrbi0
So given the stream of JASS stuff coming from you guys, I take it that doing it in GUI would be immensely ungainly and/or impossible... Curses.

Quote:
Originally Posted by Anitarf
Then why are you using GUI, it's as unclean as you can get...
I was kidding; by "clean", I meant "clean of all JASS except custom script".

@azwraith_ftl: Thanks, but since it's not on this site, I can't access it as easily. I'll probably just go with Alex's provided example. Thank you, though.

@Alex: So... I copy/paste this into a completely-blank, Custom Text trigger, then run Test Map? Probably not. What do I need to change in the code; where are the parts that say "order code of ability being cast, code of unit being summoned, etc...?
07-16-2008, 07:01 PM#7
Anitarf
Quote:
Originally Posted by Kyrbi0
@Alex: So... I copy/paste this into a completely-blank, Custom Text trigger, then run Test Map? Probably not. What do I need to change in the code; where are the parts that say "order code of ability being cast, code of unit being summoned, etc...?
All those things are in the calibration section, that's the top part of the code, you'll see some constant globals and some calibration functions where you can define a couple of spell parameters. This particular code also needs the Jass NewGen pack, since it uses vJass syntax.
07-16-2008, 07:16 PM#8
Kyrbi0
Arg! Would it be difficult to make it not require the JNGP? This is exactly what I wanted to avoid with JASS.
07-16-2008, 07:16 PM#9
Fluff
Yes, you need NewGen, but note that you need to do the fix in the new patch announcement thread.

Collapse JASS:
    globals
        private constant integer ABILITY_ID = 'AOsh'
        private constant integer UNIT_TYPE_ID = 'hpea'
    endglobals

This looks to be the only part you need to change. Change the AOsh to the ability ID of the ability. (Ctrl + D in the Object Editor to show the IDs) Then go to the unit that you want to make (serpent ward or whatever) and replace hpea with that code, which you can see by toggling the ctrl+D.

New Gen is just like the normal World Editor but with enhanced Jass features. You can use it just like the normal editor, and you can do GUI in it just like you normally would.
07-16-2008, 07:24 PM#10
Kyrbi0
Argh (again).

So what do I change/remove to make it not require JNGP?
07-16-2008, 07:30 PM#11
Alevice
What's wrong with JGNP? It adds some other handy functionality to the WE that doesn't hurt development in anyway.
07-16-2008, 07:31 PM#12
Alexander244
I suggest you amend this section:
Collapse JASS:
call CreateUnit(p, UNIT_TYPE_ID, tx, ty, angle*bj_RADTODEG)
to include adding timed life to the unit:
Collapse JASS:
set u = CreateUnit(p, UNIT_TYPE_ID, tx, ty, angle*bj_RADTODEG)
call UnitApplyTimedLife(u, 'BTLF', Duration(lvl))
Then at the top add this:
Collapse JASS:
private constant function Duration takes integer lvl returns real
    return 30.
endfunction

Quote:
Arg! Would it be difficult to make it not require the JNGP? This is exactly what I wanted to avoid with JASS.
Unless you aren't on window you should be using newgen.

If you're adament not to use vJass:
Collapse JASS:
    constant function ABILITY_ID takes nothing returns integer
        return 'AOsh'
    endfunction
    
    constant function UNIT_TYPE_ID takes nothing returns integer
        return 'hpea'
    endfunction
    
    constant function WallLength takes integer lvl returns real
        return 600.+lvl*100.
    endfunction
    
    constant function NumberOfZombies takes integer lvl returns integer
        return 5+lvl
    endfunction
    
    constant function Duration takes integer lvl returns real
        return 30.
    endfunction
    
    //===========================================================================
    function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ABILITY_ID()
    endfunction

    function Actions takes nothing returns nothing
        local location l = GetSpellTargetLoc()
        local unit u = GetSpellAbilityUnit()
        local player p = GetOwningPlayer(u)
        local integer i = 0
        local integer lvl = GetUnitAbilityLevel(u, ABILITY_ID())
        local integer n = NumberOfZombies(lvl)
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real tx = GetLocationX(l)
        local real ty = GetLocationY(l)
        local real angle = Atan2(ty-y, tx-x)
        local real d = WallLength(lvl)
        set x = Cos(angle+bj_PI/2)*d
        set y = Sin(angle+bj_PI/2)*d
        set tx = tx+x/2
        set ty = ty+y/2
        set x = x/(n-1)
        set y = y/(n-1)
        
        loop
            exitwhen i >= n
            set u = CreateUnit(p, UNIT_TYPE_ID(), tx, ty, angle*bj_RADTODEG)
            call UnitApplyTimedLife(u, 'BTLF', Duration(lvl))
            set tx = tx-x
            set ty = ty-y
            set i = i + 1
        endloop
        
        call RemoveLocation(l)
        set l = null
        set u = null
    endfunction

    //===========================================================================
    function InitTrig_XXXXXX takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
            set i = i+1
            exitwhen i > 15
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        call TriggerAddAction(t, function Actions)
    endfunction

That should work. Where XXXXX is the name of the trigger block.
You'll want to prefix all the functions with something though.
07-16-2008, 07:37 PM#13
Kyrbi0
Wow, thanks; I didn't think you'd actually re-write it for me. Heh, now I'd feel amiss if I didn't use a Zombie Wall ability! :P

Quote:
Unless you aren't on window you should be using newgen.
Yeah, probably... But my downloading is restricted, so I'd have to find time for it, then since I don't use JASS anyway, I wouldn't be using it all the much anyway, and as stated above, it would mess with my current patch-level... I don't know, I just don't see it as necessary, or even worth it.

Oh, and what do you mean by "trigger block", or "name of the trigger block"? Like, the name of the trigger itself, as if it were GUI (i.e. InitTrig_Wall_of_Zombies)?
07-16-2008, 07:43 PM#14
Alexander244
Quote:
Yeah, probably... But my downloading is restricted, so I'd have to find time for it, then since I don't use JASS anyway, I wouldn't be using it all the much anyway, and as stated above, it would mess with my current patch-level... I don't know, I just don't see it as necessary, or even worth it.
Even for a GUI user newgen is useful. But as your circumstances are limiting I see why you wouldn't want to get it.

Quote:
Oh, and what do you mean by "trigger block", or "name of the trigger block"? Like, the name of the trigger itself, as if it were GUI (i.e. InitTrig_Wall_of_Zombies)?
Yes
07-16-2008, 07:46 PM#15
Kyrbi0
Wait, if it's JASS NewGen Pack, how it is useful for GUI?