Lua script for map

I've got an idea for a new map/mode which looks easy to do. But to do it I need to know if its possible to link a lua script to a specific map? This mode/map would be an arena with 2 entrances at opposite sites. One for corruptrons and one for player's crystal. Waves of enemies will spawn as in invasion (cuz I want to do it on invasion). Players will have starting army and their goal is to survive as much as they can. After few waves he could receive new units via lua script.

I think its good improvement for CS, maybe you should make that as an official mode?


  • ShatojonShatojon Administrator Developer Backer Wiki Editor
    Hey Kuzynn!

    Sounds fun. :) I'm going to poke around the studio to get you an answer.

    Sit tight!
  • Garou1337Garou1337 Administrator Developer
    Hi Kuzyn,

    So from what I understand, you want to create a modded version of invasion in a custom map, is that correct? If that is the case, you cannot exactly "link" a lua script to a specific map, but rather create a custom game mode that you then modify to your liking, which you can then design for a specific map.

    If you're not familiar with the procedure to create a custom game mode, I'll be happy to help you with that and the mod idea you have in mind.
  • Garou1337 said:

    Hi Kuzyn,

    So from what I understand, you want to create a modded version of invasion in a custom map, is that correct? If that is the case, you cannot exactly "link" a lua script to a specific map, but rather create a custom game mode that you then modify to your liking, which you can then design for a specific map.

    If you're not familiar with the procedure to create a custom game mode, I'll be happy to help you with that and the mod idea you have in mind.

    If you can write something about this, I'll be very happy ^^Anyway I think that could be a great and simple addition to Castle Story.
    • Arena map (like colosseum made with stone bricks, without exits).
    • Starting point for player and enemy spawn.
    • No respawns for player.
    • Every wave of x waves player gets a random unit or a choice what he wants.
    • Player can't build etc. just fight.
    • The goal is to survive the highest wave.
    • Player lose when lost all units.
    So it's like invasion but just about fighting. Just a small addon.
    Also, the idea can be expanded to have something like few arenas connected and with every x lvls the new part is open and now you have to defend from 2 sides etc.
  • Garou1337Garou1337 Administrator Developer
    Alright, well first, are you familiar with the LUA programming language? Or programming in general?
    A couple things in your mod idea would require you to go in the game modes files and modify part of the user interface, for example to give the option to the player to choose a unit at the end of a wave.

    But first, you would have to create a new custom game mode:
    - Choose a gamemode amongst the ones listed there, for example, Invasion. Copy the entire folder and rename it. It has to be in the actual "Castle Story\Info\Lua\Gamemodes" path where you put it to work.
    - Go inside it and open the "meta" file.
    - Give a new codename like "CODENAME": "invasion2",
    - Give it a new display name, just so you can spot it in the gamemode choices while you've got your map selected.
    - After that, go in the "Preset" folder.
    - pick one to be a new preset for your gamemode (you can deleta the other presets, or modify several of them if you so choose). Make sure you change the codename so it matches the codename you have given to your gamemode earlier:
    "CODENAME" : "invasion2_default",
    "__DISPLAYNAME" : "Default",

    You now have created a new gamemode that you can modifiy to your liking. if you look around in the files that are at the root of your new gamemode (where you find meta, factions, RaidPresets, etc), you'll find some files that you can easily modify to change the gamemode experience.

    The config file lets you modify several parameters like the starting time of day, the wave number, wave intervals, whether you can dig the ground or not and the Bricktrons you start with. The RaidPresets file will let you customize the enemy waves that come knocking at your door.

    For the map, well, it's simple enough. Make the map to your liking in the World Editor and save it. Since your game mode works on the same principles as Invasion, you can put just the necessary markers in to satisfy the Invasion criteria.

    After that, go in your map in SandBox and build any stone blocks that you want to build your colosseum. When done, save your game. If you go in the folder where your saved games are, you'll be able to open the one which corresponds to the game that you just played (castlestory-game\Info\Saves\YourGame). It should contain a "PlacedBlocks" JSON file. Copy it and put it in your map folder (castlestory-game\Info\UGC\Maps\YourMap), basically putting the blocks as a permanent feature of the map.

    Once you've got that we can look at putting in more specific features. Let me know if you have trouble with the aforementioned steps.
  • I will try that, thanks =)
  • @Garou1337
    Okay, I've got the map and mode. Could you explain me how to do:
    - spawn friendly knight/archer/arbalest etc. at home crystal after X wave
    - do not let corruptrons destroy blocks/structures (crystal destroyable)
  • Garou1337Garou1337 Administrator Developer
    Hi again, and sorry for the delay.

    Alright, for the second part of your question, this is pretty straightforward. Now assuming you haven't renamed all the files in your custom game mode, here is what you need to do:
    - Go in castlestory-game/Info/Lua/Gamemodes/(yourCustomGamemode)/invasion.lua
    - At line 30, add this:
    spawnCrystal.isInvincible = true

    To make the ground and blocks non destroyable, go in your preset file that you have created for your gamemode, and change this:

    --Global Settings
    canDigGround = true,


    --Global Settings
    canDigGround = false,

    Now, I'm pretty sure this will work correctly, but while looking through our files, I spotted that this rule referenced a list of blocks through ID to each set them destroyable or not individually. So, it could be the case that some of the newer blocks have been omitted from that list and are still destroyable. I doubt this would be a concern, but if you ever find Corruptrons destroying blocks they shouldn't, just mention it here and I'll make the necessary adjustments so it doesn't happen anymore.

    Also, this would also mean that any block that you place during the course of the game would be indestructible, even if you tell your Bricktron to destroy them manually (although this is probably what you intended anyway).

    I'll answer part one of your question in a subsequent post.
  • Garou1337Garou1337 Administrator Developer
    edited March 1
    For the first part of your question, this will require a little bit more work.

    Again, open the same file castlestory-game/Info/Lua/Gamemodes/(yourCustomGamemode)/invasion.lua.

    If you go look at the first function in that file:

    function _InitInvasion()

    You'll see some examples of how to spawn Bricktrons at around line 35-40 or so:

    for i = 1, sv_Settings.startingWorkersCount do
    fy_Bricktron:New(faction, Random.VoxelAround(spawnPoint.position))
    for i = 1, sv_Settings.startingKnightCount do fy_Bricktron:New(faction,Random.VoxelAround(spawnPoint.position)):SetOccupation(Occupations.Knight)

    To spawn a Bricktron, you just need to call the function fy_Bricktron:New and pass it two arguments like so:
    fy_Bricktron:New(yourFaction, positionYouWant)

    If we want to make this work properly, we will need to modify a couple things. First:
    - Just before the function _InitInvasion(), add this:
    local factions = {}
    local spawnPoints = {}
    local playerSpawnPoint = nil
    local playerFaction = nil

    - then, in the function itself, change these two lines:
    local factions = Faction:GetAll()
    local spawnPoints = Markers.GetGroup("Player Starting Point")

    To this: (basically just removing the local before these variables)
    factions = Faction:GetAll()
    spawnPoints = Markers.GetGroup("Player Starting Point")

    What we just did there was to allow these variables to "exist" outside the local scope, so we can refer to them later when we make the algorithm that spawns Bricktrons.
    After that, add these two lines: (still in that _InitInvasion() function)

    if #spawnPoints == 0 then
    error("No spawnpoints in map")
    for x, faction in pairs(factions) do
    if faction:HasOwner() then
    playerFaction = faction <------ here
    local spawnPoint = spawnPoints[1] --math.random(#spawnPoints)
    playerSpawnPoint = spawnPoint <------ and here
    spawnCrystal = fy_Crystal:New(faction, spawnPoint.position)
    spawnCrystal.isFireflyHome = true
    spawnCrystal.doCrystalBrew = true;

    Now we're ready to spawn those Bricktrons.
    Where we put the spawn largely depends on what you intend to do exactly, but for the purpose of this exercise I'll assume you want them to appear right as you finish a wave. If that is the case, you can put the spawning function at line 82-83, in the _InvasionTrack() function :

    if fy_RaidProject:CountOfFaction(CorruptedFaction) == 0 then
    livingBaddies = false
    KuzynBricktronSpawnFunction(Registry.waveSurvived) <----- here

    The next step is to actually implement the function. It doesn't really matter where in the file as long as it is not inside another function, but you can just put it around line 114, just before the PlayerLost() function:

    if _wavesSurvived == 1 then
    fy_Bricktron:New(playerFaction, Random.VoxelAround(playerSpawnPoint.position))

    This is the simplest implementation and will tell you if all of the above works (I tested it here and it does, so failure to work might indicate a mistake in one of the aforementionned steps). If it does, this should make a Bricktron appear as soon as you defeat the first wave!

    From there you're free to adjust the spawning to your liking. You could just keep adding if statements like so:

    if _wavesSurvived == 2 then
    fy_Bricktron:New(playerFaction, Random.VoxelAround(playerSpawnPoint.position)):SetOccupation(Occupations.Knight)
    if _wavesSurvived == 3 then
    fy_Bricktron:New(playerFaction, Random.VoxelAround(playerSpawnPoint.position)):SetOccupation(Occupations.Archer)

    This is easy to understand and modify and will get the job done. However, you might want to use a different approach where you store data in a table, and you just read that table index to determine what you are gonna spawn on any given wave.
    You could also use a different approach where you use a kind of "Bricktron Budget" for waves and have an algorithm spawn them based on some predetermined value allocated per class.

    If you're not sure how to do that, you can always read on the lua language on the web, or ask me here for pointers on how to proceed with your chosen approach.

  • kuzynnkuzynn Member Backer
    Thank you for help! I hope that I will make it work during this weekend.
Sign In or Register to comment.