Tutorial Lua Mod Tutorial - #1 Simple Spawner

Discussion in 'Starbound Modding' started by APXEOLOG, Dec 9, 2013.

  1. APXEOLOG

    APXEOLOG Void-Bound Voyager

    Hello, this is my first tutorial about scripting custom logic with lua.
    In this tutorial we will create simple mod - monster spawner.

    *I may mistake in some moments, feel free to correct me. There also may be some text mistakes since i'm not a native speaker. Any feedback/questions appreciated!*

    1. Basic mod structure
    Since the game loads files from every directory in 'asset' folder i recommend you to create special folder for you mode, where you can store all files.
    I've used Starbound/assets/mods/apx_beacondefence/ (you may need to create 'mods' folder too)

    2. Creating spawner object
    Most of text-based assets are represented in JSON. It has very simple format, but if you not sure you can always check yourself with validator like http://jsonlint.com/
    There are nubmer of types like 'object', 'item', 'recipe' etc, specified by file extension.
    For now only wired objects can be used with lua script so we will create this one.
    Create object file in mod folder and open it with any text editor. I've created alienbeacon.object file (so full path looks like assets/mods/apx_beacondefence/alienbeacon.object now).

    I've used Iron Beacon (assets/objects/boss/ironbeacon.object) as a source for my object, after a short editing it looks like
    Code:
    {
      "objectName" : "alienbeacon",
      "rarity" : "Common",
      "objectType" : "wire",
      "description" : "Prepare for repair!",
      "shortdescription" : "Alien Beacon",
      "race" : "generic",
      "category" : "tools",
      "printable" : "false",
    
      "inventoryIcon" : "/objects/boss/ironbeaconicon.png",
      "orientations" : [
        {
          "dualImage" : "/objects/boss/ironbeacon.png:<color>.<frame>",
    
          "imagePosition" : [-16, 0],
          "frames" : 12,
          "animationCycle" : 2,
    
          "spaceScan" : 0.1,
          "anchors" : [ "bottom" ]
    
        }
      ],
    
      "animation" : "/objects/wired/ironbeacon/ironbeacon.animation",
      "animationParts" : {
        "beacon" : "/objects/boss/ironbeacon.png"
      },
      "animationPosition" : [-16, 0],
    
      "scripts" : [ "/mods/apx_beacondefence/alienbeacon_logic.lua" ],
      "scriptDelta" : 5
    }
    
    Now let's explain every property:
    objectName - this is an internal name of this object. This name should be uniq through all items and object so don't enter obvious names. Later we will use this name in the recipe
    rarity - rarity of object. For example you can write 'Legendary' here
    objectType - since lua works only with 'wire' objects now, this is what we place here.
    description - craft description
    shortdescription - this is the name which shown in the tooltip
    race - race-based restrictions. Leave 'generic' for no restrictions
    category - category of object. Just leave a 'tool'
    printable - set "true" if you want this item to be printable with 3D printer (note - you also should specify price then)
    inventoryIcon, orientations, animation, animationParts, animationPosition - this attributes specify all graphics and animation of this object. I've just copied this values from the Iron Beacon
    scripts - path to lua script (note - always specify absolute path here)
    scriptDelta - i'm not sure what it is actually, but i think it is update time (in millisec). 5 is default for most scripts

    *Some notes about paths*
    If you have image file in the same directory with object file, you can specify only it's name, without path. But this doesn't works with lua scripts - you should always specify absolute path for them.


    3. Creating recipe
    Ok now we have spawner object, but we need to get it ingame somehow. If you want to use other methods like quest rewards etc you can go to next section.
    Let's create alienbeacon.recipe file (assets/mods/apx_beacondefence/alienbeacon.recipe)
    Code:
    {
      "input" : [
        { "item" : "ironbar", "count" : 10 }
      ],
      "output" : {
        "item" : "alienbeacon",
        "count" : 1
      },
      "groups" : [ "plain", "all", "other" ]
    }
    
    Recipe definition is pretty easy.
    input - craft cost. any item resource can be specified here by it's objectName (you can find items in the assets/items/ folder)
    output - what we receive. Here we place objectName of our Alien Beacon.
    groups - craft gorup. Use 'plain' if you want this recipe in the default players craft menu, or for example 'anvil'.

    Also we should add this recipe as default blueprint to allow crafting. Edit player.config in the asset folder, search defaultBlueprints / tier1 (line 26 currently) and add alienbeacon there, so the code will looks like
    Code:
      "defaultBlueprints" : {
        "tier1" : [
          { "item" : "alienbeacon" },
          { "item" : "copperarmorhead" },
          { "item" : "copperarmorchest" },
          ....
    Now you can craft this object ingame.

    4. Lua scripting
    Ok now we are ready for the most interesting part of this tutorial :)
    This game use LUA as a scripting language. It's syntax is pretty easy, and you don't need much knowledge since most of default packages (like io) are removed.
    Create lua file. For me it is alienbeacon_logic.lua. Don't forget to change script path in .object file if you will change script name.
    Now add some default methods into it
    Code:
    function main()
    end
    
    function init(args)
    end
    There are some default function wich are called by the game.

    init() - this function is called by game evey X millisec while you are placing this object
    [​IMG]
    (init phase)

    main() - this function is called by game evey X millisec after you've placed this object.
    [​IMG]
    (main phase)

    There are also some more functions, but this two are default.

    You can also use default Iron Beacon's lua script as a sample (you can find it here: assets/objects/wired/ironbeacon/ironbeacon.lua)

    *Lua supports comment using '--', so you can see some information tooltips inside code*
    *You can see differences between my code and original one. I write in a way i think is right, you may choose other ways*

    4.1 Hello world!
    Let's start with a Hello world script of course!
    Code:
    function init(args)
        world.logInfo("Hello world!");
    end
    We use world.logInfo() to print text into log file (Starbound/starbound.log). You can use this method to debug state of your scripts, or print any info. Now you can start the game, craft Alien Beacon, select it, and watch log file. You should see lot's of Hello world! strings at the end of it (remember that init function executes every X milisecs!)

    4.2 Object Initialization
    First of all let's add 'rotation' animation to our beacon when it's placed (like original iron beacon) and make it usable. To make this let's modify main method:
    Code:
    function main()
        -- Check for the single execution
        if self.initialized == nil then
            -- Init object
            initializeObject();
            -- Set flag
            self.initialized = true;
        end
    end
    
    function initializeObject()
        -- Make our object interactive (we can interract by 'Use')
        object.setInteractive(true);
        -- Change animation for state "active"
        object.setAnimationState("beaconState", "active");
    end
    
    I use default global self variable to store information about this beacon. self is a global metatable, uniq for this instance of object. For example if you have 2 beacons, they have different self tables. I check self.initialized variable, and if it is nil (undefinded), i initialize object and define this variable. It guarantees signle execution of initializeObject() function.

    Inside initializeObject() function we use another global variable - object. object is a link to current entity. There are number of functions, availiable for such global variables like object, world, entity (for monster behavior only). You can find full function list here, i will try to make docs with arguments and explanation later.

    object.setInteractive(true); - obviously this function allows interaction with our object.

    object.setAnimationState(); - this function set current animation state of the object. You can see all animation states in the .animation file (for us it is assets/objects/wired/ironbeacon/ironbeacon.animation)


    4.3 Interaction response
    Ok in the previous part we've set our object interactive. Now we can define onInteraction() function. This function is called by the game every time you interact with object (press 'E')
    Code:
    function onInteraction(args)
        return { "ShowPopup", { message = "Hello world 2! :)" } };
    end
    This code will create popup window each time you interact with object. If you don't want to create popups you can just remove return, or return nil

    4.4 Give me something real now!
    Okay okay, now time to create something real!
    Monster spawning is actually very easy.
    Code:
    function onInteraction(args)
        -- Spawn monster
        world.spawnMonster("serpentdroid", object.toAbsolutePosition({ 0.0, 5.0 }), { level = 10 });
    end
    
    First argument of world.spawnMonster() function is monster name. serpentdroid is a mosnter from assets/monsters/unique/. Second argument is position, object.toAbsolutePosition({ 0.0, 5.0 }) creates new position, relative to position of object (beacon for us) but with offset (0, 5). Note that game use left-bottom-corner coordinate system, so (0, 5) will spawn monter above the beacon.
    Third argument is a table that specifies some parameters of new monster (for us it is level)

    [​IMG]

    Now our monster spawner works fine.

    You can download sample here: http://puu.sh/5H5QZ/04dd08fac1.zip. Simply extract it into assets/mods/ (create mod folder if needed) to make full path like assets/mods/apx_beacondefence/
    (Don't forget to add alienbeacon in the player.config - watch stage #3)

    In next lesson i will tell about scripting monster behavior and some other features. Stay tuned :)
     
    Last edited: Dec 9, 2013
  2. Ghoul159

    Ghoul159 Scruffy Nerf-Herder

    nice tutorial! :)
     
    Last edited: Dec 9, 2013
  3. dharke82

    dharke82 Intergalactic Tourist

    Awesome!
    thank you, very easy to understand.. will keep an eye out for your next one..
    also is there any where that i can find all the commands/arguments/ functions that starbound Lua is compatible with?
     
  4. APXEOLOG

    APXEOLOG Void-Bound Voyager

    There's no official lua API yet, but you can find some information here, or in the native lua scripts.
     
    dharke82 likes this.
  5. dharke82

    dharke82 Intergalactic Tourist

    cool thank you.. muchly appreciated
     
  6. krail

    krail Void-Bound Voyager

    Nice guide, do you know if there's a function for spawning furniture?
     
  7. APXEOLOG

    APXEOLOG Void-Bound Voyager

    For now you can only spawn monsters and npcs.
     
  8. sarcose

    sarcose Scruffy Nerf-Herder

    Does this lua API support arrays? Is it possible to spawn a random monster from said array?

    Can I have the object move around erratically and spawn monsters on its own?

    These are important questions. For science.

    Edit: also, can I apply a velocity to the spawned monster, and can I track the monster after spawn with a thingID?
     
    Last edited: Dec 12, 2013
  9. to correct your quote about Main() being run every so milliseconds... Its actually ever number of ticks. The game runs at 60 ticks a second, so a deltaScript of 5 means every 5 ticks, or ever 5/60ths of a second.

    also, instead of having an initializeObject, just put that code in the init(args) function and let that handle it.
     
  10. APXEOLOG

    APXEOLOG Void-Bound Voyager

    The problem is that it will be done multiple times (for objects at least). I know there's no difference, because it will be done before main cycle, but if i want code to be done once, i prefer to do it once.

    Yes, tables are equal to arrays in lua. Yes it is possible to spawn random monster. You cannot move object atm (only if it is tech...), but you can spawn monsters on it's own.
    Yes, you can set velocity and track target.

    I will make next tutorial for monsters soon, just testing some things atm.
     
  11. petecz

    petecz Star Wrangler

    Really nice tutorial, thanks.;)
     
  12. ClockworkRose

    ClockworkRose Poptop Tamer

    ^^
     
  13. Shadestyle

    Shadestyle Scruffy Nerf-Herder

    Is there a way to make it spawn Randomized monsters?
     
  14. Krejgo

    Krejgo Void-Bound Voyager

    Yes you can, simply change the name of monster in the Lua code to any monster types. Some of that monster type is : smallbiped, tallbiped, quadruped, and many others ...
    To find what monstertypes are available to be put into the code, you have to look in the Starbound/assets/monsters, open any ".monstertype" files inside the in a notepad -or other software- and look the 'type' name there, it usually in the top line.

    So the code is going to be like this
    world.spawnMonster("smallbiped", object.toAbsolutePosition({ 0.0, 5.0 }), { level = 10 });

    test it , and it gonna spawn random small bipeds monsters :D
    sorry for my bad english though.. >.<
     
  15. Applesaur

    Applesaur Space Hobo

    Last edited: Jan 6, 2014
  16. djpooppants

    djpooppants Space Hobo

    Really great tutorial. Thanks so much for making it.

    The only problem I ran in to was I had to change all of the "object" variables to "entity" in the lua script.
     
    lornlynx likes this.
  17. Daniel345

    Daniel345 Subatomic Cosmonaut

    Sorry for the necro, but I'm having some problems trying to make an item printable. When I place the item on the 3d printer, it reconizes it's price, but when I press 'scan', nothing happens, could you tell what am I doing wrong here?
     
  18. HarrisonG

    HarrisonG Scruffy Nerf-Herder

    that actually happens to me even for default in-game items.. idk why
     
  19. Gunterman5

    Gunterman5 Void-Bound Voyager

    you can find a list of all the Starbound API in /Starbound/docs/lua
     
  20. lazarus78

    lazarus78 The Waste of Time

    You replied to a nearly 4 year old post of someone who hasn't been on in an equally as long time.
     

Share This Page