Snippet DummyCaster

Jesus4Lyf

Good Idea™
Reaction score
397
Dummy Caster​
A perfect, standard dummy caster. Reproducing it in every spell and every map is lame when an object merger line and a few lines of code can do it for you perfectly.

Code:
JASS:
//
//      ___  _   _  __  __  __  __ __  __
//     |   \| | | |/  |/  |/  |/  |\ \/ /
//     | |) | |_| | / | / | / | / | \  /
//     |___/\____/_/|__/|_|/|__/|_|_|_|__
//         /  _/ /_\ / __\_   _|  __|  _ \
//        |  |_ / _ \\__ \ | | |  __|  _ /
//         \___\_/ \_\___/ |_| |____|_|\_\         By Jesus4Lyf
//
//      What is DummyCaster?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          DummyCaster is designed to be the perfect dummy caster for dummy abilities.
//          There has been a lot of thought put into this unit type, and dummy casting
//          has evolved over the years of WC3 mapping. These days, best practise is that
//          damage is triggered, and the effects of an ability such as slow or stun
//          are applied through a global dummy caster (which is owned by Neutral Hostile).
//
//          A lot of thought has been put into this unit. It has no mana, because if
//          it had mana then it could potentially run out and suddenly fail without
//          an apparent reason. It has no movement speed or casting time, allowing it
//          to instantly cast. Hence, this library only exposes one thing. A "DUMMY"
//          unit constant (global variable).
//
//          You may provide this unit with a model by having a model imported into the
//          path "Dummy.mdx". The purpose of this is allowing the same unit type
//          to be created dynamically for special effect attachment.
//
//          The rawcode of the "Dummy Caster" type is 'dumy'.
//
//          Upon issueing the order to cast a spell using the DUMMY global, as long as
//          the spell is instant, the casting will occur before the next line of
//          JASS code is executed, meaning you can cast in a loop or a ForGroup, etc
//          without bugging or dynamically creating (or recycling) dummies.
//
//          The initialiser is in a struct because struct onInit methods are called
//          before library "initializers". This allows abilities to be added on the
//          constant DUMMY unit on map initialisation.
//
//          Spells that this dummy casts should have no mana cost, no cooldown, no
//          cast time and infinite range. They also must be able to be cast from a
//          Neutral Hostile unit to your target, meaning they must be castable on
//          enemies (if you must, you can change the owner of the dummy for the cast,
//          and then change it back if you need to have it target allied units and such).
//
//          Be sure to add your spell to the dummy before trying to cast it! <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
//          Beware of permenantly adding spells with conflicting order ids/strings.
//
//      How to implement?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Create a new trigger object called DummyCaster, go to &#039;Edit -&gt; Convert to
//          Custom Text&#039;, and replace everything that&#039;s there with this script.
//
//          Save the map, close it, reopen it, and then delete the &quot;!&quot; from the
//          FAR left side of the next line (so &quot;external&quot; will line up with this line):
//!          external ObjectMerger w3u ushd dumy unam &quot;Dummy Caster&quot; uabi Aloc ucbs 0 ucpt 0 umvs 0 ushu &quot;&quot; umvh 0 umdl &quot;Dummy.mdl&quot; umpi 100000 umpm 100000 umpr 1000 ufoo 0
//
//      Thanks:
//     ¯¯¯¯¯¯¯¯¯
//          - Viikuna for demonstrating how to make dummy casters cast instantaneously.
//
library DummyCaster
    // If you&#039;re looking for where the &#039;dumy&#039; type is declared, it is declared
    // in the object merger line at the end of &quot;How to implement?&quot; in the above
    // documentation.
    globals
        // If this is changed, the object merger line must also be changed
        // before the second implementation step is followed.
        constant integer DUMMY_TYPE=&#039;dumy&#039;
        
        // This shouldn&#039;t be changed, but in some maps perhaps it is necessary.
        constant player DUMMY_OWNER=Player(PLAYER_NEUTRAL_AGGRESSIVE)
        
        // Just because these belong here:
        private constant real CREATED_AT_X=0.0
        private constant real CREATED_AT_Y=0.0

//=====================================================================================
        unit DUMMY=null
    endglobals
    
    private struct Initializer extends array // &quot;extends array&quot; removes
                                             // create/destoy methods.
        // The initialisation is done this way because struct initialisers are
        // called before library initialisers, making this important for adding
        // abilities on map initialisation.
        private static method onInit takes nothing returns nothing
            set DUMMY=CreateUnit(DUMMY_OWNER,DUMMY_TYPE,CREATED_AT_X,CREATED_AT_Y,0)
        endmethod
    endstruct
endlibrary
This gives the ability for one dummy caster to be used in maps instead of multiple. No recycling or creating units with expirations and such.

Just add your spell to the DUMMY unit, and issue the cast order. It will be done immediately, so long as the spell has no cast time, no mana cost and no cooldown.

The example map shows casting entangling roots with 3 lines of jass code on 2 units.
 

Attachments

  • DummyCaster.w3x
    17 KB · Views: 607

the_ideal

user title
Reaction score
61
> Will this work in channeling spells??
I don't know JASS, but from my understanding of this system, it uses only one unit, which means that a channeling spell would work, until the dummy was needed again. So basically, it wouldn't work.
 

Jesus4Lyf

Good Idea™
Reaction score
397
JASS:
//          Spells that this dummy casts should have no mana cost, no cooldown, no
//          cast time and infinite range. They also must be able to be cast from a
//          Neutral Hostile unit to your target, meaning they must be castable on
//          enemies (if you must, you can change the owner of the dummy for the cast,
//          and then change it back if you need to have it target allied units and such).
As for dummy casting things like aerial shackles, no, you'll need to either recycle dummies or simply create and add timed life or whatever as usual. You can only use the global DUMMY for instant cast spells. (But feel free to make units of type DUMMY_TYPE as required for other such spells.)
 

Kenny

Back for now.
Reaction score
202
This is ridiculously simple, however it is also pretty helpful. Seems like something most serious mappers would already have, and most not so serious mappers have no idea about, so this definately has a purpose.

Also, about not adding mana to the unit: Why not just give it like 100,000 mana or something, and give it 1000 mana regen? (Unless you can't adjust mana in the objectmerger line). Then if someone forgets to make a spell have 0 mana, it won't be a big deal for them.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>This is ridiculously simple, however it is also pretty helpful.
This beats the crap out of manually copying a unit over each time, and allows systems submitted on TH to require a perfect, standard dummy. :thup:

I suppose you're right about mana. I will update that when I'm not running late to be somewhere else. <_<

Actually, I'll probably upload a model or two to optionally use as well.
 

Igor_Z

You can change this now in User CP.
Reaction score
61
And what if it called for 5-10 spellz at once? Will the dummy be able to cast all of them? If so I'm importing this to my map...
 

Viikuna

No Marlo no game.
Reaction score
265
Whatabout something like this?:

JASS:
library Caster requires Dummy

struct Caster
   
   readonly integer  abilityId      =      0
   readonly integer  orderId        =      0
   private  integer  level          =      1
   private  player   player         =      PLAYER_NEUTRAL
   private  unit     unit
   
   method operator owner takes nothing returns player
       return .player
   endmethod
   method operator owner= takes player p returns nothing
       call SetUnitOwner(.unit,p,false)
       set .player=p
   endmethod
   
    method operator abilityLevel takes nothing returns integer
       return .level
   endmethod
   method operator abilityLevel= takes integer i returns nothing
       call SetUnitAbilityLevel(.unit,.abilityId,i)
       set .level=i
   endmethod
   
   static method create takes integer abilityId, string order returns Caster
       local Caster this=Caster.allocate()
       if .unit == null then
          set .unit=CreateUnit(PLAYER_NEUTRAL,DUMMY_ID,Storage_X,Storage_Y,0.0)
       endif
       call UnitAddAbility(.unit,abilityId)
       set .abilityId=abilityId
       set .orderId=OrderId(order)
       return this
   endmethod
   
   method castOnUnit takes unit target returns nothing
       call SetUnitX(.unit,GetUnitX(target))
       call SetUnitY(.unit,GetUnitY(target))
       call IssueTargetOrderById(.unit,.orderId,target)
   endmethod
   
   private method onDestroy takes nothing returns nothing
       if .player != PLAYER_NEUTRAL then
           set .player=PLAYER_NEUTRAL
           call SetUnitOwner(.unit,PLAYER_NEUTRAL,false)
       endif
       call UnitRemoveAbility(.unit,.abilityId)
   endmethod
endstruct

endlibrary


The idea is, that you have one global Caster instance per spell and you can create those in some initializer function for example.

It also works for channeling spells if you dynamicly create and destroy Caster instances.

edit. Object Merger pwns. :thup:

Also, if I remember right, that castOnUnit fails, if it returns that boolean value from IssueTargetOrder. Reminds me of that stuff Sooda once said, that checking some condition sometimes acts like 0.0 timer ( I think he used it to block damage ), or something like that. Im not sure about any of this stuff, though.
 

Jesus4Lyf

Good Idea™
Reaction score
397
And what if it called for 5-10 spellz at once? Will the dummy be able to cast all of them? If so I'm importing this to my map...
As per the documentation and demo map. Please see. You can use this to cast instant spells in a loop, without and sleeps or anything - all immediate.

Viikuna, feel free to write a caster system that uses DummyCaster, but I'm not making this into a system. The point is mappers already know how to do that stuff and will do it whatever way they see fit. No reason to make them do it some standard way - all they need really is a dummy that works. I mean, I disagree with using SetUnitX and SetUnitY for each cast for example. In mine, I just give 99999 range.

News to me about issueing an order having a delay if the response is checked. Doesn't sound quite right... But I'm not sure that it is relevant.

This is here to support mappers without being a rigid framework within which to cast spells. I don't believe there's a right answer for such a thing.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
A perfect, standard dummy caster. Reproducing it in every spell and every map is lame when an object merger line and a few lines of code can do it for you perfectly.
I've no more any doubt, you are Cohadar :p
 

Romek

Super Moderator
Reaction score
963
I see you're using my header-style on all your systems now. :p

> I suppose you're right about mana. I will update that when I'm not running late to be somewhere else. <_<
I told you that. :p

Anyway, I think every map has a dummy caster as standard anyway, so I don't find this particularly useful.
It also doesn't do dummy recycling or anything of the kind.

xe and xecast module does the job better.
 

Viikuna

No Marlo no game.
Reaction score
265
Yea, long cast range does the job too if you remove move ability, so unit can turn instantly, right?


Ok, I think you are right. This does tell people not to create casters dynamically, so it does all the job it is supposed to do.

I like it.


edit.

News to me about issueing an order having a delay if the response is checked

Actually, now when you say that I think it kinda makes sense. In that case, game has to check whether the unit obeyed its order or not. And yea, its not so revelant. It just might cause some headache, if you are writing some caster system and dont know how to debug your code properly.

edit2. It should rather be Neutral Passive IMO, since you might wanna cast positive buffs to your allies too. At least I have always used Neutral Passive.

Well, I guess it doesnt mater, since you say that it is possible to change owner for positive buff thingies.

edit3. Well, I cant really find anything that not good here, so I guess this is actually perfect.

And Romek, that standard way of creating dummies alla the time sucks, because CreateUnit is slow and incereases wc3s memory usage, since units are so complex little fuckers, and because you need to do useless work to get rid of those dummies with some timed life as well as clean possible leaks and do other stuff like that.
 

RaiJin

New Member
Reaction score
40
i was wondering, does it cast instantly with chain lightning? i made a quick spell that has a 100% chance to cast chain lightning whenever attacked and it wasn't instant :/ maybe im doing something wrong?
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
and allows systems submitted on TH to require a perfect, standard dummy. :thup:
I'd just like to cast a vote against this, since it requires ObjectMerger which requires working on Windows. :p

Handy for those who can use it, though.

(Of course, one could use a hex editor on war3map.w3u, but, you know that's not terribly convenient...)
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Open the demo map and copy the unit. ;)

It's rawcode won't be 'dumy', then.

[edit] I've also taken a look at the dummy unit itself. Shouldn't its sight range be 0? Also, shouldn't you instruct people to remove the ability after use, so the neutral hostile AI won't use it? (I've had hostile dummies casting Finger of Death on their own, for example.)
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top