Tutorial Getting you started on your first custom species!

Discussion in 'Starbound Modding' started by Kayuko, May 16, 2015.

  1. Kayuko

    Kayuko Oxygen Tank

    Yaaaay~
    Another one...~

    Lil' fluffy foxy fluff here again!
    This is going to be a LONG tutorial, so get some caffeine and aspirin ready.
    We'll go through the (theoretic) process of creating your first viable species-mod.
    This includes (but is not limited to):

    1. Character Sprite Management
    2. Ship-building
    3. Building your own base-ai
    4. Creating an armor-part and a weapon
    5. Adjust the starting treasure pool
    So, we'll start obviously with the SPECIES *cough* sprites, since those are the base of the mod.
    We will NOT go through the detailed process of creating these pixelart-works (mainly because I suck at it).
    I'll explain dimensions, color shifts and frames / animations. That's about it.

    ========================================================================================

    Things you need:

    Gimp or photoshop (due to layer- and transparence management)
    Notepad++ or any other utf-8 encode-friendly text editor (As always)
    A species template mod (more on that in a second)

    ========================================================================================

    A species template can be found once you unpack your assets. It's located in "/humanoid/any".
    https://www.dropbox.com/s/umoh49gwwjbtqou/Dummy.rar?dl=0 (for the lazy ones)

    This is a good example of your sprites' size, pose and overall looks.
    Before you modify or create anything you should keep one thing in mind:
    Every armor is based off those assets. If you want to keep the vanilla armors as they are you don't have much margin in your characters size or pose.
    As soon as you mess up the dimensions you would need to completely re-animate every armor to make them fit.

    We won't be using the dummy files as an example, as it's easier to look at an existing race.
    That's why we'll use the avian assets.

    Note: There are some unfinished climbing animations, for example in the "hair" folder. They are - however - not used, rendering the default.frames file useless. You can just ignore it! ... I think!
    Or it's used to define the frame-anchors, I'm not sure yet.


    ========================================================================================

    The first thing you'll be doing is most likely the body-sprite of your species.
    I can't help much with spriting since it's 10% inspiration, 40% the idea what you want and 50% placing pixels.
    Here are two example pictures, however, that should explain the best way to go about spriting:

    Sprites.png

    I know it's a little small, but you get the basic idea.
    First sprite the base, then color the borders and finally add color and shadows.

    Now, if you follow this tutorial in real time, do this for all the sprites you need, according to the positions on the spritesheets found in the avian (or whatever species you use as a base) folder.

    Done? Cool.

    Next up is hairs.

    You see the hair folder, right?
    This is where the default.frames (that I mentioned earlier you should ignore / just copy an existing one) is located and where some frames are defined as climbing on the spritesheet.
    Now, the important thing if you alter those frames is:
    Keep the locations. Your hair will be messed up, otherwise. You can also (unlike the avian does it) only sprite the hair, without the head. Keeping the head in, however, has one big favor: You know where each pixel will ultimately end up.

    With this said, here's a little tl;dr:

    Keep the spritesheet dimensions (altering them is something more advanced, it is possible however, more on that later)
    Keep the dimensions (especially the character height)

    Once you finished all the spritesheets (list down there) you finished the most important part for your first custom species, congratz, you got farther then I ever did!

    Spritesheets:

    /backarm.png
    /emote.png
    /femalebody.png
    /femalehead.png
    /frontarm.png
    /malebody.png
    /malehead.png
    /dead.png (This is, in fact, only a single png file, not a spritesheet)
    /hair/ (You have an unlimited [Okay, I think it's limited to 255] amount of hairs you can create, just enumerate them properly)
    /xxx/ (For example, novakid's brand. This is more advanced as it requires a few changes to be made later on, nothing too difficult tho)

    ========================================================================================

    Now to the Shi- Oh wait!
    We're far from finished.
    Now comes the fun part for everyone not good at spriting or the "fun" part for everyone not good at editing JSON files.
    (How can someone be bad at editing them? e.e)


    {
    "frameGrid" : {
    "size" : [43, 43],
    "dimensions" : [9, 6],

    "names" : [
    [ null, "idle.1", "idle.2", "idle.3", "idle.4", "idle.5", "sit.1", null, "duck.1" ],
    [ null, "walk.1", "walk.2", "walk.3", "walk.4", "walk.5", "walk.6", "walk.7", "walk.8" ],
    [ null, "run.1", "run.2", "run.3", "run.4", "run.5", "run.6", "run.7", "run.8" ],
    [ null, "jump.1", "jump.2", "jump.3", "jump.4", "fall.1", "fall.2", "fall.3", "fall.4" ],
    [ null, "climb.1", "climb.2", "climb.3", "climb.4", "climb.5", "climb.6", "climb.7", "climb.8" ],
    [ null, "swimIdle.1", null, null, "swim.1", "swim.2", "swim.3", "swim.4" ]
    ]
    },
    "aliases" : {
    "swimIdle.2" : "swimIdle.1",
    "swim.5" : "swimIdle.1",
    "swim.6" : "swimIdle.1",
    "swim.7" : "swimIdle.1",
    "lay.1" : "run.8"
    }
    }


    Now, I explained this in the JSON Doc already, but I'll explain it using normal-people words now.
    This is the frames while where the frames used for specific animations are defined.

    "frameGrid" is using two functions: "size" and "dimensions". Those are very easily explained.
    The linked spritesheet of this file, for example, has 9 columns and 6 rows with each frame being 43x43 px in size.

    Next, the "names".
    Those link the single frames to a name, later used in the animation process.
    I'll translate the first line to muggle:

    [ UnusedFrame (mostly used for in-picture description), Frame called "idle.1", Frame called "idle.2", Frame called "idle.3", Frame called "idle.4", Frame called "idle.5", Frame called "sit.1", UnusedFrame, Frame called "duck.1"],

    The comma declares a new line in the code, so the next line is linked to the 2nd row of the spritesheet.

    For single-frame sheets (like hairs, and heads) you might want to use this bit of code:


    {
    "frameList" : {
    "normal" : [43, 0, 86, 43],
    "climb" : [43, 172, 86, 215]
    }
    }


    I have no idea how it is defined, but I think the start of the frame HAS to be defined somewhere.
    //Probably fit for editing once I found out where//

    So, now you're basically finished with the humanoid folder, that's pretty much a blessing for me since that was the only thing I really had no clue about. Next up is the ship creation.

    ====================================================================================

    Creating your race's ship is basically the same thing as creating a mission or a dungeon.
    But, since this isn't an advanced-tutorial and I don't really want to link tutorials together I'll explain it again.

    Block definitions:

    aviant7blocks.png


    The actual Ship:

    aviant7.png

    The lightmap:

    aviant7lit.png


    {
    "config" : {
    "shipUpgrades" : {
    "capabilities" : ["teleport", "planetTravel", "systemTravel"],
    "maxFuel" : 1000
    }
    },

    "backgroundOverlays" : [
    {
    "image" : "avianT7.png",
    "position" : [4.62, 12.38],
    "fullbright" : true
    },
    {
    "image" : "avianT7lit.png",
    "position" : [4.62, 12.38]
    }
    ],

    "blockKey" : "blockKey.config:blockKey",
    "blockImage" : "avianT7blocks.png"
    }



    Okay, so this is the config for your ship.
    In this case it's the config of the tier7 avian ship.
    Here are a few things set:
    1. The unlocked actions you can use (Teleport [for example, disabled on tier0 ships), planetTavel [Planet to Planet, intersystem travels], systemTravel (System to System FTL jumps)
    2. The maximum amount of fuel you can add in your tank.
    3. The background setting (ships' png and positioning), you might notice the "fullbright" future, that's used later.
    4. The lightmap has a higher drawpriority (due to it being in the second spot of the array), thus it's drawn over the full-ship png. That's why the lightmap uses a slightly transparent opacity and the background image uses the "fullbright" effect.
    5. The block key info, i.e. the path to the blockKey.config file and the path to the tilemap (avianT7blocks.png in this case)



    {
    "blockKey" : [
    {
    "value" : [255, 255, 255, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : false
    },

    {
    "value" : [0, 0, 255, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true
    },

    {
    "value" : [255, 0, 0, 255],
    "foregroundBlock" : true,
    "backgroundBlock" : true
    },

    {
    "value" : [0, 255, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipwall",
    "flags" : [ "shipLockerPosition" ],
    "object" : "avianshiplocker",
    "objectParameters" : {
    "treasurePools" : [ "avianStarterTreasure" ],
    "level" : 0.5,
    "unbreakable" : true
    },
    "objectResidual" : true
    },

    {
    "value" : [0, 128, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipwall",
    "object" : "avianshiplockerTier0",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [142, 255, 142, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipwall",
    "object" : "aviantechstation",
    "objectParameters" : {
    "unbreakable" : true
    },
    "objectResidual" : true
    },

    {
    "value" : [0, 21, 128, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipwall",
    "object" : "researchstation",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [255, 87, 81, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "brokenavianfuelhatch",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [128, 44, 41, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "brokenavianfuelhatchTier0",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [255, 90, 90, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "avianfuelhatch",
    "objectParameters" : {
    "unbreakable" : true
    },
    "objectResidual" : true
    },

    {
    "value" : [255, 255, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails",
    "object" : "apexshiplight",
    "objectResidual" : true
    },

    {
    "value" : [191, 191, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails",
    "object" : "apexshiplightBroken",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [128, 128, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails",
    "object" : "apexshiplight",
    "objectParameters" : {
    "unbreakable" : true,
    "defaultLightState" : false
    }
    },

    {
    "value" : [255, 102, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : false,
    "object" : "avianshipdoor",
    "objectResidual" : true
    },

    {
    "value" : [128, 51, 0, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : false,
    "object" : "avianshipdoorBroken",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [174, 137, 81, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "shipengine",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [156, 0, 255, 255],
    "anchor" : true,
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails",
    "object" : "avianteleporter",
    "flags" : [ "playerSpawn" ],
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [79, 0, 128, 255],
    "anchor" : true,
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails",
    "object" : "avianteleporterTier0",
    "flags" : [ "playerSpawn" ],
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [167, 167, 255, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "boosterflame",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [150, 150, 255, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "bigboosterflameavian",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [168, 168, 168, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "smallboosterflame",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [0, 255, 255, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "aviancaptainschair",
    "objectDirection" : "right",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [122, 122, 122, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "invisiblelight",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [255, 232, 128, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "object" : "invisiblesparker",
    "objectParameters" : {
    "unbreakable" : true
    }
    },

    {
    "value" : [255, 255, 144],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipwall"
    },

    {
    "value" : [255, 117, 144],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipdetails"
    },

    {
    "value" : [255, 117, 255],
    "foregroundBlock" : false,
    "backgroundBlock" : true,
    "backgroundMat" : "apexshipsupport"
    },

    {
    "value" : [255, 255, 220],
    "foregroundBlock" : true,
    "backgroundBlock" : false,
    "foregroundMat" : "hazard",
    "foregroundResidual" : true
    },

    {
    "value" : [255, 200, 220],
    "foregroundBlock" : true,
    "backgroundBlock" : true,
    "foregroundMat" : "hazard",
    "foregroundResidual" : true,
    "backgroundMat" : "apexshipdetails"
    },

    {
    "value" : [0, 0, 0],
    "anchor" : true,
    "foregroundBlock" : true,
    "backgroundBlock" : false
    }
    ]
    }


    And, again, blockKey.config works like a .dungeon file.
    It scans the png for RGB values, converts matching values to blocks and objects and adds them to the map itself.
    Basically, it works like a non-gui level editor.

    Easiest way to about creating your own ship: There is none! (Because they're all easy)

    Just create the tilemap, create the normal ship.png (probably the most difficult thing, you have to design it by yourself, and that's not called pixelart anymore, that's art) and convert a lightmap (simply setting the opacity of the ship.png)

    I wish you good luck and much fun doing that, once you're done, get back here and read on!
    There's lots more to come, but that's basically it for ships. Here a little checklist tho:

    1. Don't forget the captains chair
    2. Don't forget the shiplocker
    3. Don't forget the shiplockerTier0 (Yes, that's a different thing)
    4. Don't forget the fuelhatch
    5. Don't - for gods sake - forget the techstation
    ==============================================================================

    Next up is the base-ai. I'm NOT going through the process of creating a whole Ai with all the options (might do that later) since all you really need for a viable species mod is the following:
    • Custom Animations
    • Custom Textlines
    • Patched Species Names
    We will start with the animations, since that's the hardest part.

    avianai.png

    Thats actually the avianai.png.
    If you don't want something too complicated you'll use the pre-defined frames in this spritesheet, if you do that you can just use your version and the vanilla-based settings.
    However, like the A.V.I.A.N. mod, you can also set TONS of animations, getting S.A.I.L. a smoother feel. You could actually even animate it to match the 60fps feeling (Don't do that - that's completely not needed).

    Here's the AVIAN example, posted in a spoiler, so you know why you shouldn't choose a complex animation type unless you're willing to work on that for days, probably weeks:


    AVIAN.png


    Each and every frame of that (rather amazing) spritesheet is individually defined in the .frames and .animations files linked the the ai.png. This is a LOT of work. I repeat, since you're reading this tutorial you are a beginner, DO NOT EVEN CONSIDER THIS FOR NOW!

    So, once you created your own S.A.I.L. avatar and assigned them to a spritesheet you might want to take a look at the following files:


    {
    "frameGrid" : {
    "size" : [90, 94],
    "dimensions" : [9, 4],

    "names" : [
    [null, "idle", null, "blink"],
    [null, "talk.0", "talk.1", null, "yell.0", "yell.1"],
    [null, "refuse.0", "refuse.1", "refuse.2", "refuse.3", "refuse.4", "refuse.5", "refuse.6", "refuse.7"],
    [null, "unique.0", "unique.1", "unique.2", "unique.3", "unique.4", "unique.5", "unique.6", "unique.7"]
    ]
    },
    "aliases" : {
    "idle.0" : "idle",
    "idle.1" : "idle",
    "idle.2" : "idle",
    "idle.3" : "idle",
    "idle.4" : "idle",
    "idle.5" : "idle",
    "idle.6" : "idle",
    "idle.7" : "idle",
    "idle.8" : "idle",
    "idle.9" : "idle",
    "idle.10" : "idle",
    "idle.11" : "idle",
    "idle.12" : "idle",
    "idle.13" : "blink",
    "idle.14" : "idle",
    "idle.15" : "idle",
    "idle.16" : "idle",
    "idle.17" : "idle",
    "idle.18" : "idle",
    "idle.19" : "idle",
    "idle.20" : "idle"
    }
    }


    I explained the functions of .frames files earlier, so I'll just keep it at that.


    {
    "aiAnimations" : {
    "idle" : {
    "frames" : "<image>:idle.<index>",
    "mode" : "loopForever",
    "frameNumber" : 21,
    "animationCycle" : 3.0,
    "centered" : false
    },

    "blink" : {
    "frames" : "<image>:blink.<index>",
    "mode" : "stop",
    "frameNumber" : 1,
    "centered" : false
    },

    "talk" : {
    "frames" : "<image>:talk.<index>",
    "mode" : "loopForever",
    "frameNumber" : 2,
    "animationCycle" : 0.5,
    "centered" : false
    },

    "yell" : {
    "frames" : "<image>:yell.<index>",
    "mode" : "loopForever",
    "frameNumber" : 2,
    "animationCycle" : 0.5,
    "centered" : false
    },

    "refuse" : {
    "frames" : "<image>:refuse.<index>",
    "mode" : "loopForever",
    "frameNumber" : 8,
    "centered" : false
    },

    "unique" : {
    "frames" : "<image>:unique.<index>",
    "mode" : "loopForever",
    "frameNumber" : 8,
    "centered" : false
    }
    },
    "defaultAnimation" : "idle",
    "staticAnimation" : {
    "frames" : "<image>:<index>",
    "mode" : "loopForever",
    "animationCycle" : 0.111,
    "frameNumber" : 4,
    "centered" : false
    },

    "scanlineAnimation" : {
    "frames" : "scanlines.png:<index>",
    "mode" : "loopForever",
    "animationCycle" : 0.999,
    "frameNumber" : 14,
    "centered" : false
    },

    "staticOpacity" : 0.2,
    "scanlineOpacity" : 0.5,
    "charactersPerSecond" : 45,

    "species" : {
    "apex" : {
    "aiFrames" : "apexAi.png",
    "staticFrames" : "staticApex.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "avian" : {
    "aiFrames" : "avianAi.png",
    "staticFrames" : "staticAvian.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "floran" : {
    "aiFrames" : "floranAi.png",
    "staticFrames" : "staticAvian.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "glitch" : {
    "aiFrames" : "glitchAi.png",
    "staticFrames" : "staticGlitch.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "human" : {
    "aiFrames" : "humanAi.png",
    "staticFrames" : "staticHuman.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "novakid" : {
    "aiFrames" : "NovakidAI.png",
    "staticFrames" : "staticGlitch.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "penguin" : {
    "aiFrames" : "NovakidAI.png",
    "staticFrames" : "staticGlitch.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    },
    "hylotl" : {
    "aiFrames" : "hylotlAi.png",
    "staticFrames" : "staticHylotl.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ERROR: ERROR: Info:'S.A.I.L.::run.innerLoop', 'Cnt#: ', 1198, 'Sum:ms:', ERROR: 'Min', 15, 'Max', 7199, 'Horse', 9899, 'Avg', 23, 'Last:::', '800b5', 'Var:avg,us: ERROR: ERROR: REBOOT REQUIRED!!!'",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "The thrusters and FTL drive are offline. I can repair the thrusters with the ships auto repair module but I'll need ^orange;core fragments^green; from the core of the planet below.",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "We've repaired the ships thrusters. Travel within this system is now available, ^green;did you investigate that gate yet? Next we need to fix the ship's FTL drive.",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "The ship's FTL drive is now fully functional. The galaxy is yours to explore!",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "Here you can augment your body with tech cards and nano suits. ^orange;Tech cards ^green;will give you unique abilities whilst ^orange;nano suits ^green;will allow you to survive in otherwise deadly environments.",
    "speedModifier" : 1.0
    }
    ]
    }
    },

    "enableCommandsAtLevel" : {
    "0" : ["upgradeShip1"],
    "1" : ["giveBeamaxe", "upgradeShip2"],
    "2" : ["upgradeShip3"],
    "3" : ["givePainttool"],
    "4" : ["giveWiretool"],
    "5" : [],
    "6" : [],
    "7" : []
    },

    "techPurchaseItem" : "blanktechcard"
    }


    I'm so free as to quote my own post from another thread that should explain enough on this file:

    "aiAnimations" -- Defines the animations of S.A.I.L.

    "idle" -- Animation name
    "blink" -- Animation name
    "talk" -- Animation name
    "yell" -- Animation name
    "refuse" -- Animation name
    "unique" -- Animation name

    "frames" -- Defines the png frames (format: <image>:idle.<index>)
    "mode" -- Repetition type (known possible values: "loopForever", "stop")
    "frameNumber" -- Defines how many frames the animation uses
    "animationCycle" -- Defines cycle-speed (Frames in relation to animationCycle value) [Needs confirmation]
    "centered" -- Boolean value [Needs more info]

    "defaultAnimation" -- Defines which animation is used as default. (Possible values: All animations created in "aiAnimations")
    "staticAnimation" -- Starter animation, seen prior to thruster repair
    "scanlineAnimation" -- Animation values for the green scanlines
    "staticOpacity" -- Opacity of the static animation
    "scanlineOpacity" -- Opacity of the scanline animation
    "charactersPerSecond" -- Defines how fast SAIL "talks"

    "species" -- Variable species texts and animations are defined in here
    "aiFrames" -- Filepath for the ai-image (usually <species>Ai.png)
    "staticFrames" -- Filepath for the static-image (usually static<Species>.png)
    "openSpeech" -- Function to add speech arrays
    "0", "1", "2", "3" -- Specific shipLevel enumerations
    "animation" -- Set's the animation used at a specific shipLevel (set in the enumeration) (Possible values: All animations set in "aiAnimations")
    "text" -- Strings shown in the S.A.I.L. textbox
    "speedModifier" -- Alters the "charactersPerSecond" option. (For example: 0.5 -- Speaks half as fast)
    "techIntro" -- Specific set of animations and text's set for the tech-function of S.A.I.L.
    "enableCommandsAtLevel" -- Array used to enable / add functions to S.A.I.L. at a specific shipLevel (Those are linked to the ai.folder. Example: Function "upgradeShip1" equals the "upgradeShip1.aicommand" file)
    "0" - "7" -- Enumerations for the shipLevel
    "techPurchaseItem" -- Defines the item used to purchase techs from S.A.I.L. (Default: "blanktechcard")

    That's basically all you ever need to know about the ai.config file.
    I marked the line you should take a closer look at in orange, this is the ones you might want to edit.

    This line defines the speech values of the specific species.
    You might want to ADD a species, that's what we'll be doing now.
    Here's the basic code (don't just copy&paste or you'll learn nothing):


    [
    {
    "op" : "add",
    "path" : "/species/YourSpecies",
    "value" :
    {
    "aiFrames" : "replacemeAi.png",
    "staticFrames" : "staticReplaceme.png",
    "openSpeech" : {
    "0" : [
    {
    "animation" : "unique",
    "text" : "ReplaceMe",
    "speedModifier" : 0.5
    }
    ],
    "1" : [
    {
    "animation" : "talk",
    "text" : "ReplaceMe",
    "speedModifier" : 1.0
    }
    ],
    "2" : [
    {
    "animation" : "talk",
    "text" : "ReplaceMe",
    "speedModifier" : 1.0
    }
    ],
    "3" : [
    {
    "animation" : "talk",
    "text" : "ReplaceMe",
    "speedModifier" : 1.0
    }
    ]
    },
    "techIntro" : [
    {
    "animation" : "talk",
    "text" : "ReplaceMe",
    "speedModifier" : 1.0
    }
    ]
    }
    }
    ]


    This is a basic template, just use it as reference.
    That's it for now for AI creation. I did not really go in depth because creating a custom AI with features like Matter Manipulator editing, custom TechSets or even shipUpgrades deserves its own tutorial.
    And those things are not really species-relevant.

    ========================================================================================

    Next up is creating both an armorpart (we'll take upon a chest) and a weapon (in this tutorial, it's a broadsword).
    This also serves as a basic tutorial of item creation, so I'll go a little in depth here.
    But, hey, what would your custom species be without their own weapons and armors? Booooring.

    So, here the all-trusted example files, this time two at once:


    {
    "itemName" : "florantier1chest",
    "inventoryIcon" : "icons.png:chest",
    "dropCollision" : [-4.0, -3.0, 4.0, 3.0],
    "maxStack" : 1,
    "rarity" : "Common",
    "description" : "It's rare to see a sprout chestguard not covered in dents, blood and sometimes vital organs.",
    "shortdescription" : "Sprout's Chestguard",
    "tooltipKind" : "armor",

    "maleFrames" : {
    "body" : "chest.png",
    "backSleeve" : "bsleeve.png",
    "frontSleeve" : "fsleeve.png"
    },

    "femaleFrames" : {
    "body" : "chest.png",
    "backSleeve" : "bsleeve.png",
    "frontSleeve" : "fsleeve.png"
    },

    "statusEffects" : [
    {
    "stat" : "protection",
    "amount" : 15
    },

    {
    "stat" : "maxEnergy",
    "amount" : 10
    },

    {
    "stat" : "maxHealth",
    "amount" : 8
    }
    ],

    "colorOptions" : [
    /* GREY */
    { "ffca8a" : "b5b5b5", "e0975c" : "808080", "a85636" : "555555", "6f2919" : "303030" },
    /* BLACK */
    { "ffca8a" : "838383", "e0975c" : "555555", "a85636" : "383838", "6f2919" : "151515" },
    /* GREY */
    { "ffca8a" : "b5b5b5", "e0975c" : "808080", "a85636" : "555555", "6f2919" : "303030" },
    /* WHITE */
    { "ffca8a" : "e6e6e6", "e0975c" : "b6b6b6", "a85636" : "7b7b7b", "6f2919" : "373737" },
    /* RED */
    { "ffca8a" : "f4988c", "e0975c" : "d93a3a", "a85636" : "932625", "6f2919" : "601119" },
    /* ORANGE */
    { "ffca8a" : "ffd495", "e0975c" : "ea9931", "a85636" : "af4e00", "6f2919" : "6e2900" },
    /* YELLOW */
    { "ffca8a" : "ffffa7", "e0975c" : "e2c344", "a85636" : "a46e06", "6f2919" : "642f00" },
    /* GREEN */
    { "ffca8a" : "b2e89d", "e0975c" : "51bd3b", "a85636" : "247824", "6f2919" : "144216" },
    /* BLUE */
    { "ffca8a" : "96cbe7", "e0975c" : "5588d4", "a85636" : "344495", "6f2919" : "1a1c51" },
    /* PURPLE */
    { "ffca8a" : "d29ce7", "e0975c" : "a451c4", "a85636" : "6a2284", "6f2919" : "320c40" },
    /* PINK */
    { "ffca8a" : "eab3db", "e0975c" : "d35eae", "a85636" : "97276d", "6f2919" : "59163f" },
    /* BROWN */
    { "ffca8a" : "ccae7c", "e0975c" : "a47844", "a85636" : "754c23", "6f2919" : "472b13" }

    ]
    }



    {
    "itemName" : "floranstarter",
    "dropCollision" : [-4.0, -3.0, 4.0, 3.0],
    "maxStack" : 1,
    "level" : 0.5,
    "rarity" : "legendary",
    "description" : "A broken sword. Looks like a Floran's chewed on it.",
    "shortdescription" : "Broken Venus Sword",
    "tooltipKind" : "sword",
    "weaponType" : "Broadsword",

    "image" : "floranstarter.png",
    "firePosition" : [15.5, 4.5],
    "fireTime" : 0.8,
    "fireAfterWindup" : true,
    "soundEffect" : { "fireSound" : [ { "file" : "/sfx/melee/swing_twohanded.wav" } ] },

    "colorOptions" : [
    /* GREY */
    { "ffca8a" : "b5b5b5", "e0975c" : "808080", "a85636" : "555555", "6f2919" : "303030" },
    /* BLACK */
    { "ffca8a" : "838383", "e0975c" : "555555", "a85636" : "383838", "6f2919" : "151515" },
    /* GREY */
    { "ffca8a" : "b5b5b5", "e0975c" : "808080", "a85636" : "555555", "6f2919" : "303030" },
    /* WHITE */
    { "ffca8a" : "e6e6e6", "e0975c" : "b6b6b6", "a85636" : "7b7b7b", "6f2919" : "373737" },
    /* RED */
    { "ffca8a" : "f4988c", "e0975c" : "d93a3a", "a85636" : "932625", "6f2919" : "601119" },
    /* ORANGE */
    { "ffca8a" : "ffd495", "e0975c" : "ea9931", "a85636" : "af4e00", "6f2919" : "6e2900" },
    /* YELLOW */
    { "ffca8a" : "ffffa7", "e0975c" : "e2c344", "a85636" : "a46e06", "6f2919" : "642f00" },
    /* GREEN */
    { "ffca8a" : "b2e89d", "e0975c" : "51bd3b", "a85636" : "247824", "6f2919" : "144216" },
    /* BLUE */
    { "ffca8a" : "96cbe7", "e0975c" : "5588d4", "a85636" : "344495", "6f2919" : "1a1c51" },
    /* PURPLE */
    { "ffca8a" : "d29ce7", "e0975c" : "a451c4", "a85636" : "6a2284", "6f2919" : "320c40" },
    /* PINK */
    { "ffca8a" : "eab3db", "e0975c" : "d35eae", "a85636" : "97276d", "6f2919" : "59163f" },
    /* BROWN */
    { "ffca8a" : "ccae7c", "e0975c" : "a47844", "a85636" : "754c23", "6f2919" : "472b13" }
    ],

    "primaryStances" : {
    "directional" : false,
    "projectileType" : "testswoosh3",
    "projectile" : {
    "speed" : 0.1,
    "power" : 7.2
    },
    "idle" : {
    "twoHanded" : false,
    "armAngle" : -90,
    "swordAngle" : -90,
    "handPosition" : [-6.0, -17.0],
    "duration" : 0.1
    },
    "windup" : {
    "twoHanded" : true,
    "armAngle" : 90,
    "swordAngle" : 90,
    "handPosition" : [-6.0, -17.0],
    "duration" : 0.05,
    "statusEffects" : []
    },
    "cooldown" : {
    "twoHanded" : true,
    "armAngle" : -45,
    "swordAngle" : -90,
    "handPosition" : [-6.0, -27.5],
    "duration" : 0.4,
    "statusEffects" : []
    }
    },
    "parryBlockCooldown" : 1.2,
    "parrySound" : "/sfx/melee/sword_parry.wav",
    "parryParticle" : "shieldspark",

    "altStances" : {
    "type" : "parry",
    "rescaleTiming" : false,
    "parryPoly" : [ [12, -14], [12, -2], [28, 6], [28, -38], [12, -26] ],

    "idle" : {
    "twoHanded" : false,
    "armAngle" : -90,
    "swordAngle" : -90,
    "handPosition" : [-6.0, -17.0],
    "duration" : 0.1
    },
    "windup" : {
    "twoHanded" : true,
    "armAngle" : 58,
    "swordAngle" : 208,
    "handPosition" : [15.0, -17.0],
    "duration" : 1.0
    },
    "cooldown" : {
    "twoHanded" : false,
    "armAngle" : -90,
    "swordAngle" : -90,
    "handPosition" : [-6.0, -17.0],
    "duration" : 0.1
    }
    }
    }


    So, everything there is basically self-explanatory.
    But just in case, your always trustworthy JSON dictionary:

    "itemName" -- Used to link the item to a recipe / blueprints, case sensitive
    "inventoryIcon" -- Path to the 16x16 .png file that resembles your item
    "dropCollision" -- Nothing to worry about, basically keeps the item from falling through the floor.
    "maxStack" -- Quite obviously the maximum items in one stack. (Usually 1 for Armor and Weapons)
    "rarity" -- Defines the border-color of the item. Viable options: "common", "uncommon", "rare", "legendary"
    "description" -- The description that's shown while hovering over the item
    "shortdescription" -- Items name as shown in-game
    "tooltipKind" -- That's an important one, values are "item", "armor" and weapontype, so "sword" in this case. They got different tooltips, as you might've noticed, for example: Armor shows Effects right next to the pictureframe, Weapons only show their projectile type.

    That's it for now since we'll take a look at the next function, definetly worth a shot getting some insight on:

    "statusEffects".

    This is a function defining the values of your armor.

    Basically, it's an array consisting of Armor, Energy and Health with an extra option to add other status effects.
    Those "other" status effects are the important part, since the basic-trinity (Armor, Energy and Health) is pretty straight forward.
    Effects are defined in the "/assets/stats/effects/" folder.
    You can technically use every effect in there, however, some will screw either balance or the whole game.
    So watch out for that.

    The example above shows the array in a way that's a little confusing, if you're new to modding.
    It actually should look like this:

    "statusEffects" : [
    { "stat" : "protection", "amount" : 15},
    { "stat" : "maxEnergy", "amount" : 10},
    { "stat" : "maxHealth", "amount" : 8},
    {"fullbright"}
    ]

    In this case I added the effect "fullbright" to show how custom statuseffects are usually added to armor.
    It's not that hard, really. Just experiment a bit and find a good combination (you can also add multiple effects on one part).

    Next up: Special lines in the weapon!

    Now, theres this value called "level", 0.5. That's actually the threatLevel index of the weapon (I THINK! I hope that's right).
    A weapons power and energy consumption are defined in a thing called levelingmultiplier.config.
    It uses the same array values like oredistributions.configfunctions, starting from 0.5.

    0,5 -> 1
    1,5 -> 2
    2,5 -> 3
    3,5 -> 4
    4,5 -> 5
    5,5 -> 6

    You don't need to care about the threatLevels up to 10 for now.
    However, keep that in mind when creating a weapon.

    Soundeffects, projectiles, parry mechanics and all that stuff are not needed for a basic species mod, so I will skip out on that. There will eventuall be someone writing a tutorial on half-missing stuff like this, since (imo) only fully explaining weapons doesn't deserve a full tutorial, but it's not a short enough topic to talk that over in here.

    So, I assume you got your weapons now.
    Then I shall link you to another tutorial of mine now, I know that's cheap but it's late and I've been writing this post for 7 hours now.
    This thread explains how to add recipes and how to add blueprints to the player.config.

    Do this now for your whole armorset and your weapon.

    NOTE: Fileformat for armors are as following:

    yourspecies.chest
    yourspecies.legs
    yourspecies.head

    And png's are usually called

    fsleeve.png
    head.png
    icons.png
    mask.png
    pants.png
    bsleeve.png
    chestf.png
    chestm.png

    Keep in mind that all those are spritesheet and the frames are definet in the parent-folder.
    So don't mess up the dimensions! Just like I explained in the species creation up above.

    ===================================================================================

    Now let's get this over with, last topic will be the starting treasure pool.
    Thats basically just what items you find in your shiplocker once you start the char.
    It is UTTERLY important to put a flashlight in there!
    NEVER forget the flashlight, it's a required quest condition to repair S.A.I.L.


    {
    "starterTreasure" : [
    [0, {
    "fill" : [
    {"item" : "flashlight"},
    {"item" : [ "torch", 10 ]}
    ]
    }]
    ],

    "avianStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "aviantier0shortsword", 1]},
    {"item" : [ "avianstarter", 1]}
    ]
    }]
    ],

    "apexStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "apextier0shortsword", 1]},
    {"item" : [ "apexstarter", 1]}
    ]
    }]
    ],

    "humanStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "humantier0shortsword", 1]},
    {"item" : [ "humanstarter", 1]}
    ]
    }]
    ],

    "glitchStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "glitchtier0shortsword", 1]},
    {"item" : [ "glitchstarter", 1]}
    ]
    }]
    ],

    "hylotlStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "hylotltier0shortsword", 1]},
    {"item" : [ "hylotlstarter", 1]}
    ]
    }]
    ],

    "floranStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "florantier0shortsword", 1]},
    {"item" : [ "floranstarter", 1]}
    ]
    }]
    ],

    "novakidStarterTreasure" : [
    [0, {
    "fill" : [
    {"pool" : "starterTreasure"},
    {"item" : [ "novastarter", 1]},
    {"item" : [ "novatier0rifle", 1]}
    ]
    }]
    ]
    }


    Now, this file is really self-explanatory so I won't go on over it.
    One noteable thing is there, tho: Where is this name defined?

    In the blockKey.config in your ships files is the correct answer.
    You noticed earlier, probably, but just in case: Those two files are closely tied together.

    That was a very short topic, but just a reminder, use the patch system!
    I won't add an example for one reason and one reason only:

    All required info can be found above and I want you to learn modding, not copying stuff.
    So, try it yourself till it works, that's the best way to learn.

    ==============================================================================

    And on that note there will be another thing without example.

    "/assets/universe_server.config"

    Open it, study it, create a universe_server.config.patch adding the species itself and link them to the proper shipparts.
    Done? Great. Don't worry now, we're almost done with this ridiculously long tutorial (FML).
    There is one important part left:

    The character creation specifications of your custom race.
    This is really important stuff.
    Here's an example:


    {
    "kind" : "avian",
    "nameGen" : [ "/species/aviannamegen.config:names", "/species/aviannamegen.config:names" ],
    "ouchNoises" : [ "/sfx/humanoid/avianhurt_male1.wav", "/sfx/humanoid/avianhurt_female1.wav" ],
    "gruntNoises" : [ [ "/sfx/humanoid/aviangrunt1.wav", "/sfx/humanoid/aviangrunt2.wav" ], [ "/sfx/humanoid/aviangrunt1.wav", "/sfx/humanoid/aviangrunt2.wav" ] ],
    "charGenTextLabels" : [ "FEATHER COLOR", "PLUMAGE", "SHIRT", "PANTS", "BEAK STYLE", "FLUFF", "SHIRT COLOR", "PANTS COLOR", "AVIAN", "PERSONALITY" ],
    "skull" : "/humanoid/avian/dead.png",
    "defaultBlueprints" : {
    "tier1" : [
    { "item" : "aviantier1hammer" },
    { "item" : "aviantier1shortsword" },
    { "item" : "aviantier1broadsword" },
    { "item" : "aviantier1spear" },
    { "item" : "aviantier1axe" },
    { "item" : "aviantier1dagger" },
    { "item" : "aviantier1head" },
    { "item" : "aviantier1chest" },
    { "item" : "aviantier1pants" },
    { "item" : "avianadventurershirt" },
    { "item" : "avianadventurerpants" },
    { "item" : "aviancommonershirt" },
    { "item" : "aviancommonerlegs" },
    { "item" : "avianfancyshirt" },
    { "item" : "avianfancyskirt" },
    { "item" : "avianworkershirt" },
    { "item" : "avianworkerpants" },

    { "item" : "avianstoragelocker" },

    { "item" : "flagavian" },

    { "item" : "aviantier2hammer" },
    { "item" : "aviantier2shortsword" },
    { "item" : "aviantier2broadsword" },
    { "item" : "aviantier2spear" },
    { "item" : "aviantier2axe" },
    { "item" : "aviantier2dagger" },
    { "item" : "aviantier2head" },
    { "item" : "aviantier2chest" },
    { "item" : "aviantier2pants" },

    { "item" : "aviantier3head" },
    { "item" : "aviantier3chest" },
    { "item" : "aviantier3pants" },
    { "item" : "aviantier3hammer" },
    { "item" : "aviantier3shortsword" },
    { "item" : "aviantier3broadsword" },
    { "item" : "aviantier3spear" },
    { "item" : "aviantier3axe" },
    { "item" : "aviantier3dagger" },

    { "item" : "aviantier4head" },
    { "item" : "aviantier4chest" },
    { "item" : "aviantier4pants" },
    { "item" : "aviantier4hammer" },
    { "item" : "aviantier4shortsword" },
    { "item" : "aviantier4broadsword" },
    { "item" : "aviantier4spear" },
    { "item" : "aviantier4axe" },
    { "item" : "aviantier4dagger" },

    { "item" : "aviantier5head" },
    { "item" : "aviantier5chest" },
    { "item" : "aviantier5pants" },
    { "item" : "aviantier5dagger" },

    { "item" : "aviantier6head" },
    { "item" : "aviantier6chest" },
    { "item" : "aviantier6pants" },
    { "item" : "aviantier6dagger" },

    { "item" : "aviantier7head" },
    { "item" : "aviantier7chest" },
    { "item" : "aviantier7pants" },

    { "item" : "aviantier8head" },
    { "item" : "aviantier8chest" },
    { "item" : "aviantier8pants" },
    { "item" : "aviantier8hammer" },
    { "item" : "aviantier8shortsword" },
    { "item" : "aviantier8broadsword" },
    { "item" : "aviantier8spear" },
    { "item" : "aviantier8axe" },
    { "item" : "aviantier8dagger" },

    { "item" : "aviantier9head" },
    { "item" : "aviantier9chest" },
    { "item" : "aviantier9pants" },

    { "item" : "aviantier10head" },
    { "item" : "aviantier10chest" },
    { "item" : "aviantier10pants" },
    { "item" : "aviantier10hammer" },
    { "item" : "aviantier10shortsword" },
    { "item" : "aviantier10broadsword" },
    { "item" : "aviantier10spear" },
    { "item" : "aviantier10axe" },
    { "item" : "aviantier10dagger" }
    ]
    },

    "headOptionAsFacialhair" : true,
    "altOptionAsFacialMask" : true,
    "bodyColorAsFacialMaskSubColor" : true,
    "altColorAsFacialMaskSubColor" : true,
    "genders" : [
    {
    "name" : "male",
    "image" : "/interface/title/male.png",
    "characterImage" : "/interface/title/avianmale.png",
    "hair" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" ],
    "shirt" : [ "avianadventurershirt", "aviancommonershirt", "avianfancyshirt", "avianworkershirt" ],
    "pants" : [ "avianadventurerpants", "aviancommonerlegs", "avianfancyskirt", "avianworkerpants" ],
    "facialHairGroup" : "fluff",
    "facialHair" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ],
    "facialMaskGroup" : "beaks",
    "facialMask" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ]
    },
    {
    "name" : "female",
    "image" : "/interface/title/female.png",
    "characterImage" : "/interface/title/avianfemale.png",
    "hair" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24" ],
    "shirt" : [ "avianadventurershirt", "aviancommonershirt", "avianfancyshirt", "avianworkershirt" ],
    "pants" : [ "avianadventurerpants", "aviancommonerlegs", "avianfancyskirt", "avianworkerpants" ],
    "facialHairGroup" : "fluff",
    "facialHair" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ],
    "facialMaskGroup" : "beaks",
    "facialMask" : [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ]
    }
    ],
    "bodyColor" : [
    { "ffca8a" : "f0608b", "e0975c" : "cd5061", "a85636" : "95484c", "6f2919" : "6a3836", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eacf60", "a38d59" : "c1a24e", "735e3a" : "977841" },
    { "ffca8a" : "7fdadd", "e0975c" : "61aebf", "a85636" : "4e7a90", "6f2919" : "3f566e", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eacf60", "a38d59" : "c1a24e", "735e3a" : "977841" },
    { "ffca8a" : "add068", "e0975c" : "85ac1b", "a85636" : "6e8210", "6f2919" : "596809", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eacf60", "a38d59" : "c1a24e", "735e3a" : "977841" },
    { "ffca8a" : "f3efa3", "e0975c" : "e3d965", "a85636" : "baa94a", "6f2919" : "98832d", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "efad56", "a38d59" : "c5813e", "735e3a" : "9b6638" },
    { "ffca8a" : "998779", "e0975c" : "836752", "a85636" : "625244", "6f2919" : "4e3b2e", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "efad56", "a38d59" : "c5813e", "735e3a" : "9b6638" },
    { "ffca8a" : "737275", "e0975c" : "595760", "a85636" : "3f3e43", "6f2919" : "212123", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eacf60", "a38d59" : "c1a24e", "735e3a" : "977841" },
    { "ffca8a" : "eebfea", "e0975c" : "de8ddd", "a85636" : "c060bb", "6f2919" : "9a4b9c", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eae660", "a38d59" : "c1b54e", "735e3a" : "978841" },
    { "ffca8a" : "d18bd5", "e0975c" : "a766bc", "a85636" : "814797", "6f2919" : "693367", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "efad56", "a38d59" : "c5813e", "735e3a" : "9b6638" },
    { "ffca8a" : "f3c873", "e0975c" : "db9c38", "a85636" : "b17628", "6f2919" : "89561f", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eae660", "a38d59" : "c1b54e", "735e3a" : "978841" },
    { "ffca8a" : "deeded", "e0975c" : "c5d8d8", "a85636" : "96aba9", "6f2919" : "6f807e", "f32200" : "f6fbfb", "dc1f00" : "d7e8e8", "be1b00" : "8fa7a3", "951500" : "5d6d69", "d9c189" : "eacf60", "a38d59" : "c1a24e", "735e3a" : "977841" }
    ],
    "undyColor" : [ "" ],
    "hairColor" : [ "" ]
    }



    Now, well, this file looks a little complicated at first sight.
    But let's start.
    First, it defines the name of your species.
    Second it implements the namegenerator for your species (yourspeciesnamegen.config in the same directory)
    Then there are the soundeffect-paths. Just copy them as you - most likely - didn't record your own hitNoises.

    "charGenTextLabels" are quite important, compare them to the character creation screen to see which function changes what.
    "skull" is just the dead.png found in your humanoids folder.
    "defaultBlueprints" is the same function that's called in the player.config, but limited to this race. Use this to implement race-specific items.

    "headOptionAsFacialhair" does what it says: It changes the character creators property "Head" to change the facialhair instead.
    "altOptionAsFacialMask" is the same thing, basically, just instead of alternate options (Alt options are used for different things, novakids for example use that for their Belly Button option, iirc)
    "bodyColorAsFacialMaskSubColor" -- Uses the bodyColor (skin color) as a Face-defined color, changing the secondary color of whatever is specified in the directives later on.
    "altColorAsFacialMaskSubColor" -- No need to explain that now, huh?

    All the other options specify the looks and character creation options.
    "facialHairGroup" -- the name of the folder you put your facialHair in (does not REALLY need to be hair, as you can see in this case)
    "facialHair" -- the filenames of available hairstyles
    Basically, once you get that, you should be able to complete the species file, except the directives. That's what we'll get to now.

    So, those are HEX Code-color values.
    The format is as following: { "ActualColorCode" : "ChangedToThisColor"}
    It works just like the "?replace" option in an item's directive option.

    It translates the hexvalues found in the original file-sprite to the 2nd hexcolor you specified and creates an option in the character manager for it.
    Note: It's an array, that means:

    STARTING LINE{"xxx":"xxx"},NEW LINE

    A new line always defines a new directive-collection, translating the same colors you used in the first array entry to new colors.

    SO!
    WE'RE DONE! YES! FINALLY!
    Since this actually took that long and you need the exercise, put the files in the specific folders, including patchfiles, spritesheets, configs and everything you just created (should be really a bunch of files).

    Once you've done that, add a .modinfo file and you're good to go.
    NOTE: You need a mod to extend the vanilla character creation to get your race to show up. I prefer ODB2_Black, but you can use whatever suits you.

    As always, anything missing? Any questions? Just leave me a message or reply to the thread.

    [​IMG]

    Red Panda Approved
     
    Last edited: May 16, 2015
  2. Neon2324

    Neon2324 Scruffy Nerf-Herder

    Where do you put all of these files?
     
  3. Kayuko

    Kayuko Oxygen Tank

    "Since this actually took that long and you need the exercise, put the files in the specific folders, including patchfiles, spritesheets, configs and everything you just created (should be really a bunch of files)."

    %mods%/YourSpecies/YourSpecies.modinfo
    %mods%/YourSpecies/player.config.patch
    %mods%/YourSpecies/universe_server.config.patch
    %mods%/YourSpecies/species/YourSpecies.species
    %mods%/YourSpecies/species/YourNameGen.config
    %mods%/YourSpecies/ships/YourSpecies/<All your ship-files>
    %mods%/YourSpecies/humanoid/YourSpecies/<All your species specific files>²
    %mods%/YourSpecies/recipes/<Random Folder Name>/<All your recipe files>
    %mods%/YourSpecies/items/<Random Folder Name>/<All your item files>
    %mods%/YourSpecies/ai/<All your AI stuff>

    Pay attention to keep order.
    Don't just put recipes and items loosely somewhere, keep a foldersystem so you remember your own files.

    ² This should also contain extra folders, like "hair", "beaks" and all this stuff.
     
    Last edited: May 23, 2015
  4. Neon2324

    Neon2324 Scruffy Nerf-Herder

    thank you but where do you put the ai stuff?
     
  5. Kayuko

    Kayuko Oxygen Tank

    Oh sorry, forgot that.
    Pretty simple tho, all ai-specific files go to:

    /giraffe_storage/mods/YourSpecies/ai/
     
  6. Neon2324

    Neon2324 Scruffy Nerf-Herder

    I have another problem. Sorry. Whenever I create a character from the new race it brings me back to character select where this happens
    moprobemz.PNG
    then when i delete this character this happens
    moprobemz22.PNG
    Did i forget a file or some .patch?
     
  7. Kayuko

    Kayuko Oxygen Tank

    Lol. Really, no idea. Can you send me the modfiles so I can take a look through them to locate the issue?
     
  8. Neon2324

    Neon2324 Scruffy Nerf-Herder

    Okay thanks but how do you upload an actual file to this thread. Sorry about being stupid
     
  9. Kayuko

    Kayuko Oxygen Tank

    Just upload it somewhere else and post the link. :p
    You can't directly attach files like this to a post.
    (Only works for logs, texts and pictures I think)
     
  10. Neon2324

    Neon2324 Scruffy Nerf-Herder

    Last edited: May 23, 2015
  11. Kayuko

    Kayuko Oxygen Tank

    Problem is, you didn't use patches.
    You used full files and just added a ".patch" to the filepath.
    For example, this is your universe_server.config.patch:

    Code:
    {
      "mainWakeupInterval" : 100,
      "workerPoolThreads" : 2,
      "clockUpdatePacketInterval" : 500,
      "clientWaitLimit" : 40000,
      "storageTriggerInterval" : 30000,
      "clearBrokenWorldsInterval" : 5000,
    
      "updateMeasureWindow" : 10000,
      "maxBehindUpdates" : 30,
      "maxUpdateGroup" : 5,
    
      "connectionTimeout" : 30000,
      "acceptTimeout" : 100,
      "maxPendingConnections" : 10,
    
      "worldInactiveShutdown" : 10000,
      "tempWorldDelete" : 600000,
      "passwordSaltLength" : 128,
    
      "speciesShips" : {
        "apex" : ["/ships/apex/apexT0.structure", "/ships/apex/apexT1.structure", "/ships/apex/apexT2.structure", "/ships/apex/apexT3.structure", "/ships/apex/apexT4.structure", "/ships/apex/apexT5.structure", "/ships/apex/apexT6.structure", "/ships/apex/apexT7.structure", "/ships/apex/apexT8.structure"],
        "avian" : ["/ships/avian/avianT0.structure", "/ships/avian/avianT1.structure", "/ships/avian/avianT2.structure", "/ships/avian/avianT3.structure", "/ships/avian/avianT4.structure", "/ships/avian/avianT5.structure", "/ships/avian/avianT6.structure", "/ships/avian/avianT7.structure", "/ships/avian/avianT8.structure"],
        "floran" : ["/ships/floran/floranT0.structure", "/ships/floran/floranT1.structure", "/ships/floran/floranT2.structure", "/ships/floran/floranT3.structure", "/ships/floran/floranT4.structure", "/ships/floran/floranT5.structure", "/ships/floran/floranT6.structure", "/ships/floran/floranT7.structure", "/ships/floran/floranT8.structure"],
        "glitch" : ["/ships/glitch/glitchT0.structure", "/ships/glitch/glitchT1.structure", "/ships/glitch/glitchT2.structure", "/ships/glitch/glitchT3.structure", "/ships/glitch/glitchT4.structure", "/ships/glitch/glitchT5.structure", "/ships/glitch/glitchT6.structure", "/ships/glitch/glitchT7.structure", "/ships/glitch/glitchT8.structure"],
        "human" : ["/ships/human/humanT0.structure", "/ships/human/humanT1.structure", "/ships/human/humanT2.structure", "/ships/human/humanT3.structure", "/ships/human/humanT4.structure", "/ships/human/humanT5.structure", "/ships/human/humanT6.structure", "/ships/human/humanT7.structure", "/ships/human/humanT8.structure"],
        "hylotl" : ["/ships/hylotl/hylotlT0.structure","/ships/hylotl/hylotlT1.structure", "/ships/hylotl/hylotlT2.structure", "/ships/hylotl/hylotlT3.structure", "/ships/hylotl/hylotlT4.structure", "/ships/hylotl/hylotlT5.structure", "/ships/hylotl/hylotlT6.structure", "/ships/hylotl/hylotlT7.structure", "/ships/hylotl/hylotlT8.structure"],
        "novakid" : ["/ships/novakid/novakidT0.structure", "/ships/novakid/novakidT1.structure", "/ships/novakid/novakidT2.structure", "/ships/novakid/novakidT3.structure", "/ships/novakid/novakidT4.structure", "/ships/novakid/novakidT5.structure", "/ships/novakid/novakidT6.structure", "/ships/novakid/novakidT7.structure", "/ships/novakid/novakidT8.structure"],
        "penguin" : ["/ships/novakid/novakidT0.structure", "/ships/novakid/novakidT1.structure", "/ships/novakid/novakidT2.structure", "/ships/novakid/novakidT3.structure", "/ships/novakid/novakidT4.structure", "/ships/novakid/novakidT5.structure", "/ships/novakid/novakidT6.structure", "/ships/novakid/novakidT7.structure", "/ships/novakid/novakidT8.structure"],
        "gargon" : ["/ships/human/humanT0.structure", "/ships/human/humanT1.structure", "/ships/human/humanT2.structure", "/ships/human/humanT3.structure", "/ships/human/humanT4.structure", "/ships/human/humanT5.structure", "/ships/human/humanT6.structure", "/ships/human/humanT7.structure", "/ships/human/humanT8.structure"]
      },
    
      "findStarterWorldParameters" : {
        "tries" : 200,
        "range" : 50,
        "starterWorld" : {
          "terrestrialBiome" : "garden",
          "terrestrialSize" : "small"
        },
        "requiredSystemWorlds" : [
          {
            "terrestrialBiome" : "forest"
          },
          {
            "terrestrialBiome" : "desert"
          },
          {
            "floatingDungeon" : "ancientgateway"
          }
        ]
      },
    
      "commandProcessorScripts" : []
    }
    
    
    This is what it should look like:
    Code:
    [
    {
    "op" : "add", "path" : "/speciesShips/gargon", "value" : ["/ships/human/humanT0.structure", "/ships/human/humanT1.structure", "/ships/human/humanT2.structure", "/ships/human/humanT3.structure", "/ships/human/humanT4.structure", "/ships/human/humanT5.structure", "/ships/human/humanT6.structure", "/ships/human/humanT7.structure", "/ships/human/humanT8.structure"]
    }
    ]
    
    Check all your .patch files and convert them into proper JSON-Patches.
     
    Kajshiki likes this.
  12. Kolovrat 40000

    Kolovrat 40000 Void-Bound Voyager

    Thank you very much for this ^^
     
    Kayuko likes this.
  13. Ziz

    Ziz Void-Bound Voyager

    Hi!
    This is a lovely guide, thank you! I just went through all the grunt work of animating a species from scratch, but I think I've run into the issue of needing to alter head positions through code for a few frames. I've poked at a few race mods but my case can't really be fixed through moving the head on the single sprite sheet.

    I've read that arm positioning was fixed and had taken this into account, but are heads as well? I have the "rough draft" full sheet and can show the vanilla human body layered on it that I used as a guide, if that's needed.

    Thanks!
     
  14. Kayuko

    Kayuko Oxygen Tank

    Looking at the humanoid.config, the headpositions seems to be fixed. Now, there's a thing you could try, but I'd really not recommend it.
    This thing is patching / altering the humanoid.config for new offsets. But as I said, not recommended, firstly because it'd make any vanilla race look awkward, secondly because it can cause unexpected errors.

    Let's say you got the new headposition working (just ignoring the how and why for now) you'd still need to fix the part where the armor is drawn in this specific animation frame, if you wouldn't, it'd look glitchy.
    I'm not sure what exactly you're trying to do, but I'm afraid there's really small to no room in the sprite positioning regarding player body parts.
     
  15. Ziz

    Ziz Void-Bound Voyager

    I was afraid of that. :(

    Here is the sheet in question. Incomplete exported thing (one animation needs to be re-exported!), but... alignment issues. The biggest offender is the swimming one at the bottom -- the head bounces up rather than sinks down on vanilla. The only solution I can think of here is having no head option (like the penguin) and customizing stuff via vanity gear, but that's too limiting for my tastes for something like this. Realigning shouldn't be too awful if it came down to it, but... :<

    EDIT: I thought about it a bit, and I think I have a solution. I'm going to go poking around a bit to see if this is doable, but I was wondering: Is it possible for a wearable to change its color to that of the player's skin tone, etc. when worn?

    EDIT THE SECOND: Would some alteration of this do the trick?
    http://community.playstarbound.com/threads/the-new-directives.95939/
     

    Attached Files:

    Last edited: Aug 2, 2015
  16. ReynoldHughes

    ReynoldHughes Void-Bound Voyager

    Kayuko, you're amazing person for doing this, and I'm sorry I have to ask you a question.

    After following your guide, I've run into a problem: At the character creation screen, my custom race is invisible. The clothes show up, but not the sprites for the character or their hair. At first, I had done a palette swap for Floran colours; I figured that was the issue and changed the hex values back, but the race is still invisible upon trying to create a character.

    Do you have any suggestions?
     
  17. sentiawesome

    sentiawesome Void-Bound Voyager

    Im creating a race with wings on thier back, do I need to edit the sprite map because I dont want it to affect armor
     
  18. Mimaah

    Mimaah Phantasmal Quasar

    I'd add wings to the male and female body sprites, then if you want to add armor to the wings, when you edit the armor sprites, you just have to add a little extra for where the wings are on the body.
     
  19. Flarp987

    Flarp987 Void-Bound Voyager

    i was told to read this but i still have no idea how to locate the spite sheets for novakid or any other species mater-of-fact ;(
     
  20. Mackinz

    Mackinz The Waste of Time

    You have to unpack your assets to see the games raw assets.
     

Share This Page