System Abduct

Jesus4Lyf

Good Idea™
Reaction score
397
Abduct​
Version 1.02​

Requirements:
- Jass NewGen
- AIDS
- Transport

Code:
JASS:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ~~    Abduct     ~~    By Jesus4Lyf    ~~    Version 1.02    ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//  What is Abduct?
//         - Abduct allows a unit to load units of an enemy player.
//
//  Functions:
//         - SetAbductCapacity(unit, integer)
//           Sets the number of units a unit may abduct successfully
//           at once. Use a number from 1 to 8, excluding 7. Warcraft III
//           does not allow a transport to have a maximum capacity of 7.
//
//         - GetAbductCapacity(unit)
//           Returns the abduction capacity (integer) of the unit, based on
//           SetAbductCapacity.
//
//         - RemoveAbductCapacity(unit)
//           Disallows a unit to abduct other units.
//
//         - Abduct(abductor, target)
//           Returns a boolean of success. This success is anticipated.
//           There is a slight delay until the unit is actually abducted.
//           Use this to load an enemy unit into a transport. It will
//           interrupt the transport's current order.
//
//  Details:
//         - Abduct changes the target's owner for a small amount of time while
//           it is loaded into the abductor. It then changes ownership back.
//
//  How to import:
//         - Create a trigger named Abduct.
//         - Convert it to custom text and replace the whole trigger text with this.
//         - Save the map, close it, reopen it, and then delete the "!" from the
//           FAR left side of the next lines (so "external" will line up with this line):
//!           external ObjectMerger w3a Sch3 AACG ansf "(Abduct System)" aefs "" alev 8 Car1 1 1 Car1 2 2 Car1 3 3 Car1 4 4 Car1 5 5 Car1 6 6 Car1 7 7 Car1 8 8 aare 1 0 ahdu 1 0 adur 1 0 aran 1 99999 aran 2 99999 aran 3 99999 aran 4 99999 aran 5 99999 aran 6 99999 aran 7 99999 aran 8 99999 atar 1 "friend,ground,invulnerable,vulnerable" atar 2 "friend,ground,invulnerable,vulnerable" atar 3 "friend,ground,invulnerable,vulnerable" atar 4 "friend,ground,invulnerable,vulnerable" atar 5 "friend,ground,invulnerable,vulnerable" atar 6 "friend,ground,invulnerable,vulnerable" atar 7 "friend,ground,invulnerable,vulnerable" atar 8 "friend,ground,invulnerable,vulnerable" aare 1 256 aare 2 256 aare 3 256 aare 4 256 aare 5 256 aare 6 256 aare 7 256 aare 8 256
//!           external ObjectMerger w3a Aloa AALD ansf "(Abduct System)" aran 1 99999
//
//  Thanks:
//         - Weep, for reporting the Mac unload bug and suggesting a resolution.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library Abduct initializer OnInit uses AIDS, Transport optional DummyCaster
    globals
        private constant integer ABIL_CARGO='AACG'
        private constant integer ABIL_LOAD='AALD'
        private constant integer OID_LOAD=852046
    endglobals
    private struct Data extends array
        // Abductee
        player previousOwner
        // Abductor
        unit target
        integer capacity
        private method AIDS_onDestroy takes nothing returns nothing
            // Abductee
            if this.target!=null then
                call SetUnitOwner(this.target,Data[this.target].previousOwner,false)
                set this.target=null
            endif
            // Abductor
            set this.capacity=0
        endmethod
        //! runtextmacro AIDS()
    endstruct
    function GetAbductCapacity takes unit u returns integer
        return Data<u>.capacity
    endfunction
    
    globals//locals
        private Data OrderedData
    endglobals
    private function OnAnyOrder takes nothing returns boolean
        // Safety.
        set OrderedData=Data[GetTriggerUnit()]
        if OrderedData.target!=null then
            if GetIssuedOrderId()!=OID_LOAD or GetOrderTargetUnit()!=OrderedData.target then
                call SetUnitOwner(OrderedData.target,Data[OrderedData.target].previousOwner,false)
                call UnitRemoveAbility(OrderedData.unit,ABIL_LOAD)
                set OrderedData.target=null
            endif
        endif
        return false
    endfunction
    globals//locals
        private Data LoadedData
        private Data LoadingData
    endglobals
    private function OnLoad takes nothing returns boolean
        set LoadedData=Data[GetTriggerUnit()]
        set LoadingData=Data[GetTransportUnit()]
        if LoadingData.target==LoadedData.unit then
            set LoadingData.target=null
            call SetUnitOwner(LoadedData.unit,LoadedData.previousOwner,false)
            call UnitRemoveAbility(LoadingData.unit,ABIL_LOAD)
        endif
        return false
    endfunction
    globals
        private Data AbducteeData
        private Data AbductorData
    endglobals
    function Abduct takes unit abductor, unit abductee returns boolean
        set AbductorData=Data[abductor]
        if Transport_CountPassengers(abductor)&gt;=AbductorData.capacity then
            return false
        endif
        
        set AbducteeData=Data[abductee]
        
        // So it can be loaded.
        set AbducteeData.previousOwner=GetOwningPlayer(abductee)
        call SetUnitOwner(abductee,GetOwningPlayer(abductor),false)
        
        call UnitAddAbility(abductor,ABIL_LOAD)
        if IssueTargetOrderById(abductor,OID_LOAD,abductee) then
            if AbductorData.target!=null then
                call SetUnitOwner(AbductorData.target,Data[AbductorData.target].previousOwner,false)
            endif
            set AbductorData.target=abductee
            return true
        endif
        // upon failure
        call SetUnitOwner(abductee,AbducteeData.previousOwner,false)
        call UnitRemoveAbility(abductor,ABIL_LOAD)
        return false
    endfunction
    
    function SetAbductCapacity takes unit u, integer cargo returns nothing
        debug if cargo==7 then
        debug   call BJDebugMsg(&quot;Transport: WARNING! 7 is an invalid transport capacity in Warcraft III.&quot;)
        debug endif
        call UnitAddAbility(u,ABIL_CARGO)
        set Data<u>.capacity=SetUnitAbilityLevel(u,ABIL_CARGO,cargo)
    endfunction
    function RemoveAbductCapacity takes unit u returns nothing
        call UnitRemoveAbility(u,ABIL_CARGO)
        set Data<u>.capacity=0
    endfunction
    
    private function OnInit takes nothing returns nothing
        local trigger t
        
        // Preload
        static if LIBRARY_DummyCaster then
            if UnitAddAbility(DUMMY,ABIL_LOAD) then
                call UnitRemoveAbility(DUMMY,ABIL_LOAD)
            endif
            if UnitAddAbility(DUMMY,ABIL_CARGO) then
                call UnitRemoveAbility(DUMMY,ABIL_CARGO)
            endif
        else
            local unit u=CreateUnit(Player(15),&#039;uloc&#039;,0,0,0)
            call UnitAddAbility(u,ABIL_LOAD)
            call UnitAddAbility(u,ABIL_CARGO)
            call RemoveUnit(u)
            set u=null
        endif
        
        // On load event.
        set t=CreateTrigger()
        call TriggerAddCondition(t,Filter(function OnLoad))
        call Transport_RegisterLoadEvent(t)
        
        // On any order.
        set t=CreateTrigger()
        call TriggerAddCondition(t,Filter(function OnAnyOrder))
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ISSUED_ORDER)
        
        set t=null
    endfunction
endlibrary
</u></u></u>

This allows you to force load an enemy unit into a transport unit. It makes a good replacement for Devour, as you can trigger the effects yourself, and unload the loaded units at will instead of forcing them to remain until they die. It also allows you to load multiple units at once (unlike Devour). In addition, you can call this from whatever context you like (not just as an ability).

Example:
Add a single footman to a map and it will abduct enemies instead of attack them with this code.
JASS:
scope AbductDemo initializer OnInit
    private function OnAttack takes nothing returns boolean
        if Abduct(GetAttacker(),GetTriggerUnit()) then
            call BJDebugMsg(GetUnitName(GetAttacker())+&quot; has abducted &quot;+GetUnitName(GetTriggerUnit())+&quot;.&quot;)
        else
            call BJDebugMsg(GetUnitName(GetAttacker())+&quot; failed to abduct &quot;+GetUnitName(GetTriggerUnit())+&quot;.&quot;)
        endif
        return false
    endfunction
    private function OnInit takes nothing returns nothing
        local trigger t=CreateTrigger()
        local unit footman=GroupPickRandomUnit(GetUnitsOfTypeIdAll(&#039;hfoo&#039;))
        call SetAbductCapacity(footman,2)
        
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
        call TriggerAddCondition(t,Filter(function OnAttack))
    endfunction
endscope
Use the Transport functions to iterate over all units abducted by a unit, or detect when a unit is released, etc. :)

Updates:
- Version 1.02: Fixed a bug where Mac users could not unload Abducted units. Fixed a typo in a debug message.
- Version 1.01: Added GetAbductCapacity and optional DummyCaster use for preloading.
- Version 1.00: Release.
 

Attachments

  • Abduct.w3x
    46.5 KB · Views: 259

black.sheep

Active Member
Reaction score
24
Possible for the unit to fight back?

Anyway, I could use this for some crazy blob like monster in my map that can eat people, should be fun.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Anyway, I could use this for some crazy blob like monster in my map that can eat people, should be fun.
Actually, this was inspired by the Blob model NullCurrent released a while ago. Funny that we think the same...

Look at the features in Transport and you'll see they tie in closely as well. :)

>Possible for the unit to fight back?
Not once abducted, of course... you trigger when the abduction happens yourself though, so that should not be an issue. ;)
 

Narks

Vastly intelligent whale-like being from the stars
Reaction score
90
om nom nom nom nom

Shouldn't this be integrated into Transport?
 

uberfoop

~=Admiral Stukov=~
Reaction score
177
Shouldn't this be integrated into Transport?
Nah, there's no reason to build two systems together just because one can detect actions carried out by the other. It makes sense with things like damage detection systems where, for full functionality, you must monopolize on on a gameplay element (such as spell-inflicted damage). But this isn't such a case. Transport does not need to specifically control transportation in order to properly detect transportation-related stuff.


On the other hand, I haven't tested it; does transport properly detect the owner of a unit being transported via Abduct? If not, I suppose there is at least some argument for making the systems recognize each other better.
 

Jesus4Lyf

Good Idea™
Reaction score
397
>On the other hand, I haven't tested it; does transport properly detect the owner of a unit being transported via Abduct?
Considering that Abduct is a function called by the mapper, not something natural that happens in gameplay, I don't think this is an issue...
I could add a function to get the true owner of an abducted unit, but at the moment, I expect when the OnLoad event fires, the abducted unit's owner will be the transport's owner... =/

I was originally going to integrate them, but then figured it was overkill to have objectmerger stuff in transport.
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
How come, in your demo map, when I try to drop an abducted peasant, it says, "Unable to land there," and won't unload it?
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Replay attached, Mac/1.24c beta.
[edit] Same result in 1.24b.
 

Attachments

  • AbductError.w3g
    1.6 KB · Views: 242

Weep

Godspeed to the sound of the pounding
Reaction score
400
Edit: What if you have a blank map with just Transport implemented, a goblin zeplin and a footman? Can you unload the footman?
Yes, the Transport demo map works fine.

[edit] I don't know if this makes any difference or is intentional, but in the Abduct map, the footman does not have any load/unload buttons - the only way to drop (which fails for me) is to click on the abducted unit's portrait in the unit status box area thing.
 

Tru_Power22

You can change this now in User CP.
Reaction score
144
Very cool +rep.

Was reading the documentation, I lol'd at the fact that you can't load 7 units.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Lol, thanks. :)
Was reading the documentation, I lol'd at the fact that you can't load 7 units.
Yea... well you can load 7 units but that can't be the maximum capacity - it must be 8. Wtf? :p WC3 thing.

>Was reading the documentation
Always good to hear. ;)

Edit:
>I don't know if this makes any difference or is intentional, but in the Abduct map, the footman does not have any load/unload buttons - the only way to drop (which fails for me) is to click on the abducted unit's portrait in the unit status box area thing.

Tried getting your replay to work but couldn't. <_< It just wouldn't find the map...

Hm, when I run the map I also don't have an unload button, but it doesn't seem to matter. I click the portrait of the peasant, and it unloads fine... Mac issue?

Let me know if you find a solution. Perhaps adding the unload ability. If it works with the unload ability, but disabled for that player, I can add that as a fix (or something)... :)
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
Tried getting your replay to work but couldn't. <_< It just wouldn't find the map...
Yeah, I test maps from a different folder. It was a boring replay anyway - the error text didn't even show up in playback. :p

The problem is with the AOE of your Cargo Hold ability. Too low, and it gives an error when attempting to drop. This seems to be related to the collision sizes of the units, but I don't know how (eg. 85 was not enough to drop a Blood Mage from a Footman, but 90 was; 90 was not enough to drop an Infernal from a Footman, but 125 was.)
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
The default is 250, so, sure...

[edit] Abduct 1.02 works.
 
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