the KNOCKBACK ability

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
daonlynussa
Posts: 12
Joined: March 16th, 2010, 12:00 am

the KNOCKBACK ability

Post by daonlynussa »

i am new to wml and was looking arround on the site. im creating a unit and wanted to include this ability. the macro was listed on the site, but i am somewhat macro illiterate. can some one show me an example of how to use this?
User avatar
Pentarctagon
Project Manager
Posts: 5732
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: the KNOCKBACK ability

Post by Pentarctagon »

these pages on the wiki might help: UnitTypeWML and AbilitiesWML
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: the KNOCKBACK ability

Post by zookeeper »

For anyone interested, I wrote a more modern implementation of knockback and replaced the ancient version in the wiki with it. It now correctly makes sure that units can't be pushed back onto terrain they couldn't normally move to.
User avatar
MrEPIC
Posts: 103
Joined: June 9th, 2009, 12:20 am
Location: GMT-6/-5

Re: the KNOCKBACK ability

Post by MrEPIC »

Code: Select all

   
[event]
       name=attacker hits
       first_time_only=no
   
       [filter_attack]
           special=knockback
       [/filter_attack]
   
       [filter_second]
           [not]
               [filter_location]
                   terrain=*^V*
               [/filter_location]
           [/not]
       [/filter_second]
   
       [if]   #The hitpoint subtraction seems to take place before this filter is passed, so 0 is more suitable
           [variable]
               name=second_unit.hitpoints      
               greater_than=0
           [/variable]                        
There was a tiny problem in that code which prevented the knockback from happening unless the targeted unit had at least double the hitpoints of what was inflicted on them. I am assuming that this was not the intended behavior, so I just changed $damage_inflicted to 0. Besides that issue, everything seems to be working alright, thanks zookeeper!

To use the special, you would need to place the event code and the dummy weapon special macro (linked by zookeeper in previous post) into your scenario or era file. Then, you would need to give a unit the special. For example, if you gave this special to the melee attacks of all units recruited by side 1, then the code would be:

Code: Select all

[event]
    name=recruit
    first_time_only=no
    [filter]
        side=1
    [/filter]
    [object]
        silent=yes
        [effect]
            apply_to=attack
            range=melee
            [set_specials]
                mode=append
                {WEAPON_SPECIAL_KNOCKBACK}
            [/set_specials]
        [/effect]
    [/object]
[/event]
Last edited by MrEPIC on March 16th, 2010, 4:19 pm, edited 1 time in total.
3 player co-op campaign: The Haunted Woods (v1.6.19)
1v1 campaign: Tug of War (v0.4.0)
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: the KNOCKBACK ability

Post by zookeeper »

MrEPIC wrote:There was a tiny problem in that code which prevented the knockback from happening unless the targeted unit had at least double the hitpoints of what was inflicted on them. I am assuming that this was not the intended behavior, so I just changed $damage_inflicted to 0.
Oh right, good catch. It's fixed now in the wiki, too.
daonlynussa
Posts: 12
Joined: March 16th, 2010, 12:00 am

Re: the KNOCKBACK ability

Post by daonlynussa »

Thanks so much!
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: the KNOCKBACK ability

Post by Dixie »

I am also looking forward to inserting this in an era I'm working on at the moment. I do have some questions however:

- With the code zookeeper offers in the wiki, we don,t need to add a macro from the Utility page some place strange like it said on some other/older wiki, if I am not mistaken? Only the present code is needed?

- I thought of knockback of more of a defensive move than an offensive one. You know, one for ranged units to push away melee attackers. Is it possible to make it work on defense? What would I have to change? Would this look ok? :

Code: Select all

   [event]
       name=defender hits
       first_time_only=no
   
[...]

   [/event]
(I changed "attacker" for "defender")
If this modification is right, I suspect it would only work on defense. Could it work both on offense and defense? How would I pull that off?

- I also wanted to make a smokebomb variation of the ability. The unit using the 0-1 smokebomb would retreat back one hex if its attack hit (even though it would cause no damage). Do you think this is possible? Would this seem right to you (I didn't change the word "knockback", it would probably because something like "flee") ? :

Code: Select all


[...]

           [then]
               [if]
                   [have_unit]
                       x,y=$x1,$y1
                       [filter_adjacent]
                           x,y=$x2,$y2
                           adjacent=n
                       [/filter_adjacent]
                   [/have_unit]
                   [then]
                       {VARIABLE knockback_direction s}
                   [/then]
                   [else]
                       [if]
                           [have_unit]
                               x,y=$x1,$y1
                               [filter_adjacent]
                                   x,y=$x2,$y2
                                   adjacent=ne
                               [/filter_adjacent]
                           [/have_unit]
                           [then]
                               {VARIABLE knockback_direction sw}
                           [/then]
                           [else]
                               [if]
                                   [have_unit]
                                       x,y=$x1,$y1
                                       [filter_adjacent]
                                           x,y=$x2,$y2
                                           adjacent=se
                                       [/filter_adjacent]
                                   [/have_unit]
                                   [then]
                                       {VARIABLE knockback_direction nw}
                                   [/then]
                                   [else]
                                       [if]
                                           [have_unit]
                                               x,y=$x1,$y1
                                               [filter_adjacent]
                                                   x,y=$x2,$y2
                                                   adjacent=s
                                               [/filter_adjacent]
                                           [/have_unit]
                                           [then]
                                               {VARIABLE knockback_direction n}
                                           [/then]
                                           [else]
                                               [if]
                                                   [have_unit]
                                                       x,y=$x1,$y1
                                                       [filter_adjacent]
                                                           x,y=$x2,$y2
                                                           adjacent=sw
                                                       [/filter_adjacent]
                                                   [/have_unit]
                                                   [then]
                                                       {VARIABLE knockback_direction ne}
                                                   [/then]
                                                   [else]
                                                       [if]
                                                           [have_unit]
                                                               x,y=$x1,$y1
                                                               [filter_adjacent]
                                                                   x,y=$x2,$y2
                                                                   adjacent=nw
                                                               [/filter_adjacent]
                                                           [/have_unit]
                                                           [then]
                                                               {VARIABLE knockback_direction se}
                                                           [/then]
                                                       [/if]
                                                   [/else]
                                               [/if]
                                           [/else]
                                       [/if]
                                   [/else]
                               [/if]
                           [/else]
                       [/if]
                   [/else]
               [/if]

[...]

(I inverted the adjacent and knockback directions. If adjacent said "n", knockback direction would say "s")

Thanks in advance for your pointers! :)
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Re: the KNOCKBACK ability

Post by Sapient »

FYI, it is possible to reverse direction using a minus sign.
So, "-n" is the same as "s"
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: the KNOCKBACK ability

Post by Dixie »

Ok, people, I think I figured out how to make a reverse knockback (or "flee") by myself. I'll test it out and come back if I am wrong and can't figure out why.

I still have one question, though. The description says it only works on offense. But then, shouldn't the code on the wiki include something like "apply_to=attack" somewhere? I've looked at it a lot and can't find it. Does it mean there's a mistake in the code and that it would actually work on offense AND defense (which I actually want, by the way)?

Oh, and thanks for the "-n" trick :)

Edit:
And before I go, if I include the whole [event] tag in the "#define WEAPON_SPECIAL_KNOCKBACK" like a lot of eras do with their abilities, would it work out anyway by linking my units to it with some kind of "{WEAPON_SPECIAL_KNOCKBACK}" tag (like with other mainline abilities)? I planned on putting it all in some abilities.cfg file with other costum abilities...
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: the KNOCKBACK ability

Post by zookeeper »

Dixie wrote:Edit:
And before I go, if I include the whole [event] tag in the "#define WEAPON_SPECIAL_KNOCKBACK" like a lot of eras do with their abilities, would it work out anyway by linking my units to it with some kind of "{WEAPON_SPECIAL_KNOCKBACK}" tag (like with other mainline abilities)? I planned on putting it all in some abilities.cfg file with other costum abilities...
Just put the [event] tag inside your [era], that's the easiest way. And it's a good idea to do that by putting it in some abilities-events.cfg file and then include it from inside the [era].
fog_of_gold
Posts: 637
Joined: December 20th, 2009, 5:59 pm
Location: Germany

Re: the KNOCKBACK ability

Post by fog_of_gold »

I think it's better and easier to include them in a [/abilities] [+abilities] "tag".
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: the KNOCKBACK ability

Post by Dixie »

I will look further into it tonight, but now that I've been able to test my era more, I note that my "Retreat" (or reverse knockback) doesn't work, even though it appears next to the unit's weapon.

The ability should work both on offense and defense (although I really don't know why a unit would want to use it on offense since it's primarily a defensive thing). When the attack with "Retreat" hits, instead of the target being knocked back one hex, it's the attacker that goes back a hex (flees the encounter).

Here is the code for my ability:

Code: Select all

#define WEAPON_SPECIAL_RETREAT
       [dummy]
           id=retreat
           name= _ "retreat"
           female_name= _ "female^retreat"
           description=_ "Retreat:
   When a unit scores a hit with a retreat attack, it allows it to move back one hex, thus interupting the attack. A unit can't retreat from a village, however, and can't move into an occupied space or a space it couldn't normally move to."
       [/dummy]

[event]
       name=attacker hits
       first_time_only=no
   
       [filter_attack]
           special=retreat
       [/filter_attack]
   
       [filter_second]
           [not]
               [filter_location]
                   terrain=*^V*
               [/filter_location]
           [/not]
       [/filter_second]
   
       [if]
           [variable]
               name=second_unit.hitpoints
               greater_than=0
           [/variable]
   
           [then]
               [if]
                   [have_unit]
                       x,y=$x1,$y1
                       [filter_adjacent]
                           x,y=$x2,$y2
                           adjacent=n
                       [/filter_adjacent]
                   [/have_unit]
                   [then]
                       {VARIABLE retreat_direction -n}
                   [/then]
                   [else]
                       [if]
                           [have_unit]
                               x,y=$x1,$y1
                               [filter_adjacent]
                                   x,y=$x2,$y2
                                   adjacent=ne
                               [/filter_adjacent]
                           [/have_unit]
                           [then]
                               {VARIABLE retreat_direction -ne}
                           [/then]
                           [else]
                               [if]
                                   [have_unit]
                                       x,y=$x1,$y1
                                       [filter_adjacent]
                                           x,y=$x2,$y2
                                           adjacent=se
                                       [/filter_adjacent]
                                   [/have_unit]
                                   [then]
                                       {VARIABLE retreat_direction -se}
                                   [/then]
                                   [else]
                                       [if]
                                           [have_unit]
                                               x,y=$x1,$y1
                                               [filter_adjacent]
                                                   x,y=$x2,$y2
                                                   adjacent=s
                                               [/filter_adjacent]
                                           [/have_unit]
                                           [then]
                                               {VARIABLE retreat_direction -s}
                                           [/then]
                                           [else]
                                               [if]
                                                   [have_unit]
                                                       x,y=$x1,$y1
                                                       [filter_adjacent]
                                                           x,y=$x2,$y2
                                                           adjacent=sw
                                                       [/filter_adjacent]
                                                   [/have_unit]
                                                   [then]
                                                       {VARIABLE retreat_direction -sw}
                                                   [/then]
                                                   [else]
                                                       [if]
                                                           [have_unit]
                                                               x,y=$x1,$y1
                                                               [filter_adjacent]
                                                                   x,y=$x2,$y2
                                                                   adjacent=nw
                                                               [/filter_adjacent]
                                                           [/have_unit]
                                                           [then]
                                                               {VARIABLE retreat_direction -nw}
                                                           [/then]
                                                       [/if]
                                                   [/else]
                                               [/if]
                                           [/else]
                                       [/if]
                                   [/else]
                               [/if]
                           [/else]
                       [/if]
                   [/else]
               [/if]
   
               [store_locations]
                   [not]
                       [filter]
                       [/filter]
                   [/not]
   
                   [filter_adjacent_location]
                       x,y=$x1,$y1
                       adjacent=$retreat_direction
                   [/filter_adjacent_location]
   
                   variable=retreat_target_hex
               [/store_locations]
   
               [if]
                   [variable]
                       name=retreat_target_hex.length
                       greater_than=0
                   [/variable]
   
                   [then]
                       [teleport]
                           [filter]
                               x,y=$x1,$y1
                           [/filter]
   
                           x,y=$retreat_target_hex.x,$retreat_target_hex.y
                           ignore_passability=no
                       [/teleport]
   
                       [if]
                           [have_unit]
                               x,y=$retreat_target_hex.x,$retreat_target_hex.y
                           [/have_unit]
   
                           [then]
                               [sound]
                                   name=fist.ogg
                               [/sound]
   
                               # the knockbacked unit doesn't seem to receive experience by default,
                               # so we need to add it manually
                               [store_unit]
                                   [filter]
                                       x,y=$retreat_target_hex.x,$retreat_target_hex.y
                                   [/filter]
   
                                   kill=yes
                                   variable=fled
                               [/store_unit]
   
                               {VARIABLE_OP fled.experience add $unit.level}
   
                               [unstore_unit]
                                   variable=fled
                                   text= _ "escaped"
                                   {COLOR_HARM}
                                   advance=true
                               [/unstore_unit]
   
                               {CLEAR_VARIABLE fled}
                           [/then]
                       [/if]
                   [/then]
               [/if]
   
               {CLEAR_VARIABLE retreat_direction,retreat_target_hex}
           [/then]
       [/if]
   [/event]

#enddef
It occurs to me the problem might come from the whole "abilities.cfg" file, so here it is:
Spoiler:
Anyway, it looked fine to me, but hey, I'm no expert. Any thoughts on how I might fix this?
Thanks a lot!
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
User avatar
Dixie
Posts: 1757
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: the KNOCKBACK ability

Post by Dixie »

I've tried it a bit this morning, and noticed that the knockback ability suggested above doesn't work either (for me, at least). Did I integrate it wrong? I put it in a "ability.cfg" file (along with other abilities. The file is in the previous post), which is integrated via the "_main.cfg" file in my era folder. It works for other costum abilities such as Hit and Run, so I suspect de problem must be coming from the knockback code rather than the way it is integrate. Even though you suggested I put it in some other way (which I might try out tonight)...

I know it's once again a lot of code, but just to be sure, here's what it looks like:

Code: Select all

#define WEAPON_SPECIAL_KNOCKBACK
       [dummy]
           id=knockback
           name= _ "knockback"
           female_name= _ "female^knockback"
           description=_ "Knockback:
   When a unit is hit with a knockback attack, it is immediately pushed back one hex away from the attacker. Units cannot be knocked back into an occupied hex, out of villages or onto terrain they normally could not move to."
       [/dummy]

[event]
       name=attacker hits
       first_time_only=no
   
       [filter_attack]
           special=knockback
       [/filter_attack]
   
       [filter_second]
           [not]
               [filter_location]
                   terrain=*^V*
               [/filter_location]
           [/not]
       [/filter_second]
   
       [if]
           [variable]
               name=second_unit.hitpoints
               greater_than=0
           [/variable]
   
           [then]
               [if]
                   [have_unit]
                       x,y=$x1,$y1
                       [filter_adjacent]
                           x,y=$x2,$y2
                           adjacent=n
                       [/filter_adjacent]
                   [/have_unit]
                   [then]
                       {VARIABLE knockback_direction n}
                   [/then]
                   [else]
                       [if]
                           [have_unit]
                               x,y=$x1,$y1
                               [filter_adjacent]
                                   x,y=$x2,$y2
                                   adjacent=ne
                               [/filter_adjacent]
                           [/have_unit]
                           [then]
                               {VARIABLE knockback_direction ne}
                           [/then]
                           [else]
                               [if]
                                   [have_unit]
                                       x,y=$x1,$y1
                                       [filter_adjacent]
                                           x,y=$x2,$y2
                                           adjacent=se
                                       [/filter_adjacent]
                                   [/have_unit]
                                   [then]
                                       {VARIABLE knockback_direction se}
                                   [/then]
                                   [else]
                                       [if]
                                           [have_unit]
                                               x,y=$x1,$y1
                                               [filter_adjacent]
                                                   x,y=$x2,$y2
                                                   adjacent=s
                                               [/filter_adjacent]
                                           [/have_unit]
                                           [then]
                                               {VARIABLE knockback_direction s}
                                           [/then]
                                           [else]
                                               [if]
                                                   [have_unit]
                                                       x,y=$x1,$y1
                                                       [filter_adjacent]
                                                           x,y=$x2,$y2
                                                           adjacent=sw
                                                       [/filter_adjacent]
                                                   [/have_unit]
                                                   [then]
                                                       {VARIABLE knockback_direction sw}
                                                   [/then]
                                                   [else]
                                                       [if]
                                                           [have_unit]
                                                               x,y=$x1,$y1
                                                               [filter_adjacent]
                                                                   x,y=$x2,$y2
                                                                   adjacent=nw
                                                               [/filter_adjacent]
                                                           [/have_unit]
                                                           [then]
                                                               {VARIABLE knockback_direction nw}
                                                           [/then]
                                                       [/if]
                                                   [/else]
                                               [/if]
                                           [/else]
                                       [/if]
                                   [/else]
                               [/if]
                           [/else]
                       [/if]
                   [/else]
               [/if]
   
               [store_locations]
                   [not]
                       [filter]
                       [/filter]
                   [/not]
   
                   [filter_adjacent_location]
                       x,y=$x2,$y2
                       adjacent=-$knockback_direction
                   [/filter_adjacent_location]
   
                   variable=knockback_target_hex
               [/store_locations]
   
               [if]
                   [variable]
                       name=knockback_target_hex.length
                       greater_than=0
                   [/variable]
   
                   [then]
                       [teleport]
                           [filter]
                               x,y=$x2,$y2
                           [/filter]
   
                           x,y=$knockback_target_hex.x,$knockback_target_hex.y
                           ignore_passability=no
                       [/teleport]
   
                       [if]
                           [have_unit]
                               x,y=$knockback_target_hex.x,$knockback_target_hex.y
                           [/have_unit]
   
                           [then]
                               [sound]
                                   name=fist.ogg
                               [/sound]
   
                               # the knockbacked unit doesn't seem to receive experience by default,
                               # so we need to add it manually
                               [store_unit]
                                   [filter]
                                       x,y=$knockback_target_hex.x,$knockback_target_hex.y
                                   [/filter]
   
                                   kill=yes
                                   variable=knockbacked
                               [/store_unit]
   
                               {VARIABLE_OP knockbacked.experience add $unit.level}
   
                               [unstore_unit]
                                   variable=knockbacked
                                   text= _ "knockback"
                                   {COLOR_HARM}
                                   advance=true
                               [/unstore_unit]
   
                               {CLEAR_VARIABLE knockbacked}
                           [/then]
                       [/if]
                   [/then]
               [/if]
   
               {CLEAR_VARIABLE knockback_direction,knockback_target_hex}
           [/then]
       [/if]
   [/event]

#enddef
Anyway, thanks again in advance for your time and thoughts!
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth
fog_of_gold
Posts: 637
Joined: December 20th, 2009, 5:59 pm
Location: Germany

Re: the KNOCKBACK ability

Post by fog_of_gold »

The [/ability] [+ability] "tag" is forgotten. So change it into something like this:
Spoiler:
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: the KNOCKBACK ability

Post by zookeeper »

fog_of_gold wrote:The [/ability] [+ability] "tag" is forgotten.
No.

The tag isn't "[ability]", this isn't an ability and that method doesn't work for weapon specials anyway (at least the last time I checked, I think).
Post Reply