Warcraft 3 documentation
vJASS & Zinc Documentation
For the latest documentation about how it works vJASS and Zinc language layers for Warcraft III, please follow these links:
Jasshelper documentation - Zinc documentation - WC3 Optimizer documentation

Custom Race System No New Posts Codes & Snippets

Started by
moyack

0 Members and 1 Guest are viewing this topic.

Rating

Average Score - 5 / 5

« Created: December 28, 2017, 07:51:38 AM by moyack »

Custom Race System
on: April 14, 2012, 09:05:36 AM
Category: Execution, System, AI
Language: vJASS
Download Demo Map

Documentation
The purpose of this system is to provide a simple framework for the implementation of custom melee races. It accomplishes this by setting up key components Blizzard should have given since the beginning (at least in a more portable state): the race initialization and victory / defeat conditions.

The approach chosen was one discussed a long time ago, probably on the Power of Corruption boards: letting the user pick their race by means of choosing one of the standard races and setting the handicap to a given value, which would be translated by the system into a particular custom race.


"API"
You create a struct of type CustomRace, with the following constructor:
static method create takes string Name, race Race, real Handicap returns CustomRace

Each of the parameters are described below:
  • string Name  - The name for your race
  • race Race  - The standard race it will be based on (eg, RACE_HUMAN).
  • real Handicap  - The handicap value users need to set so they can pick the race. Accpetable values are 0.5, 0.6, onwards up to 1.0 (which means you can overwrite the standard races too)

You can also create and register a custom race for all handicaps of a single race with:
static method createAll takes string Name, race Race returns CustomRace


You can extend the registration of a custom race to more than one handicap with:
method register takes race Race, real Handicap returns nothing
 
 
 

Once created, you still need to register its townhall, the workers types (you can have more than one type of worker) and hero(es). You can do it by using the following methods:

method setTownHall takes integer TownHallId returns nothing
  • integer TownHallId   - The rawcode of the race's Townhall (eg 'ogre' for Orc Great Hall)

method addWorkerType takes integer WorkerId, integer Priority, integer Quantity returns nothing
  • integer WorkerId   - The rawcode of the race's Worker (eg 'hpea' for Human Peasant)
  • integer Priority  - The priority where the worker type unit will be created. Acceptable values are
    • CustomRace.NEAR_MINE  - Spawns them near the closest mine. Normally all worker units should use this value.
    • CustomRace.NEAR_HALL  - Spawns them near the starting Town Hall unit type. This is included if you want additional workers, in the same vein Ghouls are for the Undead race.
  • integer Quantity   - The amount of initial workers of that type.

method addHeroType takes integer HeroId returns nothing
  • integer HeroId  - The rawcode of the race's hero (eg 'Hpal' for Human Paladin)


If you've got an AI ready to be implemented, then you've already done the hard part. All this takes is a string for the file path and it takes care of the rest. Custom races that were registered but don't have AI scripts cannot be played by the computer. Of course, you can circumvent this (for whatever silly reason) by using this with a string that doesn't refer to an .ai file ("poop" for example).

method setAIScript takes string FilePath returns nothing
  • string FilePath  - The filepath of the .ai script, either in an MPQ or imported to the map


Finally, if your race needs extended initialization beyond the creation of worker units, you can do so by assigning a custom callback function that will run after all the initial units are created; this might be useful to replicate behaviour like the initial Haunted Goldmine the Undead start with, or the Entagled Goldmine for the Night Elves. For that you use the following method:

method setCallback takes CustomRaceCall callback returns nothing
  • CustomRaceCall callback  - A function that matches the CustomRaceCall function interface. More on that below.


The CustomRaceCall function interface is used for the aforementioned callback. It is defined as follows:

function interface CustomRaceCall takes player Player, group Workers, unit Goldmine, unit Townhall, unit Randhero returns nothing
  • player Player  - The owning player of the units passed to the callback function.
  • group Workers  - A unit group with all the created workers created, regardless of type.
  • unit Goldmine  - The nearest Goldmine found at the start location. If there isn't a Goldmine nearby, this parameter is null.
  • unit Townhall  - The townhall created on initialization.
  • unit Randhero  - If the "Use a Random Hero" option is checked before starting the game, this parameter points to the randomly created Hero; otherwise, it will be null.


If you need to get the custom race of a player, GetPlayerCustomRaceName will return a name string of the custom race. Hopefully, you aren't silly enough to name your custom races identically.

function GetPlayerCustomRaceName takes player Player returns string
  • player Player  - The player with a custom race. Players without a custom race associated with them will return an empty string.

 
Demo Map Credits
Playtesters
  • Alevice
  • Anopob
  • cosmicat
  • Dragoon
  • Michael Peppers
Models
  • Callahan  - Mur'gul House
  • DonDustin  - Blue Basilisk Missile
  • JetFangInferno  - Aqua Spike
  • jigrael  - Reptilian Sanctuary, Sea Drake
  • Phoenix - IV  - Naga Town Hall
  • MasterHaosis  - Mur'gul Labor Mill
  • Szythe  - Water Buff
Icons
  • Anachron  - Water Shockwave
  • bigapple90  - Water Tornado
  • Technomancer  - Drown
Scripts
  • Anitarf  - Stack
  • Vexorian  - SimError, Table, TimerUtils


Things to take into consideration
  • If a Goldmine cant be found within default melee lookup radius, all created workers will be located near the Town Hall. this is done accodirng to default melee behaviour.
  • You can now register custom races in their own separate libraries. They should require CustomRaceSystem and must run on initialization.
  • The system now supports AI. And the Naga are a great example of it, if I may say so.
  • If you define two or more custom races with the same base race and handicap, a debug message will be displayed in - game and whichever races were defined beyond the first will not be registered.

Custom Race System
Code: jass
  1. // ==============================================================================
  2.  //  Custom Race System by Archmage Owenalacaster
  3.  // ==============================================================================
  4.  //
  5.  //  Purpose:
  6.  //       - Creates the starting units for custom races and replaces the standard
  7.  //        Melee Initialization trigger. Custom races are selected by race and
  8.  //        handicap.
  9.  //
  10.  //  Usage:
  11.  //       - Register a new custom race with CustomRace.create(name, RACE, handicap)
  12.  //          Handicaps: Valid handicap values are 1.0, 0.9, 0.8, 0.7, 0.6 and 0.5.
  13.  //       - Register a new custom race for all handicaps of a single race with
  14.  //        CustomRace.createAll(name, RACE)
  15.  //       - Extend the registration of a race with c.register(RACE, handicap)
  16.  //       - Set the townhall type with c.setTownHall(unitid)
  17.  //       - Add a new worker type with c.addWorkerType(unitid, priority, qty)
  18.  //          Priorities: c.NEAR_MINE spawns workers near the mine, where workers
  19.  //                        typically spawn.
  20.  //                      c.NEAR_HALL spawns workers near the town hall, where
  21.  //                        Ghouls spawn.
  22.  //       - Add a random hero type with c.addHeroType(unitid)
  23.  //       - Set the ai script used by computer players with c.setAIScript(stringpath)
  24.  //       - Set a callback function with c.setCallback(CustomRaceCall.function)
  25.  //          Callbacks: The callback is executed after all the starting units for a
  26.  //                     player are created, and its purpose is to provide enhanced
  27.  //                     initial behaviour for a race. A good example of this with the
  28.  //                     standard races would be the Undead Goldmine Haunting and
  29.  //                     Night Elves Goldmine Entangling.
  30.  //                     The callback function passes as arguments all the units
  31.  //                     generated in addition to the nearest goldmine detected.
  32.  //                     Please note that if a random hero is not created, the last
  33.  //                     argument will have a null value, so always do a check.
  34.  //        - Get a player's custom race name string with GetPlayerCustomRaceName(player)
  35.  //
  36.  //  Notes:
  37.  //       - Supports a maximum of 24 custom races.
  38.  //       - Maximum for worker and hero types are configurable.
  39.  //
  40.  //  Requirements:
  41.  //       - JassHelper version 0.9.E.0 or newer (older versions may still work).
  42.  //
  43.  //  Installation:
  44.  //       - Create a new trigger called CustomRaceSystem.
  45.  //       - Convert it to custom text and replace all the code with this code.
  46.  //
  47.  //  Special Thanks:
  48.  //       - Alevice:  He practically co - wrote the code.
  49.  //       - cosmicat: His formula for circular unit formation.
  50.  //                  Co - developing the single - array registry.
  51.  //
  52.  // ==============================================================================
  53.  
  54. library CustomRaceSystem initializer Init
  55.    
  56.  // ===========================================================================
  57.  //                                CONFIGURATION SECTION
  58.  // ===========================================================================
  59.     globals
  60.          // Unit Type Constants
  61.         private constant integer MAX_WORKERTYPES = 4
  62.         private constant integer MAX_HEROTYPES = 4
  63.     endglobals
  64.  // ===========================================================================
  65.  //                                END CONFIGURATION SECTION
  66.  // ===========================================================================
  67.  
  68.     function interface CustomRaceCall takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
  69.    
  70.     private function r2S takes race r returns string
  71.         if r == RACE_HUMAN then
  72.             return "Human"
  73.         elseif r == RACE_ORC then
  74.             return "Orc"
  75.         elseif r == RACE_UNDEAD then
  76.             return "Undead"
  77.         elseif r == RACE_NIGHTELF then
  78.             return "Night Elf"
  79.         endif
  80.         return "Unknown"
  81.     endfunction
  82.    
  83.     private function r2I takes race r returns integer
  84.         if r == RACE_HUMAN then
  85.             return 1
  86.         elseif r == RACE_ORC then
  87.             return 2
  88.         elseif r == RACE_UNDEAD then
  89.             return 3
  90.         elseif r == RACE_NIGHTELF then
  91.             return 4
  92.         endif
  93.         return 5
  94.     endfunction
  95.    
  96.     globals
  97.          // Victory Defeat Variables
  98.         private string array KEY_STRUCTURE
  99.         private integer KEY_STRUCTURE_COUNT = 0
  100.     endglobals
  101.    
  102.  // ===========================================================================
  103.  //                                STRUCT DATA
  104.  // ===========================================================================
  105.     private keyword createStartingUnits
  106.    
  107.     struct CustomRace
  108.         string name
  109.        
  110.          // Town Hall Variable
  111.         integer townhallType = 0
  112.        // string  townhallName
  113.          // Town Hall name is not currently supported.
  114.        
  115.          // Worker Variables
  116.         integer totalWorkerTypes = 0
  117.         integer array workerType[MAX_WORKERTYPES]
  118.         integer array workerPriority[MAX_WORKERTYPES]
  119.         integer array workerQty[MAX_WORKERTYPES]
  120.        
  121.          // Random Hero Variables
  122.         integer totalHeroTypes = 0
  123.         integer array heroType[MAX_HEROTYPES]
  124.        
  125.          // AI Script Directory String Variable
  126.         string aiscript = ""
  127.        
  128.          // Callback Variable
  129.         private CustomRaceCall c
  130.        
  131.          // Registry Variable
  132.         static integer array REGISTRY
  133.        
  134.          // Spawn Priority Variables
  135.         static integer NEAR_MINE     = 0
  136.         static integer NEAR_HALL     = 1
  137.        
  138.         static method get takes race r, real h returns CustomRace
  139.             return CustomRace(.REGISTRY[((r2I(r) - 1) * 6) + (10 - R2I(h * 10.))])
  140.         endmethod
  141.        
  142.         method register takes race r, real h returns boolean
  143.             local CustomRace c = CustomRace.get(r, h)
  144.             if c != 0 then
  145.                 debug call BJDebugMsg("|cffff0000Registration of " + .name + " failed due to conflict with " + c.name + " registered for " + r2S(r) + " race Handicap " + R2S(h))
  146.                 return false
  147.             endif
  148.             set .REGISTRY[((r2I(r) - 1) * 6) + (10 - R2I(h * 10.))] = integer(this)
  149.             return true
  150.         endmethod
  151.        
  152.         static method create takes string name, race r, real h returns CustomRace
  153.             local CustomRace c = CustomRace.allocate()
  154.             set c.name = name
  155.             if not c.register(r, h) then
  156.                 call c.destroy()
  157.                 return 0
  158.             endif
  159.             return c
  160.         endmethod
  161.        
  162.         static method createAll takes string name, race r returns CustomRace
  163.             local CustomRace c = CustomRace.allocate()
  164.             set c.name = name
  165.             if not c.register(r, 1.0) and not c.register(r, 0.9) and not c.register(r, 0.8) and not c.register(r, 0.7) and not c.register(r, 0.6) and not c.register(r, 0.5) then
  166.                 call c.destroy()
  167.                 return 0
  168.             endif
  169.             return c
  170.         endmethod
  171.        
  172.         method setTownHall takes integer hallid returns nothing
  173.             set .townhallType = hallid
  174.             set KEY_STRUCTURE[KEY_STRUCTURE_COUNT] = UnitId2String(hallid)
  175.             set KEY_STRUCTURE_COUNT = KEY_STRUCTURE_COUNT + 1
  176.         endmethod
  177.        
  178.         method addWorkerType takes integer workerid, integer priority, integer quantity returns nothing
  179.             set .workerType[.totalWorkerTypes] = workerid
  180.             set .workerPriority[.totalWorkerTypes] = priority
  181.             set .workerQty[.totalWorkerTypes] = quantity
  182.             set .totalWorkerTypes = .totalWorkerTypes + 1
  183.         endmethod
  184.        
  185.         method addHeroType takes integer heroid returns nothing
  186.             local integer i = 0
  187.             set .heroType[.totalHeroTypes] = heroid
  188.             set .totalHeroTypes = .totalHeroTypes + 1
  189.             loop
  190.                 call SetPlayerTechMaxAllowed(Player(i), heroid, 1)
  191.                 set i = i + 1
  192.                 exitwhen i == bj_MAX_PLAYERS
  193.             endloop
  194.         endmethod
  195.        
  196.         private method getRandomHeroType takes nothing returns integer
  197.             local integer randomindex = GetRandomInt(0, .totalHeroTypes - 1)
  198.             return .heroType[randomindex]
  199.         endmethod
  200.        
  201.         method setAIScript takes string s returns nothing
  202.             set .aiscript = s
  203.         endmethod
  204.        
  205.         method setCallback takes CustomRaceCall callb returns nothing
  206.             set .c = callb
  207.         endmethod
  208.        
  209.         private method createRandomHero takes player p, location loc returns unit
  210.             local unit h = CreateUnitAtLoc(p, .getRandomHeroType(), loc, bj_UNIT_FACING)
  211.             if bj_meleeGrantHeroItems then
  212.                 call MeleeGrantItemsToHero(h)
  213.             endif
  214.             return h
  215.         endmethod
  216.        
  217.         method createStartingUnits takes player p returns nothing
  218.             local location   startLoc        = GetPlayerStartLocationLoc(p)
  219.             local location   nearMineLoc     = startLoc
  220.             local location   nearTownLoc     = startLoc
  221.             local location   spawnLoc        = startLoc
  222.             local location   heroLoc         = startLoc
  223.             local unit       nearestMine     = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
  224.             local unit       myTownhall      = null
  225.             local unit       myRandHero      = null
  226.             local group      workerGroup     = CreateGroup()
  227.             local integer    workertypeindex = 0
  228.             local integer    workerqty       = 0
  229.             local integer    spawnPriority   = 0
  230.             if nearestMine != null then
  231.                 set nearMineLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine), startLoc, 320, 0)
  232.                 set nearTownLoc = MeleeGetProjectedLoc(startLoc, GetUnitLoc(nearestMine), 288, 0)
  233.                 set heroLoc     = MeleeGetProjectedLoc(GetUnitLoc(nearestMine), startLoc, 384, 45)
  234.             endif
  235.             set myTownhall = CreateUnitAtLoc(p, .townhallType, startLoc, bj_UNIT_FACING)
  236.             loop
  237.                 exitwhen workertypeindex == .totalWorkerTypes
  238.                     set spawnPriority = .workerPriority[workertypeindex]
  239.                     if (spawnPriority==.NEAR_HALL) then
  240.                         set spawnLoc = nearTownLoc
  241.                     elseif(spawnPriority==.NEAR_MINE) then
  242.                         set spawnLoc = nearMineLoc
  243.                     endif
  244.                     loop
  245.                         call GroupAddUnit(workerGroup, CreateUnitAtLoc(p,.workerType[workertypeindex],PolarProjectionBJ(spawnLoc,65,(I2R(workerqty) * (360.00 / I2R(.workerQty[workertypeindex])))  +  90),bj_UNIT_FACING))
  246.                         set workerqty = workerqty  +  1
  247.                         exitwhen workerqty >= .workerQty[workertypeindex]
  248.                     endloop
  249.                     call RemoveLocation(spawnLoc)
  250.                     set workerqty = 0
  251.                 set workertypeindex = workertypeindex + 1
  252.             endloop
  253.             if (IsMapFlagSet(MAP_RANDOM_HERO) and .totalHeroTypes>0 ) then
  254.                 set myRandHero = .createRandomHero(p,heroLoc)
  255.             else
  256.             endif
  257.             if(.c!=0) then
  258.                 call .c.evaluate(p,workerGroup,nearestMine,myTownhall,myRandHero)
  259.             else
  260.                 call DestroyGroup(workerGroup)
  261.             endif
  262.             if nearMineLoc != startLoc then
  263.                 call RemoveLocation(nearMineLoc)
  264.                 call RemoveLocation(nearTownLoc)
  265.                 call RemoveLocation(heroLoc)
  266.             endif
  267.             call RemoveLocation(startLoc)
  268.             set startLoc    = null
  269.             set nearMineLoc = null
  270.             set nearTownLoc = null
  271.             set spawnLoc    = null
  272.             set heroLoc     = null
  273.             set nearestMine = null
  274.             set myTownhall  = null
  275.             set myRandHero  = null
  276.             set workerGroup = null
  277.         endmethod
  278.      endstruct
  279.      
  280.      globals
  281.         private string array PLAYER_RACE
  282.      endglobals
  283.      
  284.      function GetPlayerCustomRaceName takes player p returns string
  285.         return PLAYER_RACE[GetPlayerId(p)]
  286.      endfunction
  287.    
  288. //===========================================================================
  289. //                         UNIT CREATION SECTION
  290. //===========================================================================
  291.     private function CreateStartingUnitsForAllPlayers takes nothing returns nothing
  292.         local integer    index = 0
  293.         local player     indexPlayer
  294.         local race       playerRace
  295.         local CustomRace c
  296.         loop
  297.             set indexPlayer = Player(index)
  298.             if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
  299.                 set playerRace = GetPlayerRace(indexPlayer)
  300.                 set c = CustomRace.get(playerRace,GetPlayerHandicap(indexPlayer) + 0.01)
  301.                 if (GetPlayerController(indexPlayer) == MAP_CONTROL_USER or (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER and c.aiscript != "" )) and c != 0 then
  302.                     set PLAYER_RACE[index] = c.name
  303.                     call c.createStartingUnits(indexPlayer)
  304.                 elseif playerRace == RACE_HUMAN then
  305.                     call MeleeStartingUnitsHuman(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
  306.                 elseif playerRace == RACE_ORC then
  307.                     call MeleeStartingUnitsOrc(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
  308.                 elseif playerRace == RACE_NIGHTELF then
  309.                     call MeleeStartingUnitsNightElf(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
  310.                 elseif playerRace == RACE_UNDEAD then
  311.                     call MeleeStartingUnitsUndead(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
  312.                 else
  313.                     call MeleeStartingUnitsUnknownRace(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
  314.                 endif
  315.             endif
  316.             set index = index  +  1
  317.             exitwhen index == bj_MAX_PLAYERS
  318.         endloop
  319.     endfunction
  320.    
  321. //===========================================================================
  322. //                         CUSTOM MELEE AI SECTION
  323. //===========================================================================
  324.     private function CustomMeleeStartingAI takes nothing returns nothing
  325.         local integer index = 0
  326.         local player  indexPlayer
  327.         local race    indexRace
  328.         local CustomRace c
  329.         loop
  330.             set indexPlayer = Player(index)
  331.             if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
  332.                 set indexRace = GetPlayerRace(indexPlayer)
  333.                 set c = CustomRace.get(indexRace,GetPlayerHandicap(indexPlayer) + 0.01)
  334.                 call SetPlayerHandicap(indexPlayer,1.0)
  335.                 if (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER) then
  336.                     // Run a race-specific melee AI script.
  337.                     if c != 0 and c.aiscript != "" then
  338.                         call StartMeleeAI(indexPlayer, c.aiscript)
  339.                     elseif (indexRace == RACE_HUMAN) then
  340.                         call PickMeleeAI(indexPlayer, "human.ai", null, null)
  341.                     elseif (indexRace == RACE_ORC) then
  342.                         call PickMeleeAI(indexPlayer, "orc.ai", null, null)
  343.                     elseif (indexRace == RACE_UNDEAD) then
  344.                         call PickMeleeAI(indexPlayer, "undead.ai", null, null)
  345.                         call RecycleGuardPosition(bj_ghoul[index])
  346.                     elseif (indexRace == RACE_NIGHTELF) then
  347.                         call PickMeleeAI(indexPlayer, "elf.ai", null, null)
  348.                     else
  349.                         // Unrecognized race.
  350.                     endif
  351.                     call ShareEverythingWithTeamAI(indexPlayer)
  352.                 endif
  353.             endif
  354.  
  355.             set index = index  +  1
  356.             exitwhen index == bj_MAX_PLAYERS
  357.         endloop
  358.     endfunction   
  359.  
  360. //===========================================================================
  361. //                         VICTORY DEFEAT SECTION
  362. //===========================================================================
  363.     private function CustomGetAllyKeyStructureCount takes player whichPlayer returns integer
  364.         local integer    i           = 0
  365.         local integer    keyStructs  = 0
  366.         local integer    playerIndex = 0
  367.         local player     indexPlayer
  368.         loop
  369.             set indexPlayer = Player(playerIndex)
  370.             if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
  371.                 set keyStructs = keyStructs  +  GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true)
  372.                 set keyStructs = keyStructs  +  GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true)
  373.                 set keyStructs = keyStructs  +  GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true)
  374.                 set keyStructs = keyStructs  +  GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true)
  375.                 loop
  376.                     set keyStructs = keyStructs  +  GetPlayerTypedUnitCount(indexPlayer, KEY_STRUCTURE[i], true, true)
  377.                     set i = i + 1
  378.                     exitwhen i == KEY_STRUCTURE_COUNT
  379.                 endloop
  380.             endif
  381.             set playerIndex = playerIndex  +  1
  382.             exitwhen playerIndex == bj_MAX_PLAYERS
  383.         endloop
  384.         return keyStructs
  385.     endfunction
  386.  
  387.     private function CustomPlayerIsCrippled takes player whichPlayer returns boolean
  388.         local integer allyStructures    = MeleeGetAllyStructureCount(whichPlayer)
  389.         local integer allyKeyStructures = CustomGetAllyKeyStructureCount(whichPlayer)
  390.         return (allyStructures > 0) and (allyKeyStructures <= 0)
  391.     endfunction
  392.  
  393.     private function CustomCheckForCrippledPlayers takes nothing returns nothing
  394.         local integer    playerIndex
  395.         local player     indexPlayer
  396.         local boolean    isNowCrippled
  397.         if bj_finishSoonAllExposed then
  398.             return
  399.         endif
  400.         set playerIndex = 0
  401.         loop
  402.             set indexPlayer = Player(playerIndex)
  403.             set isNowCrippled = CustomPlayerIsCrippled(indexPlayer)
  404.             if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
  405.                 set bj_playerIsCrippled[playerIndex] = true
  406.                 call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
  407.                 if (GetLocalPlayer() == indexPlayer) then
  408.                     call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
  409.                     call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_WARNING_HUMAN"))
  410.                 endif
  411.             elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
  412.                 set bj_playerIsCrippled[playerIndex] = false
  413.                 call PauseTimer(bj_crippledTimer[playerIndex])
  414.                 if (GetLocalPlayer() == indexPlayer) then
  415.                     call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
  416.                     if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
  417.                         if (bj_playerIsExposed[playerIndex]) then
  418.                             call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
  419.                         else
  420.                             call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
  421.                         endif
  422.                     endif
  423.                 endif
  424.                 call MeleeExposePlayer(indexPlayer, false)
  425.             endif
  426.             set playerIndex = playerIndex  +  1
  427.             exitwhen playerIndex == bj_MAX_PLAYERS
  428.         endloop
  429.     endfunction
  430.  
  431.     private function CustomInitVictoryDefeat takes nothing returns nothing
  432.         local trigger    checker = CreateTrigger()
  433.         local trigger    trig
  434.         local integer    index
  435.         local player     indexPlayer
  436.         call TriggerAddAction(checker, function CustomCheckForCrippledPlayers)
  437.         set trig = CreateTrigger()
  438.         call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)
  439.         set trig = CreateTrigger()
  440.         call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)
  441.         set index = 0
  442.         loop
  443.             set indexPlayer = Player(index)
  444.             if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
  445.                 set bj_meleeDefeated[index] = false
  446.                 set bj_meleeVictoried[index] = false
  447.                 set bj_playerIsCrippled[index] = false
  448.                 set bj_playerIsExposed[index] = false
  449.                 set bj_crippledTimer[index] = CreateTimer()
  450.                 set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
  451.                 call TimerDialogSetTitle(bj_crippledTimerWindows[index], MeleeGetCrippledTimerMessage(indexPlayer))
  452.                 call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
  453.                 call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_DEATH, null)
  454.                 call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
  455.                 call TriggerRegisterPlayerAllianceChange(checker, indexPlayer, ALLIANCE_PASSIVE)
  456.                 call TriggerRegisterPlayerStateEvent(checker, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
  457.                 set trig = CreateTrigger()
  458.                 call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
  459.                 call TriggerAddAction(trig, function MeleeTriggerActionPlayerDefeated)
  460.                 set trig = CreateTrigger()
  461.                 call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
  462.                 call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
  463.              else
  464.                 set bj_meleeDefeated[index] = true
  465.                 set bj_meleeVictoried[index] = false
  466.                 if (IsPlayerObserver(indexPlayer)) then
  467.                     set trig = CreateTrigger()
  468.                     call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
  469.                     call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
  470.                 endif
  471.             endif
  472.             set index = index  +  1
  473.             exitwhen index == bj_MAX_PLAYERS
  474.         endloop
  475.         call TimerStart(CreateTimer(), 2.0, false, function CustomCheckForCrippledPlayers)
  476.     endfunction
  477.    
  478.     private function TimerAction takes nothing returns nothing
  479.         call MeleeStartingHeroLimit()
  480.         call MeleeGrantHeroItems()
  481.         call MeleeStartingResources()
  482.         call MeleeClearExcessUnits()
  483.         call CreateStartingUnitsForAllPlayers()
  484.         call CustomMeleeStartingAI()
  485.         call CustomInitVictoryDefeat()
  486.         call DestroyTimer(GetExpiredTimer())
  487.     endfunction
  488.    
  489.     private function Init takes nothing returns nothing
  490.         call TimerStart(CreateTimer(),0,false,function TimerAction)
  491.     endfunction
  492.    
  493. endlibrary   

Here is an example of implementation from the demo map. Naga are a playable race for Night Elf, Handicap 90%.

Custom Race Setup
Code: jass
  1. //====================================================================
  2. //                           HUMAN SETUP
  3. //====================================================================
  4.  
  5. library HumanSetup initializer Init requires CustomRaceSystem
  6.    
  7.     private function Init takes nothing returns nothing
  8.         local CustomRace c = CustomRace.create("Human",RACE_HUMAN,1.0)
  9.         call c.setTownHall('htow')                  // Town Hall
  10.         call c.addWorkerType('hpea',c.NEAR_MINE,5)  // Peasant
  11.         call c.addHeroType('Hpal')                  // Paladin
  12.         call c.addHeroType('Hamg')                  // Archmage
  13.         call c.addHeroType('Hmkg')                  // Mountain King
  14.         call c.addHeroType('Hblm')                  // Blood Mage
  15.         call c.setAIScript("human.ai")
  16.     endfunction
  17.    
  18. endlibrary
  19.  
  20. //====================================================================
  21. //                            ORC SETUP
  22. //====================================================================
  23.  
  24. library OrcSetup initializer Init requires CustomRaceSystem
  25.    
  26.     private function Init takes nothing returns nothing
  27.         local CustomRace c = CustomRace.create("Orc",RACE_ORC,1.0)
  28.         call c.setTownHall('ogre')                  // Great Hall
  29.         call c.addWorkerType('opeo',c.NEAR_MINE,5)  // Peon
  30.         call c.addHeroType('Obla')                  // Blademaster
  31.         call c.addHeroType('Ofar')                  // Far Seer
  32.         call c.addHeroType('Otch')                  // Tauren Chieftain
  33.         call c.addHeroType('Oshd')                  // Shadow Hunter
  34.         call c.setAIScript("orc.ai")
  35.     endfunction
  36.    
  37. endlibrary
  38.  
  39. //====================================================================
  40. //                          UNDEAD SETUP
  41. //====================================================================
  42.  
  43. library UndeadSetup initializer Init requires CustomRaceSystem
  44.    
  45.     private function WorkerHideToggle takes nothing returns nothing
  46.     endfunction
  47.    
  48.     private function HauntGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
  49.         call ForGroup(workers,function WorkerHideToggle)
  50.         call BlightGoldMineForPlayerBJ(goldmine,play)
  51.         call ForGroup(workers,function WorkerHideToggle)
  52.         call DestroyGroup(workers)
  53.     endfunction
  54.    
  55.     private function Init takes nothing returns nothing
  56.         local CustomRace c = CustomRace.create("Undead",RACE_UNDEAD,1.0)
  57.         call c.setTownHall('unpl')                  // Necropolis
  58.         call c.addWorkerType('uaco',c.NEAR_MINE,3)  // Acolyte
  59.         call c.addWorkerType('ugho',c.NEAR_HALL,1)  // Ghoul
  60.         call c.addHeroType('Udea')                  // Death Knight
  61.         call c.addHeroType('Ulic')                  // Lich
  62.         call c.addHeroType('Udre')                  // Dreadlord
  63.         call c.addHeroType('Ucrl')                  // Crypt Lord
  64.         call c.setCallback(CustomRaceCall.HauntGoldMine)
  65.         call c.setAIScript("undead.ai")
  66.     endfunction
  67.    
  68. endlibrary
  69.  
  70. //====================================================================
  71. //                          NIGHT ELF SETUP
  72. //====================================================================
  73.  
  74. library NightElfSetup initializer Init requires CustomRaceSystem
  75.    
  76.     private function EntangleGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing
  77.         call SetUnitPosition(townhall,GetUnitX(goldmine),GetUnitY(goldmine))
  78.         call IssueTargetOrder(townhall, "entangleinstant", goldmine)
  79.         call DestroyGroup(workers)
  80.     endfunction
  81.    
  82.     private function Init takes nothing returns nothing
  83.         local CustomRace c = CustomRace.create("Night Elf",RACE_NIGHTELF,1.0)
  84.         call c.setTownHall('etol')                  // Tree of Life
  85.         call c.addWorkerType('ewsp',c.NEAR_MINE,5)  // Wisp
  86.         call c.addHeroType('Ekee')                  // Keeper of the Grove
  87.         call c.addHeroType('Emoo')                  // Priestess of the Moon
  88.         call c.addHeroType('Edem')                  // Demon Hunter
  89.         call c.addHeroType('Ewar')                  // Warden
  90.         call c.setCallback(CustomRaceCall.EntangleGoldMine)
  91.         call c.setAIScript("elf.ai")
  92.     endfunction
  93.    
  94. endlibrary
  95.  
  96. //====================================================================
  97. //                           NAGA SETUP
  98. //====================================================================
  99.  
  100. library NagaSetup initializer Init requires CustomRaceSystem
  101.    
  102.     private function Init takes nothing returns nothing
  103.         local CustomRace c = CustomRace.create("Naga",RACE_NIGHTELF,0.9)
  104.         call c.setTownHall('nntt')                  // Temple of Tides
  105.         call c.addWorkerType('nmpe',c.NEAR_MINE,5)  // Murgul Slave
  106.         call c.addHeroType('Hvsh')                  // Lady Vashj
  107.         call c.setAIScript("naga.ai")
  108.     endfunction
  109.    
  110. endlibrary
« Last Edit: December 28, 2017, 11:01:36 AM by moyack »



 

Started by cohadar

Replies: 0
Views: 2040
Codes & Snippets

Started by ashujon

Replies: 0
Views: 2971
Warcraft III Spells and Systems

Started by azlier

Replies: 0
Views: 1787
Codes & Snippets

Started by Magtheridon96

Replies: 0
Views: 2022
Codes & Snippets

Started by moyack

Replies: 6
Views: 18995
Codes & Snippets
Vivir aprendiendo.co - A place for learning stuff, in Spanish   Chaos Realm - The world of Game modders and wc3 addicts   Diplo, a gaming community   Power of Corruption, an altered melee featuring Naga and Demon. Play it now!!!   WC3JASS.com - The JASS Vault + vJASS and Zinc   Jetcraft - A Starcraft II mod   WormTastic Clan (wTc)   Warcraft RESOURCES Reforged: Modelos, mapas, proyectos y mas...