Wc3C.net

Wc3C.net (http://www.wc3c.net/forums.php)
-   Systems (http://www.wc3c.net/forumdisplay.php?f=648)
-   -   Custom Race System (http://www.wc3c.net/showthread.php?t=105611)

Archmage Owenalacaster 04-22-2009 04:30 AM

Custom Race System
 
5 Attachment(s)
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.

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.


Expand Custom Race System:

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

Kyrbi0 04-22-2009 04:36 AM

As stated in the previous thread, good luck. This is a great boon to Custom Race-rs everywhere.

Anitarf 04-22-2009 10:10 AM

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?

Archmage Owenalacaster 04-22-2009 10:33 AM

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.
Collapse 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.

Michael Peppers 04-22-2009 12:18 PM

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 :emote_thumbup:

Archmage Owenalacaster 04-22-2009 12:41 PM

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.

Michael Peppers 04-22-2009 02:51 PM

Collapse 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

Archmage Owenalacaster 04-22-2009 03:11 PM

Mister Peppers, thanks for catching that.

Also, first post has been updated to include some information about the demo map.

moyack 04-22-2009 03:19 PM

Mister Arch.... you deserve man love for this implementation. Well done. I'll test it this night and do some comments about it.

Alevice 04-22-2009 11:18 PM

I dont understand what this system is good for. :S

Does it make custom races with 3 lines or something? Sorry, kind of confuysing-:emote_confused:

ignore anything here


srego
\

/
levi


Michael Peppers 04-22-2009 11:25 PM

Quote:

Originally Posted by Alevice in noob-like pants and disguise
I dont understand what this system is good for. :S

Does it make custom races with 3 lines or something? Sorry, kind of confuysing-:emote_confused:


Ha! Seems kinda like the beginning of a publicity xD

Quote:

Originally Posted by Michael Peppers other times ago
But this code is awesome nonetheless, test it, 4 more lines and you've got your own custom race spawned perfectly...


Archmage Owenalacaster 04-25-2009 02:08 AM

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.

Sunwarrior25 04-25-2009 03:28 PM

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! :emote_thumbup:

EDIT: Apparantly, you already thought of that. Anywho, I think everyone can find a use for this.

Kyrbi0 04-25-2009 03:31 PM

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

cosmicat 05-01-2009 01:46 AM

Huh, sounds cool. Guess I'll try the map some time.


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

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