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

Summoning Ability

Status
Not open for further replies.
Level 4
Joined
Dec 2, 2011
Messages
76
Hello everyone,
I want to make an ability that summons a builder unit and then disables itself or stops working due to the builder unit already being summoned.
I thought making a spell that would summon a builder classified as a hero and when the hero counter was full you couldn't summon another builder would work but I'm not sure.

I hope that this is in the right forum, I checked for a spell forum but couldn't find one.
Thanks to everyone for their help.
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Hello everyone,
I want to make an ability that summons a builder unit and then disables itself or stops working due to the builder unit already being summoned.
I thought making a spell that would summon a builder classified as a hero and when the hero counter was full you couldn't summon another builder would work but I'm not sure.

I hope that this is in the right forum, I checked for a spell forum but couldn't find one.
Thanks to everyone for their help.

so if i understand u want make a summonner spell and siable the spell if have too many builder?

replace animated dead to your ability and peasant to your builder

  • Disable ability
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Animate Dead
      • (Number of living Peasant units owned by (Triggering player)) Greater than or equal to 10
    • Actions
      • Player - Disable Animate Dead for (Triggering player)
  • Builder die
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Peasant
      • (Number of living Peasant units owned by (Triggering player)) Less than or equal to 10
    • Actions
      • Player - Enable Animate Dead for (Triggering player)
 
Level 5
Joined
Nov 7, 2007
Messages
134
so if i understand u want make a summonner spell and siable the spell if have too many builder?

replace animated dead to your ability and peasant to your builder

  • Disable ability
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Animate Dead
      • (Number of living Peasant units owned by (Triggering player)) Greater than or equal to 10
    • Actions
      • Player - Disable Animate Dead for (Triggering player)
  • Builder die
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Peasant
      • (Number of living Peasant units owned by (Triggering player)) Less than or equal to 10
    • Actions
      • Player - Enable Animate Dead for (Triggering player)

Excuse me, but Animate Dead? That would require corpses to work, wouldn't it? Why not just Summon Water Elemental as the base ability? Other than that, the solution seems solid enough.
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
I was going to use feral spirit as a base but water elemental sounds good.
Thank you you two.

have more way, but main thing is the trigger
personally i use trigger for create unit, also i add same effect than necromancer got for raise skeleton, and add summoned unit classification and customize the unit with trigger but for me its part of rpg not for building.

u can use channel ability and create unit with trigger and then u can use damn much summon ability because u can change the channel ability base order id (dont forget remove the art time, follow time, and change to point target, check out the visible then its perfect for this)

anyway following abilityes is similiar in that point, they all create new unit but have difference in timeing and effect and working but u can have fun with them: Serpent ward, Feral Spirit, Summon Water element, Inferno, Carrion Beetles, Spirit of Vengeance, Force of Nature, Summon Sea Elemental, Healing Ward, Spawn Hydra, Spawn Skeleton, Spawn Spiders (last 3 when unit die automatically spawn x unit type), Summon Misha, Summon Quilbeast etc

if u want replace unit but keep the stat just improve (like turret upgrade) then bear form, metamorph, avatar could work
 
Level 9
Joined
Nov 19, 2011
Messages
516
Feral spirit will be better. In this skill you don't need to check that unit is curently summoned or not. Just if your unit will be alive it will die instantly while summoning another one.

If I understood you well you want it be hero clasificated peasant? Just change unit clasification in object editor as peasant.
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Feral spirit will be better. In this skill you don't need to check that unit is curently summoned or not. Just if your unit will be alive it will die instantly while summoning another one.

If I understood you well you want it be hero clasificated peasant? Just change unit clasification in object editor as peasant.

oh now i got why he asked, maybe he tryed find this
  • (Number of living Peasant units owned by (Triggering player)) Greater than or equal to 10
but its integer condition - Unit -> Count living unit by Player (also count unit in group work aswell)

yea Feral spirit summon 2 unit with one cast and cant allow more than 2, but what if he want summon only 1 unit / cast and he want max 10 builder at same time not 1?
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
So do it this way:

var:
x:unit[10];
c:int; //pointer

While unit cast (summoning skill) do
{
c = (c+1) mod 10;
kill x[c];
x[c] = summoned unit;
}

This way unit summoned faster will be raplaced with last one with max count of 10.

Please stop using other programming languages as a reference for GUI or Jass.
Even though it does look alike, I think it's better to either post GUI or Jass. People might get confused...

I know what your trying to explain, but it might be hard for other people to read this.

Also: using summoned unit while unit casting the skill does not work, you have to use this when the unit starts the effect of the ability.
Else summoned unit will be null ;) All your doing right now is killing x and then setting it to null 10 times in a row ^.^




Another note: since your "trigger" is in a different programming language you can't correctly reference it to GUI or Jass for the following reason:

While unit cast (summoning skill) do
{
c = (c+1) mod 10;
kill x[c];
x[c] = summoned unit;
}

Let's assume that while the unit is casting the ability 20 units get summoned.
Now since this while loop continues until the skill being cast is done,
you can't be sure whether the variables that are being defined are setting the units in an ascending order because of the processing time.
Which means that it can skip some of the units being summoned since you don't know when the actions are being processed due to the length of the ability being cast.
they can be defined as random 10 units from the 20 units that are being summoned...

That's why I'd rather not use different programing languages to give an example of a trigger.
 
Last edited:
Level 17
Joined
Nov 13, 2006
Messages
1,814
So do it this way:

var:
x:unit[10];
c:int; //pointer

While unit cast (summoning skill) do
{
c = (c+1) mod 10;
kill x[c];
x[c] = summoned unit;
}

This way unit summoned faster will be raplaced with last one with max count of 10.

faster the create a unit, kill older one than dont even summon nothing after already 10 unit? i doubt :p

since u can disable the summoning ability if have already 10 unit and reenable if have less than 10 :p

if i understand well then he want just summon builder and not a pet what he want replace, se enough if just turn off when player got more than 10 unit and turn on if player lose a builder
 
Level 9
Joined
Nov 19, 2011
Messages
516
Sorry to useing other languages but I don't know vJass at all, and my GUI is polish so peaple usualy get confused more. So there should be that chage:

from:
x[c] = summoned unit
to:
unit - create (your unit) for player (owner of (casting unit)) at (position of castion unit + {there put some point to avoid unit stuck});
set x[c] = last created unit;

If he want to disable he can add if condition to check that next point unit (x[c]) is dead or null before starts trigger.
 
Last edited:
Level 14
Joined
Apr 20, 2009
Messages
1,543
Sorry to useing other languages but I don't know vJass at all, and my GUI is polish so peaple usualy get confused more. So there should be that chage:

from:
x[c] = summoned unit
to:
unit - create (your unit) for player (owner of (casting unit)) at (position of castion unit + {there put some point to avoid unit stuck});
set x[c] = last created unit;

If he want to disable he can add if condition to check that next point unit (x[c]) is dead or null before starts trigger.

If you already know a programming language then why not learn Jass? It's simple :)

b.t.w. this already looks a lot more like GUI ^.^

(I don't even have the world editor open and I'm at work, 0 spacebars = Trigger name, 3 space bars = event, conditions and actions and 6 space bars = everything inbetween)

  • Trigger Name
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
    • Actions
      • Unit - Create 1 (your unit) for Player(owner of (triggering unit)) at (position of triggering unit)
      • Set - x[c] = last created unit
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Sorry to useing other languages but I don't know vJass at all, and my GUI is polish so peaple usualy get confused more. So there should be that chage:

from:
x[c] = summoned unit
to:
unit - create (your unit) for player (owner of (casting unit)) at (position of castion unit + {there put some point to avoid unit stuck});
set x[c] = last created unit;

If he want to disable he can add if condition to check that next point unit (x[c]) is dead or null before starts trigger.

but why? coz i dont see ur point really. why u must store to array, even that why u store to unit array if u store to somewhere, since this way every player get only 1 summoned unit or just 1 player can summon...
if u want store to variable (what is absolute not needed) then better if u add to global unit group array and u can count how much unit have in unit group....

but anyway absolute dont needed since u can check how many unit got a player from x unit type with a single condition
 
Level 9
Joined
Nov 19, 2011
Messages
516
Cpu

Let me tell you diffrence between what you see and whats happening:

Checking units alive goes (for CPU) this way:

here,there: pointer;
list: {chain struct};

func (chossen_owner);
{
new (list);
here=list;
there=units;
while true do
{
if there->unit->owner == choosen_owner then
{
here->val = unit;
here=here->next;
}
there=there->next;
if there == null then breake
}

//Thats your 'pick evry unit' acction which will be called evry cast.
//After that CPU will check all units on list that is it alive.
//What gives around 50xPlayers + 50 acctions
//
//If you will add and remove it from stable list it will give
//5 acctions on cast (is unit[x] alive,create,kill,set unit[x], x++)
//and 1 acctions on unit death (unit[x] type);
//Thats couses less lags during game
//(650 CPU acctions per cast or 1 acction per death + 5 acctions per cast
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Let me tell you diffrence between what you see and whats happening:

Checking units alive goes (for CPU) this way:

here,there: pointer;
list: {chain struct};

func (chossen_owner);
{
new (list);
here=list;
there=units;
while true do
{
if there->unit->owner == choosen_owner then
{
here->val = unit;
here=here->next;
}
there=there->next;
if there == null then breake
}

//Thats your 'pick evry unit' acction which will be called evry cast.
//After that CPU will check all units on list that is it alive.
//What gives around 50xPlayers + 50 acctions
//
//If you will add and remove it from stable list it will give
//5 acctions on cast (is unit[x] alive,create,kill,set unit[x], x++)
//and 1 acctions on unit death (unit[x] type);
//Thats couses less lags during game
//(650 CPU acctions per cast or 1 acction per death + 5 acctions per cast

a groupenum somehow i bet a damn minimal cpu usage, what u dont notice...
also if use count in group than dont needed check if unit is alive if we talk about builders and not about heroes=> create a potentional action but only if condition is true else its ignore all action until in ur case its do action every time also if u count a trigger do more action than that few function in action part :p

see if i try resolve this in php or vbasic then its also fail since its is is JASS when u save the map and not everything work like in other language

from:
x[c] = summoned unit
to:
unit - create (your unit) for player (owner of (casting unit)) at (position of castion unit + {there put some point to avoid unit stuck});
set x[c] = last created unit;

example
the default create a unit
JASS:
 call CreateNUnitsAtLoc( 1, 'hfoo', Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING )

if u use this than its more faster
JASS:
 call CreateUnit (Player(0), 'hfoo', x, y)

when u remove a ability, add ability, create unit, order unit, in background must of time have alot useless function call :p

so overall that a unitgroup count per cast its really pitty difference compared how much action handle a map
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
I'm not sure becouse CPU still needs to check ALL units on map. When you hold your units in variable unit group its faster. But disable/enable idea can make it faster yet.

lets see


  • (Number of units in (Units owned by (Triggering player) of type Footman)) Less than 10
when map or u convert it the condition look like this =>

JASS:
function Trig_Untitled_Trigger_001_Conditions takes nothing returns boolean
    if ( not ( CountUnitsInGroup(GetUnitsOfPlayerAndTypeId(GetTriggerPlayer(), 'hfoo')) > 10 ) ) then
        return false
    endif
    return true
endfunction

optimize

JASS:
function Trig_Untitled_Trigger_001_Conditions takes nothing returns boolean
     return CountUnitsInGroup(GetUnitsOfPlayerAndTypeId(GetTriggerPlayer(), 'hfoo')) > 10
endfunction

the getunitsofplayerandtypeid function is

JASS:
function GetUnitsOfPlayerAndTypeId takes player whichPlayer, integer unitid returns group
    local group g = CreateGroup()
    set bj_groupEnumTypeId = unitid
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterGetUnitsOfPlayerAndTypeId)
    return g
endfunction
function GetUnitsOfPlayerAndTypeIdFilter takes nothing returns boolean
    return GetUnitTypeId(GetFilterUnit()) == bj_groupEnumTypeId
endfunction

GroupEnumUnitsOfPlayer is a native same like GroupEnumUnitsOfType, GroupEnumUnitsInRange, GroupEnumUnitsInRect, GroupEnumUnitsSelected

lets see CountUnitsInGroup

JASS:
function CountUnitsInGroup takes group g returns integer
    // If the user wants the group destroyed, remember that fact and clear
    // the flag, in case it is used again in the callback.
    local boolean wantDestroy = bj_wantDestroyGroup
    set bj_wantDestroyGroup = false

    set bj_groupCountUnits = 0
    call ForGroup(g, function CountUnitsInGroupEnum)

    // If the user wants the group destroyed, do so now.
    if (wantDestroy) then
        call DestroyGroup(g)
    endif
    return bj_groupCountUnits
endfunction

but if u optimize a group count and combine with group enum then everything it is just this

JASS:
function Trig_Untitled_Trigger_001_Conditions takes nothing returns boolean
local integer i = 0
local unit u
local group g = bj_lastCreatedGroup
call GroupEnumUnitsOfPlayer (g, Player(0), null)
  loop
     set u = FirstOfGroup(g)
     exitwhen u == null
     if GetUnitTypeId(u) == 'hpea' then
     set i = i + 1
     endif
     call GroupRemoveUnit(g, u)
  endloop
set g = null
set u = null
return i > 10
endfunction

conclusion if u want reduce the cpu usage then better if u check 1st the triggers, even its look simple, but in background can have alot useless function call


-Kobas-
About requiment, sadly not possible make in object editor a unit requiment where instead egual we can use '>' or '<' too, then everything could be easier :D
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
is NOT array of unit unit group?? :vw_wtf:

no exactly....


unit[1-1000], if u use this then u also must calculated each time since i guess not only player 1 can summon, so each player use same unit array?
in unit group also could be array, this make it easier, since u can make unit_group[1] for player 1, unit_group[2] for player 2 but in unit case u must use more index like:
unit[player number*max summonable unit number]-> unit[player number*max summonable unit number+max summonable unit number-1]

in example for player 1 if default each player can summon 50 unit then
unit[50]->unit[99]
for player 2
unit[100]->unit[149]
etc :p

until u must use dynamic indexing for unit array for check how much unit got a player, at unit group u can simple count unit in group (also u can do a loop methode for check if unit[x]=null else count=count+1 but then easier the unit group counting)

about unit count its not same, atleast the natives
  • Unit Group - Pick every unit in (Units in (Playable map area)) and do (Actions)
    • Loop - Actions
and

  • Unit Group - Pick every unit in (Units owned by (Triggering player)) and do (Actions)
    • Loop - Actions
unit enum

JASS:
native GroupEnumUnitsInRect                 takes group whichGroup, rect r, boolexpr filter returns nothing

JASS:
native GroupEnumUnitsOfPlayer               takes group whichGroup, player whichPlayer, boolexpr filter returns nothing

yea unit group variable is faster ofc but not requiment absolute :p
 
Level 17
Joined
Nov 13, 2006
Messages
1,814
Looks like you don't know what chains and pointers are.

By the way. He didn't say that more than 1 player can summon, did he?

Sorry but WE convert to Jass not to C, else we could make alot more thing :D


else show me how u import ur c to map?

anyway somehow i suggest where somebody build its possible better if its multiplayer map since wc3 got enough normal maps vs computer :p

i already made my summon system, just at my case a bit different since at rpg i customize the summoned unit by ability level and i use 1 trigger for 3 ability
JASS:
function Trig_Summons_for_necro_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A03Y' or GetSpellAbilityId() == 'A03U'  or GetSpellAbilityId() == 'A040'
endfunction

function Trig_Summons_for_necro_Actions takes nothing returns nothing
local player pl = GetTriggerPlayer()
local integer p = GetPlayerId(pl)+1
local unit u = GetTriggerUnit()
local unit pu = GetTriggerUnit()
local real xt = GetSpellTargetX()
local real yt = GetSpellTargetY()
local integer ulv = GetUnitAbilityLevel(u, 'A03V') 
local integer a = GetSpellAbilityId()
local integer lv = GetUnitAbilityLevel(u, a) 
local integer hlv = GetHeroLevel(u)
local string s1 = "Abilities\\Spells\\Undead\\RaiseSkeletonWarrior\\RaiseSkeleton.mdl"
local string s2 = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl"
local real size = 1+lv/15
local real mrate = 1
local real prate = 1
local integer cv 
local integer utype

if ulv != GetPlayerTechCount(pl, 'R001', true) then
    call SetPlayerTechResearched(pl,'R001', ulv )
endif

call DestroyEffect (AddSpecialEffect (s1, xt,yt))
if a == 'A03Y' then
     if CountUnitsInGroup(udg_Summon_I)==5 then
      set pu = FirstOfGroup(udg_Summon_I)
      call GroupRemoveUnit(udg_Summon_I, pu)
      call DestroyEffect (AddSpecialEffect (s2, GetUnitX(pu),GetUnitY(pu)))      
      call KillUnit( pu )
     endif
  set pu = CreateUnit(Player(p-1),'uske' , xt,yt, 0)
  call GroupAddUnit(udg_Summon_I, pu)
  call UnitAddType( pu, UNIT_TYPE_SUMMONED )
  if lv > 1 then
    call UnitAddAbility (pu, 'Arel')
  endif
  if lv > 2 then
    call UnitAddAbility (pu, 'AIae')
  endif
  if lv > 3 then
    call UnitAddAbility (pu, 'ACrk')
  endif
  if lv > 4 then
    call UnitAddAbility (pu, 'AIrr')
  endif
endif

if a == 'A03U' then
     if CountUnitsInGroup(udg_Summon_II)==4 then
      set pu = FirstOfGroup(udg_Summon_II)
      call GroupRemoveUnit(udg_Summon_II, pu)
      call DestroyEffect (AddSpecialEffect (s2, GetUnitX(pu),GetUnitY(pu)))      
      call KillUnit( pu )
     endif
  set pu = CreateUnit(Player(p-1),'nsca' , xt,yt, 0)
  call GroupAddUnit(udg_Summon_II, pu)
  call UnitAddType( pu, UNIT_TYPE_SUMMONED )
  set cv = GetUnitUserData(pu)
  if lv > 1 then
    set udg_Global_Crit[cv] = udg_Global_Crit[cv] + 5
  endif
  if lv > 2 then
    set udg_Global_Eva[cv] = udg_Global_Eva[cv] + 10
  endif
  if lv > 3 then
  //  call UnitAddAbility (pu, 'ACcw')
  endif
  if lv > 4 then
    call UnitAddAbility (pu, 'ACbh')
  endif
endif

if a == 'A040' then
     if CountUnitsInGroup(udg_Summon_III)==3 then
      set pu = FirstOfGroup(udg_Summon_III)
      call GroupRemoveUnit(udg_Summon_III, pu)
      call DestroyEffect (AddSpecialEffect (s2, GetUnitX(pu),GetUnitY(pu)))      
      call KillUnit( pu )
     endif
  set pu = CreateUnit(Player(p-1),'uskm' , xt,yt, 0)
  call GroupAddUnit(udg_Summon_III, pu)
  call UnitAddType( pu, UNIT_TYPE_SUMMONED )
  set cv = GetUnitUserData(pu)
  if lv > 1 then
    call UnitAddAbility (pu, 'AIrm')
  endif
  if lv > 2 then
    call UnitAddAbility (pu, 'AIse')
  endif
  if lv > 3 then
    call UnitAddAbility (pu, 'AIav')
  endif
  if lv > 4 then
    call UnitAddAbility (pu, 'AIos')
  endif
endif

set cv = GetUnitUserData(pu)
call AddDef (pu, hlv)
call SetUnitScale(pu, size, size, size)

set pl = null
set pu = null
set u = null
set s1 = null
set s2 = null
endfunction

//===========================================================================
function InitTrig_Summons_for_necro takes nothing returns nothing
    set gg_trg_Summons_for_necro = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Summons_for_necro, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Summons_for_necro, Condition( function Trig_Summons_for_necro_Conditions ) )
    call TriggerAddAction( gg_trg_Summons_for_necro, function Trig_Summons_for_necro_Actions )
endfunction
 
Level 14
Joined
Apr 20, 2009
Messages
1,543
Looks like you don't know what chains and pointers are.

By the way. He didn't say that more than 1 player can summon, did he?

And why exactly does he need to know how pointers and chains work if he knows that referencing variables is faster then re-using the same function calls?
I know why learning the underlying structure is good, but it's not necessary for creating optimized Jass script...

Also C++ is not the same as Jass, in C++ it's about clean and less code to make your CPU execute as fast as possible.
In Jass this doesn't necessarily have to be true.
In Jass it's about how many function calls are being executed, using a so called BJ native (the red function calls that are in the editor by default) your calling other functions. Which can actually be done more efficiently by directly calling the functions inside the BJ.

So for example:
Instead of using the red BJ native, you can search for this native in the function list at the header of your map in order to see which functions this BJ calls, you can then call these functions yourself instead of calling the BJ making it easier for the CPU to handle since less functions are then called.

An example in code can be found in shadowvzs's posts...

But is good to know how they made it to optimize scripts.

About remounting DLL's: not a good idea, it's considered to be a hack eventually because your altering game data. And it will get you banned...
If you, MajorKaza can show us 1 example of how it can improve and optimize Jass script, then I will agree on your so called "mandatory" statement...

One more thing: the new posts in here are irrelevant to the topic at hand,
I suggest we await the requests/instructions of the OP and drop this conversation unless significant information on this conversation can be contributed.
 
Last edited:
Level 9
Joined
Nov 19, 2011
Messages
516
Sorry but you used too many words that I don't know.

I understood only that we are going out of thread and that remounting DLL will be hack (I agree). But I still can't see why PICK ALL UNITS function should be faster than pick units in group of 10....?

By the way. You are best trigger/script helper I've met here. Maby you will slove my problem?
http://www.hiveworkshop.com/forums/triggers-scripts-269/buying-item-209946/
 
Last edited:
Level 17
Joined
Nov 13, 2006
Messages
1,814
I understood only that we are going out of thread and that remounting DLL will be hack (I agree). But I still can't see why PICK ALL UNITS function should be faster than pick units in group of 10....?

sorry but point was, unit group easier than unit array if we do for more player, another thing there dont was pick all unit, also the main point optimezed trigger faster than regular, another point if u skip that pretty small speed difference between pick all unit owned by x player and x unit group array then u can ignore the useing global variable (after u use 200+ global variable, maybe u understand why confusing the huge amount of global variable)
 
Status
Not open for further replies.
Top