wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Resources > - Submit a resource -
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 07-15-2010, 07:27 PM   #1
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default [script] Skill Learnable

Well, after some investigation i found a way to check whether a hero can learn a specific ability.

This uses vJass and Table.

Collapse Library Code:
/**
 *                  SKILL LEARNABLE
 *                     by Deaod
 *
 * A library to check whether an ability can be learned by
 * a specific unit type.
 *
 * CREDITS:
 *  - Vexorian (Table, JassHelper)
 *  - MindWorX (JassNewGenPack)
 *  - PitzerMike (JassNewGenPack)
 *  - PipeDream (Grimoire)
 *  - SFilip (TESH)
 *
 * API:
 *
 *  function HeroCanLearnSkill takes unit hero, integer abilityId returns boolean
 *  Parameters:
 *      hero - The unit you want to check whether its able to learn abilityId.
 *      abilityId - The ability you want to check whether hero is able to learn it.
 *
 *  Returns:
 *      true if hero is able to learn abilityId
 *      false otherwise.
 *
 *  Note: 
 *      If CACHE_UNITS is true, don't use this function in
 *      struct or module initializers. It won't work.
 *
 *  function IsCheckingHeroSkill takes nothing returns boolean
 *  Returns:
 *      true if HeroCanLearnSkill is currently running
 *      false otherwise
 *
 *  Note:
 *      This was added to prevent endless recursion which would crash WC3.
 *      HeroCanLearnSkill uses the following natives, make sure you dont
 *      get endless recursion when for example hooking one of these:
 *      GetUnitTypeId, HaveSavedBoolean, LoadBoolean, PauseUnit, CreateUnit, Player,
 *      ShowUnit, UnitAddAbility, IssueImmediateOrderById, UnitRemoveAbility,
 *      SaveBoolean, RemoveUnit
 * 
 */
library SkillLearnable initializer Init requires Table
    
    // CONFIGURATION CONSTANTS
    // It's okay, go ahead and modify those.
    globals
        private constant    boolean             CACHE_UNITS                 = true
        // If true, only one unit is created for each ID thats checked if it can learn an ability.
        // 
        // If false, a unit is created every time you need to check if a type ID can learn an ability.
        // After the check the unit is removed.
        
        private constant    boolean             CACHE_RESULTS               = true
        // If true, the result for HeroCanLearnSkill is only calculated once and then stored for future use.
        //
        // If false, the result for HeroCanLearnSkill is calculated every time you request it.
        // I recommend setting this to false only if youre VERY short on hashtable instances
        
        private constant    real                SAFE_X                      = 0.
        private constant    real                SAFE_Y                      = 0.
        // indicates a position on the map where the dummy units are to be stored, if CACHE_UNITS is true.
        // choose a location where hidden units wont affect gameplay.
        
        private constant    integer             DUMMY_PLAYER_ID             = 15
        // 
        
        private constant    integer             RETRAINING_ABILITY          = 'Aret'
        // As custom abilities based off of 'Aret' wont work, you should never change this.
        private constant    integer             RETRAINING_ORDER            = 852471
        // The order doesnt have a string associated to it, and probably cant be changed in 'Aret',
        // so leave it as it is.
    endglobals
    
    // Don't touch anything blow.
    
    globals
        private Table UnitCacheTable=0
        private unit array UnitCache
        private integer CacheSize=0
        
        private boolean Checking=false
        
        private hashtable ResultsTable=null
    endglobals
    
    // Dont use before library initialization
    function HeroCanLearnSkill takes unit hero, integer abilityId returns boolean
    local integer heroUnitId=GetUnitTypeId(hero)
    local unit dummy
    local boolean result
        static if CACHE_RESULTS then
            if HaveSavedBoolean(ResultsTable, heroUnitId, abilityId) then
                return LoadBoolean(ResultsTable, heroUnitId, abilityId)
            endif
        endif
        static if CACHE_UNITS then
            set Checking=true
            if UnitCacheTable[heroUnitId]>0 then
                set dummy=UnitCache[UnitCacheTable[heroUnitId]]
                call PauseUnit(dummy, false) // paused units cant be issued orders, so unpause the dummy
            else
                set dummy=CreateUnit(Player(DUMMY_PLAYER_ID), heroUnitId, SAFE_X, SAFE_Y, 0)
                call ShowUnit(dummy, false)
                call UnitAddAbility(dummy, 'Aloc') // turn off collision, avoid detection by GroupEnumUnitsInRect/Range, make unit invulnerable
                call UnitAddAbility(dummy, RETRAINING_ABILITY) // Add the Tome of Retraining ability
                set CacheSize=CacheSize+1 // this ensures UnitCache[0] is never filled
                set UnitCache[CacheSize]=dummy
                set UnitCacheTable[heroUnitId]=CacheSize
            endif
            call UnitAddAbility(dummy, abilityId)
            set result=IssueImmediateOrderById(dummy, RETRAINING_ORDER) // try using the Tome of Retraining ability.
            // IssueImmediateOrderById returns false if the unit doesnt have an ability it can unlearn.
            if not result then
                call UnitRemoveAbility(dummy, abilityId)
            endif
            call PauseUnit(dummy, true) // make sure dummy units don't interact with actual units
            static if CACHE_RESULTS then
                call SaveBoolean(ResultsTable, heroUnitId, abilityId, result)
            endif
            set Checking=false
            return result
        else
            set Checking=true
            set dummy=CreateUnit(Player(DUMMY_PLAYER_ID), heroUnitId, SAFE_X, SAFE_Y, 0)
            call ShowUnit(dummy, false)
            call UnitAddAbility(dummy, abilityId)
            call UnitAddAbility(dummy, RETRAINING_ABILITY)
            set result=IssueImmediateOrderById(dummy, RETRAINING_ORDER)
            call RemoveUnit(dummy) // because killing isnt enough for heroes.
            set dummy=null
            static if CACHE_RESULTS then
                call SaveBoolean(ResultsTable, heroUnitId, abilityId, result)
            endif
            set Checking=false
            return result
        endif
    endfunction
    
    function IsCheckingHeroSkill takes nothing returns boolean
        return Checking
    endfunction
    
    private function Init takes nothing returns nothing
        set UnitCacheTable=Table.create()
        static if CACHE_RESULTS then
            set ResultsTable=InitHashtable()
        endif
    endfunction
    
endlibrary
__________________

Last edited by Deaod : 07-19-2010 at 08:26 AM.
Deaod is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 07-16-2010, 03:37 PM   #2
Tyrande_ma3x
User
 
Tyrande_ma3x's Avatar
 
Join Date: Feb 2009
Posts: 185

Submissions (1)

Tyrande_ma3x is on a distinguished road (12)

Default

I can't understand what this check consists of - it checks if, for example, a Hero has remaining levels of a specific spell to learn or what?
Tyrande_ma3x is offline   Reply With Quote
Old 07-16-2010, 08:03 PM   #3
Michael Peppers
Lepus?
 
Michael Peppers's Avatar
 
Join Date: Jan 2009
Posts: 1,308

Michael Peppers is a jewel in the rough (188)Michael Peppers is a jewel in the rough (188)Michael Peppers is a jewel in the rough (188)

Default

Quote:
Originally Posted by Tyrande_ma3x
I can't understand what this check consists of - it checks if, for example, a Hero has remaining levels of a specific spell to learn or what?
It's clearly explained in the comments.

First, this script creates a dummy hero of the same kind you want to check, then he gives it the skill you decided and the "Tome Of Retraining" skill, then
Collapse JASS:
            set result=IssueImmediateOrderById(dummy, RETRAINING_ORDER) // try using the Tome of Retraining ability.
            // IssueImmediateOrderById returns false if the unit doesnt have an ability it can unlearn.

If it can't unlearn the ability, it can't learn it as well.

Good job on discovering this, Deaod!
__________________
Projects:Tutorials: Competitive AI Step by Step with AI Editor (Pending)
Resources: [AI Script] Michael Peppers's Melee AI template (Pending)

Last edited by Michael Peppers : 07-16-2010 at 08:08 PM.
Michael Peppers is offline   Reply With Quote
Old 07-16-2010, 08:20 PM   #4
DioD
obey
 
DioD's Avatar
 
Join Date: Feb 2006
Posts: 1,532

Submissions (4)

DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)DioD is a jewel in the rough (220)

Send a message via ICQ to DioD
Default

it checks hero for specific learnable skill (if hero not learned skill yet and it level is zero you cant check with ability level.


BUT this completely useless, for such tasks databasing exists.
DioD is offline   Reply With Quote
Old 07-16-2010, 08:25 PM   #5
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

DioD has a point, if for some reason you need this functionality in a map (which I am not really convinced you do), it would be considerably more efficient and not all that difficult to just create a database of all the hero types and their hero skills used in the map.
__________________

Last edited by Anitarf : 07-16-2010 at 08:26 PM.
Anitarf is offline   Reply With Quote
Old 07-16-2010, 08:38 PM   #6
Tyrande_ma3x
User
 
Tyrande_ma3x's Avatar
 
Join Date: Feb 2009
Posts: 185

Submissions (1)

Tyrande_ma3x is on a distinguished road (12)

Default

> It's clearly explained in the comments.
If it were clear for me, I wouldn't have had to ask for a better explanation. But now I see what it does, thanks for clarifying.
Tyrande_ma3x is offline   Reply With Quote
Old 07-17-2010, 09:02 AM   #7
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Anitarf, check AbilityLearning for a use of this library. Creating a database of all abilities any hero in a map can learn is not really an option when youre not writing code for a specific map.

I could have used ODE. Maybe ill make a version of this that uses ODE.

EDIT: Updated!
__________________

Last edited by Deaod : 07-19-2010 at 08:27 AM.
Deaod is offline   Reply With Quote
Old 04-26-2011, 06:27 AM   #8
Jewel
User
 
Join Date: Apr 2011
Posts: 6

Jewel has little to show at this moment (4)

Default

Why shouldn't the following work?
Collapse Zinc:
//! zinc
library AbilityLearnable requires xebasic {
    
    unit abilityTester = null

    public function IsAbilityLearnable(integer whichAbility) -> boolean {
        if (UnitAddAbility(abilityTester, whichAbility) == true) {
            UnitRemoveAbility(abilityTester, whichAbility);
            return true;
        }
        return false;
    }
    
    function onInit() {
        abilityTester = CreateUnit(XE_DUMMY_UNITID, PLAYER_NEUTRAL_PASSIVE, 0.0, 0.0, 0.0);
        if (GetUnitAbilityLevel(abilityTester, 'Aloc') == 0) { 
            UnitAddAbility(abilityTester, 'Aloc');
        }
        PauseUnit(abilityTester, true);
    }
}
//! endzinc

I haven't tested how UnitAddAbility returns its boolean, but I don't see why it wouldn't work.

But I like your script nonetheless.

Last edited by Jewel : 04-26-2011 at 07:50 AM.
Jewel is offline   Reply With Quote
Old 04-30-2011, 08:42 AM   #9
Deaod
User
 
Join Date: Jan 2007
Posts: 542

Submissions (11)

Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)Deaod is a jewel in the rough (192)

Default

Because UnitAddAbility always returns true (in all cases ive tested, anyway, inlcuding the case youre using).
Also, learnability means that the unit is a hero and can actually learn the ability over the hero learn menu.
__________________
Deaod is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 01:15 AM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services