| 04-22-2009, 04:30 AM | #1 | |
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. Please do not redistribute this system. This is a WC3C-exclusive resource, and I wish it to remain that way.
Demo Map Credits Playtesters
Things to take into consideration
Custom Race System://============================================================================== // Custom Race System by Archmage Owenalacaster //============================================================================== // // Purpose: // - Creates the starting units for custom races and replaces the standard // Melee Initialization trigger. Custom races are selected by race and // handicap. // // Usage: // - Register a new custom race with CustomRace.create(name, RACE, handicap) // Handicaps: Valid handicap values are 1.0, 0.9, 0.8, 0.7, 0.6 and 0.5. // - Register a new custom race for all handicaps of a single race with // CustomRace.createAll(name, RACE) // - Extend the registration of a race with c.register(RACE, handicap) // - Set the townhall type with c.setTownHall(unitid) // - Add a new worker type with c.addWorkerType(unitid, priority, qty) // Priorities: c.NEAR_MINE spawns workers near the mine, where workers // typically spawn. // c.NEAR_HALL spawns workers near the town hall, where // Ghouls spawn. // - Add a random hero type with c.addHeroType(unitid) // - Set the ai script used by computer players with c.setAIScript(stringpath) // - 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. // - Get a player's custom race name string with GetPlayerCustomRaceName(player) // // Notes: // - Supports a maximum of 24 custom races. // - Maximum for worker and hero types are configurable. // // 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 CustomRaceSystem initializer Init //=========================================================================== // CONFIGURATION SECTION //=========================================================================== globals // Unit Type Constants private constant integer MAX_WORKERTYPES = 4 private constant integer MAX_HEROTYPES = 4 endglobals //=========================================================================== // END CONFIGURATION SECTION //=========================================================================== function interface CustomRaceCall takes player play, 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 if r == RACE_HUMAN then return 1 elseif r == RACE_ORC then return 2 elseif r == RACE_UNDEAD then return 3 elseif r == RACE_NIGHTELF then return 4 endif return 5 endfunction globals // Victory Defeat Variables private string array KEY_STRUCTURE private integer KEY_STRUCTURE_COUNT = 0 endglobals //=========================================================================== // STRUCT DATA //=========================================================================== private keyword createStartingUnits struct CustomRace string name // Town Hall Variable integer townhallType = 0 //string townhallName // Town Hall name is not currently supported. // Worker Variables integer totalWorkerTypes = 0 integer array workerType[MAX_WORKERTYPES] integer array workerPriority[MAX_WORKERTYPES] integer array workerQty[MAX_WORKERTYPES] // Random Hero Variables integer totalHeroTypes = 0 integer array heroType[MAX_HEROTYPES] // AI Script Directory String Variable string aiscript = "" // Callback Variable private CustomRaceCall c // Registry Variable static integer array REGISTRY // Spawn Priority Variables static integer NEAR_MINE = 0 static integer NEAR_HALL = 1 static method get takes race r, real h returns CustomRace return CustomRace(.REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))]) endmethod method register takes race r, real h returns boolean 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 false endif set .REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))] = integer(this) return true endmethod static method create takes string name, race r, real h returns CustomRace local CustomRace c = CustomRace.allocate() set c.name = name if not c.register(r,h) then call c.destroy() return 0 endif return c endmethod static method createAll takes string name, race r returns CustomRace local CustomRace c = CustomRace.allocate() set c.name = name 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 call c.destroy() return 0 endif return c endmethod method setTownHall takes integer hallid returns nothing set .townhallType = 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 private method getRandomHeroType takes nothing returns integer local integer randomindex = GetRandomInt(0,.totalHeroTypes-1) return .heroType[randomindex] endmethod method setAIScript takes string s returns nothing set .aiscript = s endmethod method setCallback takes CustomRaceCall callb returns nothing set .c = callb endmethod private 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 call RemoveLocation(spawnLoc) 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(p,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 globals private string array PLAYER_RACE endglobals function GetPlayerCustomRaceName takes player p returns string return PLAYER_RACE[GetPlayerId(p)] endfunction //=========================================================================== // UNIT CREATION SECTION //=========================================================================== private function CreateStartingUnitsForAllPlayers takes nothing returns nothing local integer index = 0 local player indexPlayer local race playerRace local CustomRace c loop set indexPlayer = Player(index) if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then set playerRace = GetPlayerRace(indexPlayer) set c = CustomRace.get(playerRace,GetPlayerHandicap(indexPlayer)+0.01) if (GetPlayerController(indexPlayer) == MAP_CONTROL_USER or (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER and c.aiscript != "" )) and c != 0 then set PLAYER_RACE[index] = c.name 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 endif set index = index + 1 exitwhen index == bj_MAX_PLAYERS endloop endfunction //=========================================================================== // CUSTOM MELEE AI SECTION //=========================================================================== private function CustomMeleeStartingAI takes nothing returns nothing local integer index = 0 local player indexPlayer local race indexRace local CustomRace c loop set indexPlayer = Player(index) if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then set indexRace = GetPlayerRace(indexPlayer) set c = CustomRace.get(indexRace,GetPlayerHandicap(indexPlayer)+0.01) call SetPlayerHandicap(indexPlayer,1.0) if (GetPlayerController(indexPlayer) == MAP_CONTROL_COMPUTER) then // Run a race-specific melee AI script. if c != 0 and c.aiscript != "" then call StartMeleeAI(indexPlayer, c.aiscript) elseif (indexRace == RACE_HUMAN) then call PickMeleeAI(indexPlayer, "human.ai", null, null) elseif (indexRace == RACE_ORC) then call PickMeleeAI(indexPlayer, "orc.ai", null, null) elseif (indexRace == RACE_UNDEAD) then call PickMeleeAI(indexPlayer, "undead.ai", null, null) call RecycleGuardPosition(bj_ghoul[index]) elseif (indexRace == RACE_NIGHTELF) then call PickMeleeAI(indexPlayer, "elf.ai", null, null) else // Unrecognized race. endif call ShareEverythingWithTeamAI(indexPlayer) endif 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 set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "townhall", true, true) set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "greathall", true, true) set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "necropolis", true, true) set keyStructs = keyStructs + GetPlayerTypedUnitCount(indexPlayer, "treeoflife", true, true) 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 private 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 private function TimerAction takes nothing returns nothing call SetFloatGameState(GAME_STATE_TIME_OF_DAY, bj_MELEE_STARTING_TOD) call MeleeStartingHeroLimit() call MeleeGrantHeroItems() call MeleeStartingResources() call MeleeClearExcessUnits() call CreateStartingUnitsForAllPlayers() call CustomMeleeStartingAI() call CustomInitVictoryDefeat() call DestroyTimer(GetExpiredTimer()) endfunction private function Init takes nothing returns nothing call TimerStart(CreateTimer(),0,false,function TimerAction) endfunction endlibrary Here is an example of implementation from the demo map. Naga are a playable race for Night Elf, Handicap 90%. Custom Race Setup://==================================================================== // HUMAN SETUP //==================================================================== library HumanSetup initializer Init requires CustomRaceSystem private function Init takes nothing returns nothing local CustomRace 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 call c.setAIScript("human.ai") endfunction endlibrary //==================================================================== // ORC SETUP //==================================================================== library OrcSetup initializer Init requires CustomRaceSystem private function Init takes nothing returns nothing local CustomRace 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 call c.setAIScript("orc.ai") endfunction endlibrary //==================================================================== // UNDEAD SETUP //==================================================================== library UndeadSetup initializer Init requires CustomRaceSystem private function WorkerHideToggle takes nothing returns nothing call ShowUnit(GetEnumUnit(),IsUnitHidden(GetEnumUnit())) endfunction private function HauntGoldMine takes player play, group workers, unit goldmine, unit townhall, unit randhero returns nothing call ForGroup(workers,function WorkerHideToggle) call BlightGoldMineForPlayerBJ(goldmine,play) call ForGroup(workers,function WorkerHideToggle) call DestroyGroup(workers) endfunction private function Init takes nothing returns nothing local CustomRace 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) call c.setAIScript("undead.ai") endfunction endlibrary //==================================================================== // NIGHT ELF SETUP //==================================================================== library NightElfSetup initializer Init requires CustomRaceSystem private function EntangleGoldMine takes player play, 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 Init takes nothing returns nothing local CustomRace 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) call c.setAIScript("elf.ai") endfunction endlibrary //==================================================================== // NAGA SETUP //==================================================================== library NagaSetup initializer Init requires CustomRaceSystem private function Init takes nothing returns nothing local CustomRace 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 call c.setAIScript("naga.ai") endfunction endlibrary |
| 04-22-2009, 04:36 AM | #2 |
As stated in the previous thread, good luck. This is a great boon to Custom Race-rs everywhere. |
| 04-22-2009, 10:10 AM | #3 |
Is it possible to assign the same race to multiple handicaps, so as to prevent a player from being able to get the default races? |
| 04-22-2009, 10:33 AM | #4 |
Yes, although the current design would require redundant registration. The code could easily be adapted to permit extended registration; I'll add a register method. EDIT: I think this will reduce code redundancy to one line per extension. register method:method register takes race r, real h returns nothing 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)) endif set .REGISTRY[((r2I(r)-1)*6)+(10-R2I(h*10.))] = integer(this) endmethod Code and demo map updated. |
| 04-22-2009, 12:18 PM | #5 |
How did I lose this thread? I really like this system, flexible and really useful for a lot of coders. Lots of thanks for making this available to all |
| 04-22-2009, 12:41 PM | #6 |
At Levi's suggestion, I'm adding a method to register a custom race for all handicaps of a single race. EDIT: static method registerAll added. Code and demo updated. |
| 04-22-2009, 02:51 PM | #7 |
JASS:static method registerAll takes string name, race r returns CustomRace local CustomRace c = CustomRace.allocate() set c.name = name 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 c.register(r,0.5) then call c.destroy() endif return c endmethod Did you perhaps miss a "not" in the highlighted point? If "not", well, my fault :P |
| 04-22-2009, 03:11 PM | #8 |
Mister Peppers, thanks for catching that. Also, first post has been updated to include some information about the demo map. |
| 04-22-2009, 03:19 PM | #9 |
Mister Arch.... you deserve man love for this implementation. Well done. I'll test it this night and do some comments about it. |
| 04-22-2009, 11:18 PM | #10 | |
I dont understand what this system is good for. :S Does it make custom races with 3 lines or something? Sorry, kind of confuysing- ![]()
|
| 04-22-2009, 11:25 PM | #11 | ||
Quote:
Ha! Seems kinda like the beginning of a publicity xD Quote:
|
| 04-25-2009, 02:08 AM | #12 |
It's worth noting a future version of the system will support an extension of custom races to computer players only if they have AIs provided. |
| 04-25-2009, 03:28 PM | #13 |
Nice! I'm not sure, but I think the only problem would be the weakening of a race as the handicap gets lower. Anyhoo, good luck! EDIT: Apparantly, you already thought of that. Anywho, I think everyone can find a use for this. |
| 04-25-2009, 03:31 PM | #14 |
It's made to reset the Handicap level to 100% if you choose a certain Race/Handicap combo. The only problem with that is that people can't play as "Human 90%" if they actually did want to do so. :P |
| 05-01-2009, 01:46 AM | #15 |
Huh, sounds cool. Guess I'll try the map some time. |
