HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[PROOF-READ] Custom Race System

04-15-2009, 11:20 PM#1
Archmage Owenalacaster
I need some proofreading on this before I move to implementation and submission. This system replaces standard Melee Initialization triggers, supports the starting unit creation for custom races, recognizes custom town halls for crippled-player revealing timers, and otherwise intends to emulate standard melee.

It requires no outside systems and is self-contained.
Included are examples of registration for the 4 standard races and 4 custom races.

The code is so long, I must divide it into two posts.
Collapse CustomRaceSystem Setup Library:
//==============================================================================
//  Custom Race System by Archmage Owenalacaster
//==============================================================================
//
//  Purpose:
//      - Creates the starting units for custom races and replaces the standard
//        Melee Initialization trigger.
//
//  Usage:
//      - Register a new custom race with customRace.register(NAME, RACE, HANDICAP)
//      - Set the townhall type with c.addTownHall(unitid)
//      - Add a new worker type with c.addWorkerType(unitid, priority, qty)
//          Priorities: c.NEAR_MINE spawns workers near the mine.
//                      c.NEAR_HALL spawns workers near the town hall.
//      - Add a random hero type with c.addHeroType(unitid)
//      - Set a callback function with c.setCallback(CustomRaceCall.function)
//          Callbacks: The callback is executed after all the starting units for a
//                     player are created, and its purpose is to provide enhanced
//                     initial behaviour for a race. A good example of this with the
//                     standard races would be the Undead Goldmine Haunting and
//                     Night Elves Goldmine Entangling.
//                     The callback function passes as arguments all the units
//                     generated in addition to the nearest goldmine detected.
//                     Please note that if a random hero is not created, the last
//                     argument will have a null value, so always do a check.
//
//  Notes:
//      - Supports a maximum of 24 custom races.
//      - Each race may have a maximum of 4 worker types and 4 hero types.
//
//  Requirements:
//      - JassHelper version 0.9.E.0 or newer (older versions may still work).
//
//  Installation:
//      - Create a new trigger called CustomRaceSystem.
//      - Convert it to custom text and replace all the code with this code.
//
//  Special Thanks:
//      - Alevice:  He practically co-wrote the code.
//      - cosmicat: His formula for circular unit formation.
//                  Co-developing the single-array registry.
//
//==============================================================================

library_once CustomRaceSetup initializer Init requires CustomRaceSystem
//===========================================================================
//                         START CALIBRATION SECTION
//===========================================================================
    
    private function SetTechAvail takes integer techid, boolean available, player p returns nothing
        local integer i     = 0
        local integer avail = 0
        if available then
            set avail = -1
        endif
        if p == null then
            loop
                call SetPlayerTechMaxAllowed(Player(i),techid,avail)
                set i = i+1
                exitwhen i == bj_MAX_PLAYERS
            endloop
        else
            call SetPlayerTechMaxAllowed(p,techid,avail)
        endif
    endfunction
    
    private function ReplaceTech takes integer oldtechid, integer newtechid, player p returns nothing
        call SetTechAvail(oldtechid,false,p)
        call SetTechAvail(newtechid,true,p)
    endfunction
    
    //=======================
    //  Lordaeron Remnants
    //=======================
    private function SetRemnantTech takes group workers, unit goldmine, unit townhall, unit randhero returns nothing
        local player p = GetOwningPlayer(townhall)
        call ReplaceTech('hbar','hb00',p) // Barracks / Remnant Barracks
        call ReplaceTech('halt','hb01',p) // Altar of Kings / Remnant Altar of Kings
        call ReplaceTech('hars','hb02',p) // Arcane Sanctum / Remnant Arcane Sanctum
        call ReplaceTech('hgra','hb03',p) // Gryphon Aviary / Remnant Gryphon Aviary
        call DestroyGroup(workers)
    endfunction
    
    //=======================
    //  Undead
    //=======================
    private function HauntGoldMine takes group workers, unit goldmine, unit townhall, unit randhero returns nothing
        call BlightGoldMineForPlayerBJ(goldmine,GetOwningPlayer(townhall))
        call DestroyGroup(workers)
    endfunction
    
    //=======================
    //  Night Elf
    //=======================
    private function EntangleGoldMine takes group workers, unit goldmine, unit townhall, unit randhero returns nothing
        call SetUnitPosition(townhall,GetUnitX(goldmine),GetUnitY(goldmine))
        call IssueTargetOrder(townhall, "entangleinstant", goldmine)
        call DestroyGroup(workers)
    endfunction
    
    private function RegisterCustomRaces takes nothing returns nothing
        local CustomRace c = 0
        // Human Race
        set c = CustomRace.create("Human",RACE_HUMAN,1.0)
        call c.setTownHall('htow')                  // Town Hall
        call c.addWorkerType('hpea',c.NEAR_MINE,5)  // Peasant
        call c.addHeroType('Hpal')                  // Paladin
        call c.addHeroType('Hamg')                  // Archmage
        call c.addHeroType('Hmkg')                  // Mountain King
        call c.addHeroType('Hblm')                  // Blood Mage
        // Orc Race
        set c = CustomRace.create("Orc",RACE_ORC,1.0)
        call c.setTownHall('ogre')                  // Great Hall
        call c.addWorkerType('opeo',c.NEAR_MINE,5)  // Peon
        call c.addHeroType('Obla')                  // Blademaster
        call c.addHeroType('Ofar')                  // Far Seer
        call c.addHeroType('Otch')                  // Tauren Chieftain
        call c.addHeroType('Oshd')                  // Shadow Hunter
        // Undead Race
        set c = CustomRace.create("Undead",RACE_UNDEAD,1.0)
        call c.setTownHall('unpl')                  // Necropolis
        call c.addWorkerType('uaco',c.NEAR_MINE,3)  // Acolyte
        call c.addWorkerType('ugho',c.NEAR_HALL,1)  // Ghoul
        call c.addHeroType('Udea')                  // Death Knight
        call c.addHeroType('Ulic')                  // Lich
        call c.addHeroType('Udre')                  // Dreadlord
        call c.addHeroType('Ucrl')                  // Crypt Lord
        call c.setCallback(CustomRaceCall.HauntGoldMine)
        // Night Elf Race
        set c = CustomRace.create("Night Elf",RACE_NIGHTELF,1.0)
        call c.setTownHall('etol')                  // Tree of Life
        call c.addWorkerType('ewsp',c.NEAR_MINE,5)  // Wisp
        call c.addHeroType('Ekee')                  // Keeper of the Grove
        call c.addHeroType('Emoo')                  // Priestess of the Moon
        call c.addHeroType('Edem')                  // Demon Hunter
        call c.addHeroType('Ewar')                  // Warden
        call c.setCallback(CustomRaceCall.EntangleGoldMine)
        // Lordaeron Remnants
        set c = CustomRace.create("Lordaeron Remnants",RACE_HUMAN,0.9)
        call c.setTownHall('htow')                  // Town Hall
        call c.addWorkerType('hpea',c.NEAR_MINE,5)  // Peasant
        call c.addHeroType('Hlgr')                  // Lord Garithos
        call c.setCallback(CustomRaceCall.SetRemnantTech)
            // Disabled Tech
            call SetTechAvail('hb00',false,null)        // Remnant Barracks
            call SetTechAvail('hb01',false,null)        // Remnant Altar of Kings
            call SetTechAvail('hb02',false,null)        // Remnant Arcane Sanctum
            call SetTechAvail('hb03',false,null)        // Remnant Gryphon Aviary
        // Draenei Race
        set c = CustomRace.create("Draenei",RACE_ORC,0.9)
        call c.setTownHall('ndh2')                  // Draenei Haven
        call c.addWorkerType('ndrl',c.NEAR_MINE,5)  // Draenei Laborer
        call c.addHeroType('Naka')                  // Akama
        // Demon Race
        set c = CustomRace.create("Demon",RACE_UNDEAD,0.9)
        call c.setTownHall('ndmg')                  // Demon Gate
        call c.addWorkerType('nchw',c.NEAR_MINE,5)  // Fel Orc Warlock
        call c.addHeroType('Uwar')                  // Archimonde
        call c.setCallback(CustomRaceCall.HauntGoldMine)
        set c = CustomRace.create("Naga",RACE_NIGHTELF,0.9)
        call c.setTownHall('nntt')                  // Temple of Tides
        call c.addWorkerType('nmpe',c.NEAR_MINE,5)  // Murgul Slave
        call c.addHeroType('Hvsh')                  // Lady Vashj
    endfunction
    
//===========================================================================
//                       END OF CALIBRATION SECTION
//===========================================================================
    private function Init takes nothing returns nothing
        call RegisterCustomRaces()
        call SetFloatGameState(GAME_STATE_TIME_OF_DAY, bj_MELEE_STARTING_TOD)
        call MeleeStartingHeroLimit()
        call MeleeGrantHeroItems()
        call MeleeStartingResources()
        call MeleeClearExcessUnits()
        call CreateStartingUnitsForAllPlayers()
        call MeleeStartingAI()
        call CustomInitVictoryDefeat()
    endfunction
    
endlibrary
04-15-2009, 11:21 PM#2
Archmage Owenalacaster
Collapse CustomRaceSystem Core Library:
library CustomRaceSystem

    function interface CustomRaceCall takes group workers, unit goldmine, unit townhall, unit randhero returns nothing
    
    private function r2S takes race r returns string
        if r == RACE_HUMAN then
            return "Human"
        elseif r == RACE_ORC then
            return "Orc"
        elseif r == RACE_UNDEAD then
            return "Undead"
        elseif r == RACE_NIGHTELF then
            return "Night Elf"
        endif
        return "Unknown"
    endfunction
    
    private function r2I takes race r returns integer
        return r
        return 0
    endfunction
    
    globals
        // Unit Type Constants
        private constant integer MAX_WORKERTYPES = 4
        private constant integer MAX_HEROTYPES = 4
        // Victory Defeat Constants
        private string array KEY_STRUCTURE
        private integer KEY_STRUCTURE_COUNT = 0
    endglobals
    
//===========================================================================
//                                STRUCT DATA
//===========================================================================
    struct CustomRace
        string name
        
        // Town Hall Variables
        integer townhallType
      //string  townhallName
        
        // Worker Variables
        integer totalWorkerTypes
        integer array workerType[MAX_WORKERTYPES]
        integer array workerPriority[MAX_WORKERTYPES]
        integer array workerQty[MAX_WORKERTYPES]
        
        // Random Hero Variables
        integer totalHeroTypes
        integer array heroType[MAX_HEROTYPES]
        
        // Callback Variables
        private CustomRaceCall c
        
        // Registry Variable
        static integer array REGISTRY
        
        // Spawn Priority Variables
        static integer NEAR_MINE     = 0
        static integer NEAR_HALL     = 1
      //static integer NEAR_TREES    = 2
        
        static method get takes race r, real h returns CustomRace
            return CustomRace(.REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))])
        endmethod
        
        static method create takes string name, race r, real h returns CustomRace
            local CustomRace c = CustomRace.get(r,h)
            if c != 0 then
                debug call BJDebugMsg("|cffff0000Registration of "+name+" failed due to conflict with "+c.name+" registered for "+r2S(r)+" race Handicap "+R2S(h))
                return 0
            endif
            set c = CustomRace.allocate()
            set c.name = name
            set .REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))] = integer(c)
            return c
        endmethod
        
        method setTownHall takes integer hallid returns nothing
            set .townhallType = hallid
          //set .townhallName = GetObjectName(hallid)
            set KEY_STRUCTURE[KEY_STRUCTURE_COUNT] = UnitId2String(hallid)
            set KEY_STRUCTURE_COUNT = KEY_STRUCTURE_COUNT+1
        endmethod
        
        method addWorkerType takes integer workerid, integer priority, integer quantity returns nothing
            set .workerType[.totalWorkerTypes] = workerid
            set .workerPriority[.totalWorkerTypes] = priority
            set .workerQty[.totalWorkerTypes] = quantity
            set .totalWorkerTypes = .totalWorkerTypes+1
        endmethod
        
        method addHeroType takes integer heroid returns nothing
            local integer i = 0
            set .heroType[.totalHeroTypes] = heroid
            set .totalHeroTypes = .totalHeroTypes+1
            loop
                call SetPlayerTechMaxAllowed(Player(i),heroid,1)
                set i = i+1
                exitwhen i == bj_MAX_PLAYERS
            endloop
        endmethod
        
        method getRandomHeroType takes nothing returns integer
            local integer randomindex = GetRandomInt(0,.totalHeroTypes)
            return .heroType[randomindex]
        endmethod
        
        method setCallback takes CustomRaceCall callb returns nothing
            set .c = callb
        endmethod
        
        method createRandomHero takes player p, location loc returns unit
            local unit h = CreateUnitAtLoc(p, .getRandomHeroType(), loc, bj_UNIT_FACING)
            if bj_meleeGrantHeroItems then
                call MeleeGrantItemsToHero(h)
            endif
            return h
        endmethod
        
        
        method createStartingUnits takes player p returns nothing
            local location   startLoc        = GetPlayerStartLocationLoc(p)
            local location   nearMineLoc     = startLoc
            local location   nearTownLoc     = startLoc
            local location   spawnLoc        = startLoc
            local location   heroLoc         = startLoc
            local unit       nearestMine     = MeleeFindNearestMine(startLoc, bj_MELEE_MINE_SEARCH_RADIUS)
            local unit       myTownhall      = null
            local unit       myRandHero      = null
            local group      workerGroup     = CreateGroup()
            local integer    workertypeindex = 0
            local integer    workerqty       = 0
            local integer    spawnPriority   = 0
            if nearestMine != null then
                set nearMineLoc = MeleeGetProjectedLoc(GetUnitLoc(nearestMine),startLoc,320,0)
                set nearTownLoc = MeleeGetProjectedLoc(startLoc,GetUnitLoc(nearestMine),288,0)
                set heroLoc     = MeleeGetProjectedLoc(GetUnitLoc(nearestMine),startLoc,384,45)
            endif
            set myTownhall = CreateUnitAtLoc(p,.townhallType,startLoc,bj_UNIT_FACING)
            loop
                exitwhen workertypeindex == .totalWorkerTypes
                    set spawnPriority = .workerPriority[workertypeindex]
                    if (spawnPriority==.NEAR_HALL) then
                        set spawnLoc = nearTownLoc
                    elseif(spawnPriority==.NEAR_MINE) then
                        set spawnLoc = nearMineLoc
                    endif
                    loop
                        call GroupAddUnit(workerGroup, CreateUnitAtLoc(p,.workerType[workertypeindex],PolarProjectionBJ(spawnLoc,65,(I2R(workerqty)*(360.00 / I2R(.workerQty[workertypeindex]))) + 90),bj_UNIT_FACING))
                        set workerqty = workerqty + 1
                        exitwhen workerqty >= .workerQty[workertypeindex]
                    endloop
                    set workerqty = 0
                set workertypeindex = workertypeindex+1
            endloop
            if (IsMapFlagSet(MAP_RANDOM_HERO) and .totalHeroTypes>0 ) then
                set myRandHero = .createRandomHero(p,heroLoc)
            else
                call SetPlayerState(p,PLAYER_STATE_RESOURCE_HERO_TOKENS,bj_MELEE_STARTING_HERO_TOKENS)
            endif
            if(.c!=0) then
                call .c.evaluate(workerGroup,nearestMine,myTownhall,myRandHero)
            else
                call DestroyGroup(workerGroup)
            endif
            if nearMineLoc != startLoc then
                call RemoveLocation(nearMineLoc)
                call RemoveLocation(nearTownLoc)
                call RemoveLocation(heroLoc)
            endif
            call RemoveLocation(startLoc)
            set startLoc    = null
            set nearMineLoc = null
            set nearTownLoc = null
            set spawnLoc    = null
            set heroLoc     = null
            set nearestMine = null
            set myTownhall  = null
            set myRandHero  = null
            set workerGroup = null
        endmethod
     endstruct
    
//===========================================================================
//                         UNIT CREATION SECTION
//===========================================================================
    function CreateStartingUnitsForAllPlayers takes nothing returns nothing
        local integer    index = 0
        local player     indexPlayer
        local race       playerRace
        local CustomRace c
        loop
            set indexPlayer = Player(index)
            set playerRace = GetPlayerRace(indexPlayer)
            if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
                set c = CustomRace.get(playerRace,GetPlayerHandicap(indexPlayer)+0.01)
                if GetPlayerController(indexPlayer) == MAP_CONTROL_USER and c != 0 then
                    call c.createStartingUnits(indexPlayer)
                elseif playerRace == RACE_HUMAN then
                    call MeleeStartingUnitsHuman(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
                elseif playerRace == RACE_ORC then
                    call MeleeStartingUnitsOrc(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
                elseif playerRace == RACE_NIGHTELF then
                    call MeleeStartingUnitsNightElf(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
                elseif playerRace == RACE_UNDEAD then
                    call MeleeStartingUnitsUndead(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
                else
                    call MeleeStartingUnitsUnknownRace(indexPlayer,GetStartLocationLoc(GetPlayerStartLocation(indexPlayer)),true,true,true)
                endif
                call SetPlayerHandicap(indexPlayer,1.0)
            endif
            set index = index + 1
            exitwhen index == bj_MAX_PLAYERS
        endloop
    endfunction

//===========================================================================
//                         VICTORY DEFEAT SECTION
//===========================================================================
    private function CustomGetAllyKeyStructureCount takes player whichPlayer returns integer
        local integer    i           = 0
        local integer    keyStructs  = 0
        local integer    playerIndex = 0
        local player     indexPlayer
        loop
            set indexPlayer = Player(playerIndex)
            if (PlayersAreCoAllied(whichPlayer, indexPlayer)) then
                loop
                    set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, KEY_STRUCTURE[i], true, true)
                    set i = i+1
                    exitwhen i == KEY_STRUCTURE_COUNT
                endloop
            endif
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYERS
        endloop
        return keyStructs
    endfunction

    private function CustomPlayerIsCrippled takes player whichPlayer returns boolean
        local integer allyStructures    = MeleeGetAllyStructureCount(whichPlayer)
        local integer allyKeyStructures = CustomGetAllyKeyStructureCount(whichPlayer)
        return (allyStructures > 0) and (allyKeyStructures <= 0)
    endfunction

    private function CustomCheckForCrippledPlayers takes nothing returns nothing
        local integer    playerIndex
        local player     indexPlayer
        local boolean    isNowCrippled
        call MeleeCheckForLosersAndVictors()
        if bj_finishSoonAllExposed then
            return
        endif
        set playerIndex = 0
        loop
            set indexPlayer = Player(playerIndex)
            set isNowCrippled = CustomPlayerIsCrippled(indexPlayer)
            if (not bj_playerIsCrippled[playerIndex] and isNowCrippled) then
                set bj_playerIsCrippled[playerIndex] = true
                call TimerStart(bj_crippledTimer[playerIndex], bj_MELEE_CRIPPLE_TIMEOUT, false, function MeleeCrippledPlayerTimeout)
                if (GetLocalPlayer() == indexPlayer) then
                    call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], true)
                    call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_WARNING_HUMAN"))
                endif
            elseif (bj_playerIsCrippled[playerIndex] and not isNowCrippled) then
                set bj_playerIsCrippled[playerIndex] = false
                call PauseTimer(bj_crippledTimer[playerIndex])
                if (GetLocalPlayer() == indexPlayer) then
                    call TimerDialogDisplay(bj_crippledTimerWindows[playerIndex], false)
                    if (MeleeGetAllyStructureCount(indexPlayer) > 0) then
                        if (bj_playerIsExposed[playerIndex]) then
                            call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNREVEALED"))
                        else
                            call DisplayTimedTextToPlayer(indexPlayer, 0, 0, bj_MELEE_CRIPPLE_MSG_DURATION, GetLocalizedString("CRIPPLE_UNCRIPPLED"))
                        endif
                    endif
                endif
                call MeleeExposePlayer(indexPlayer, false)
            endif
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYERS
        endloop
    endfunction

    function CustomInitVictoryDefeat takes nothing returns nothing
        local trigger    checker = CreateTrigger()
        local trigger    trig
        local integer    index
        local player     indexPlayer
        set bj_finishSoonTimerDialog = CreateTimerDialog(null)
        call TriggerAddAction(checker, function CustomCheckForCrippledPlayers)
        set trig = CreateTrigger()
        call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
        call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)
        set trig = CreateTrigger()
        call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
        call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)
        set index = 0
        loop
            set indexPlayer = Player(index)
            if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
                set bj_meleeDefeated[index] = false
                set bj_meleeVictoried[index] = false
                set bj_playerIsCrippled[index] = false
                set bj_playerIsExposed[index] = false
                set bj_crippledTimer[index] = CreateTimer()
                set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
                call TimerDialogSetTitle(bj_crippledTimerWindows[index], MeleeGetCrippledTimerMessage(indexPlayer))
                call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
                call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_DEATH, null)
                call TriggerRegisterPlayerUnitEvent(checker, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
                call TriggerRegisterPlayerAllianceChange(checker, indexPlayer, ALLIANCE_PASSIVE)
                call TriggerRegisterPlayerStateEvent(checker, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
                set trig = CreateTrigger()
                call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
                call TriggerAddAction(trig, function MeleeTriggerActionPlayerDefeated)
                set trig = CreateTrigger()
                call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
                call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
             else
                set bj_meleeDefeated[index] = true
                set bj_meleeVictoried[index] = false
                if (IsPlayerObserver(indexPlayer)) then
                    set trig = CreateTrigger()
                    call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
                    call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
                endif
            endif
            set index = index + 1
            exitwhen index == bj_MAX_PLAYERS
        endloop
        call TimerStart(CreateTimer(), 2.0, false, function CustomCheckForCrippledPlayers)
    endfunction
    
endlibrary
04-15-2009, 11:47 PM#3
Rising_Dusk
That's a pretty imposing piece of code you've got there.
Quote:
Originally Posted by Archmage Owenalacaster
It requires no outside systems, it uses a gamecache, its self-contained.
Which means you should use Table instead.
04-15-2009, 11:51 PM#4
Kyrbi0
Quote:
Originally Posted by Archmage Owenalacaster
It requires no outside systems,
My favorite part. :P

Good work with this. If it does what it's supposed to, this is a great boon to Custom Race-rs everywhere.
04-15-2009, 11:54 PM#5
Archmage Owenalacaster
Good point.

Vanilla gamecache offers two key fields so I can store struct references according to race and handicap, which Table doesn't. However I could concatenate the strings into one for the Table key, but I would prefer not to compromise the system's independence.
04-15-2009, 11:58 PM#6
Kyrbi0
I think the capability to use Race+Handicap should definitely be in there, as it's (so far) one of the simplest and cleanest methods for picking custom races (much better than dialogs). Or is that not what you're saying?...

Also, if that's what this thing is using, I would suggest putting moyack in the credits, as he was the one to originally tell me of it (unless you guys thought of it yourself).
04-16-2009, 12:14 AM#7
cosmicat
This system already implements the Handicap system, allowing a maximum of 20 custom races. I'm not sure whether the idea was taken from moyack/you/me or not.

Note that this system requires vJass. Boo hoo.
04-16-2009, 12:22 AM#8
Michael Peppers
24 races (overwriting the normal ones), and the (first) goal of my project is 28 :(

But this code is awesome nonetheless, test it, 4 more lines and you've got your own custom race spawned perfectly...

EDIT: I recall that it was an idea of moyack...
04-16-2009, 12:25 AM#9
Kyrbi0
Quote:
Originally Posted by cosmicat
Note that this system requires vJass. Boo hoo.
Eh? In what way? I mean, so far it needs nothing (as he said), and if he changes it to need Tables, then it'll just need that.
04-16-2009, 12:28 AM#10
Michael Peppers
Quote:
Originally Posted by Kyrbi0
Quote:
Originally Posted by cosmicat
Note that this system requires vJass. Boo hoo.
Eh? In what way? I mean, so far it needs nothing (as he said), and if he changes it to need Tables, then it'll just need that.

Collapse From above:
//  Requirements:
//      - JassHelper version 0.9.E.0 or newer (older versions may still work).

It must be compiled, ergo (or "so" if you prefer) it's vJass, sorry Kyrbi0...
04-16-2009, 12:30 AM#11
Kyrbi0
Alright, then what's this supposed to mean:
Quote:
It requires no outside systems, it uses a gamecache, its self-contained.
Granted I'm a noob at advanced triggering, but wouldn't "Jasshelper" count as an "outside system"?
04-16-2009, 12:30 AM#12
Alevice
You know, after looking a few of those callbacks, maybe a player argument should have been put. I mean, if you intend to create additional stuff for the player, you still need to know who triggered it.


Quote:
Originally Posted by Kyrbi0
Eh? In what way? I mean, so far it needs nothing (as he said), and if he changes it to need Tables, then it'll just need that.

Bascially it uses things that are nonly supported by vJass. Also, Table requires vJass as well.

I take you still have not installed JNGP?

EDIT: Jasshelper is the de facto standard these days. Calling it an outside system is an understatement of what it does.
04-16-2009, 12:40 AM#13
cosmicat
Tables also require JassHelper, so changing this system to use Table wouldn't improve it in any way.
04-16-2009, 01:49 AM#14
Anitarf
I haven't really had a chance to read at the code, but why the heck would this need gamecache? Regular war3 melee triggers don't need it...

I'd put the content (the RegisterCustomRaces part) in a separate library from the system, since if it's in the same library it has to be at the end instead of a calibration function at the start.
04-16-2009, 02:33 AM#15
Alevice
Quote:
Originally Posted by Anitarf
I haven't really had a chance to read at the code, but why the heck would this need gamecache? Regular war3 melee triggers don't need it...

It is just for registering the races. Since it needs two keys (base race and handicap), GC was kind of the simpler approach. Any other alternative surely is welcome.


Quote:
Originally Posted by Anitarf
I'd put the content (the RegisterCustomRaces part) in a separate library from the system, since if it's in the same library it has to be at the end instead of a calibration function at the start.

Technically, the second post is the actual system. The first post contains an (obviously optional) expanded example implementing races with custom callbacks for each of them (including a recreation of the basic races, just to demonstrate the felxibility of the system). That's why it looks like it is in the end, but actually, it isn't.