Garry's Mod

Garry's Mod

Not enough ratings
Sourcegrind - Making your own Patterns
By Diamondus_Frvr
This is how you can make your own custom patterns for the Sourcegrind addon. Check out the addon here: https://steamhost.cn/steamcommunity_com/sharedfiles/filedetails/?id=3493225988
   
Award
Favorite
Favorited
Unfavorite
Understanding the basics
Requirements:
- A text editor (Notepad++ recommended).
- Very minor knowledge of Lua.

Here is what you need to know about making your Pattern:

The map consists of 10x10 blocks that you can set to specific heights

Each pattern consists of 2 things: A Geometry map and a Spawn map. The Geometry map will define how the Pattern will physically look like. The Spawn map will define what type of enemies can spawn where. Both of the maps are stored as a 10x10 large 2D list. You will be required to define both to be able to create a Pattern.

The Spawn map will require something called the Spawnpool list. The Spawnpool list is a list which contains certain spawnpools for a certain block. You can use the default pools, but ideally you want to extend on this to be able to fully customize your level.

To get started, go to gmod's lua folder. By default this is going to be:
C:\Program Files (x86)\Steam\steamapps\common\GarrysMod\garrysmod\lua
Create a folder called "sourcegrind" here. This is where you will define the custom Patterns in.
Creating your Spawnpools
As said, it is not required to create your Spawnpool list, but it is recommended to do so.

To get started, create a new file in the sourcegrind folder called "custom_spawnpools.lua". It's important that the name matches exactly!

Here we will want to define the enemies we want to appear in our Patterns. First, add the import of the Spawnable table, that is used to define enemies in the Sourcegrind
local Spawnable = include("sourcegrind/spawnable.lua")

Next, we can begin adding our Spawnables. Here is an example of what a Spawnable looks like:
local PoisonZombie = Spawnable:new("npc_poisonzombie", -- Classname of NPC -- Pre Spawn Action function(ent) -- Makes the Poison Zombie like the Combine soldiers ent:AddRelationship("npc_combine_s D_LI 99") -- Makes the Poison Zombie like the Metrocops ent:AddRelationship("npc_metropolice D_LI 99") -- Makes the Poison Zombie like the Manhacks ent:AddRelationship("npc_manhack D_LI 99") end, -- Post Spawn Action function(ent) ent:SetHealth(100) -- Self explanitory ent:SetMaxHealth(100) end )
- The Classname is the classname of the NPC that you want to spawn. You can even write NPC classnames from different addons aswell.
- The Pre Spawn Action is the code that runs BEFORE the NPC is spawned. Most of the code will have to go here, like adding weapons, defining relationships with other NPCs etc.
- The Post Spawn Action runs RIGHT AFTER the NPC is spawned. This is most useful for SetHealth, because that can only be set after the NPC has spawned.

Note that defining the Pre and Post Spawn action is not required, but it is advised to at least add the relationship to NPCs that would otherwise attack each other

Once we defined some Spawnables, we need to put them into a Spawnpool list. A Spawnpool is a list of Spawnables that we want to spawn on a block. We return with this list. Optionally, place a print to be able to verify that that the custom Spawnpool list has been loaded

For example, if we defined Metrocop, Soldier, PoisonZombie then we can define a Spawnpool list like this:
print("Custom Spawnpool list loaded!") return { {Metrocop, Soldier}, -- 1: soldiers {PoisonZombie} -- 2: poison zombie }
This means, that on our Patterns, we can place blocks where on 1 either Metrocop OR Soldier can spawn, and where we put 2, PoisonZombies can spawn only.

Here is what the default spawnpools look like:
-- custom_spawnpools.lua local Spawnable = include("sourcegrind/spawnable.lua") local Metrocop = Spawnable:new("npc_metropolice", function(ent) ent:AddSpawnFlags(8192) -- Do not drop weapons ent:RemoveSpawnFlags(8) -- Drop healthkit (disabled) ent:SetKeyValue("additionalequipment", "weapon_pistol") ent:AddRelationship("npc_headcrab_fast D_LI 99") ent:AddRelationship("npc_headcrab_black D_LI 99") ent:AddRelationship("npc_poisonzombie D_LI 99") end) local Soldier = Spawnable:new("npc_combine_s", function(ent) ent:AddSpawnFlags(8192) -- Do not drop weapons ent:RemoveSpawnFlags(8) -- Drop healthkit (disabled) ent:AddSpawnFlags(131072) -- Do not drop grenades ent:SetKeyValue("additionalequipment", "weapon_smg1") ent:AddRelationship("npc_headcrab_fast D_LI 99") ent:AddRelationship("npc_headcrab_black D_LI 99") ent:AddRelationship("npc_poisonzombie D_LI 99") end) local FastCrab = Spawnable:new("npc_headcrab_fast", function(ent) ent:AddRelationship("npc_metropolice D_LI 99") ent:AddRelationship("npc_combine_s D_LI 99") ent:AddRelationship("npc_manhack D_LI 99") end) local PoisonZombie = Spawnable:new("npc_poisonzombie", function(ent) ent:AddRelationship("npc_combine_s D_LI 99") ent:AddRelationship("npc_metropolice D_LI 99") ent:AddRelationship("npc_manhack D_LI 99") end, function(ent) ent:SetHealth(100) ent:SetMaxHealth(100) end ) local Manhack = Spawnable:new("npc_manhack", function(ent) ent:AddRelationship("npc_headcrab_fast D_LI 99") ent:AddRelationship("npc_headcrab_black D_LI 99") ent:AddRelationship("npc_poisonzombie D_LI 99") end) return { {Metrocop, Soldier}, -- 1: default {FastCrab, PoisonZombie}, -- 2: zombie {Manhack} -- 3: manhack }
Creating Map Patterns
Now that we have Spawnpools, we can define the Map Patterns. In the sourcegrind folder, create a new file called "custom_patterns.lua". Again, this must match exactly!

First, we import the MapPattern table:
local MapPattern = include("sourcegrind/mappattern.lua")

Then, we can start creating our Map Patterns. Here is one an existing Map Pattern (the one you see on the Workshop thumbnail GIF):
local map0 = MapPattern:new( "Fort", -- Name of the Pattern "Frvr", -- Creator of the Pattern { {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, -- Geometry Map {0.00, 0.40, 0.03, 0.03, 0.40, 0.40, 0.03, 0.03, 0.40, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.40, 0.00, 0.00, 0.00, 0.50, 0.00, 0.00, 0.40, 0.00}, {0.00, 0.40, 0.00, 0.00, 0.50, 0.00, 0.00, 0.00, 0.40, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.40, 0.03, 0.03, 0.40, 0.40, 0.03, 0.03, 0.40, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00} }, { {0, 0, 0, 0, 2, 2, 0, 0, 0, 0}, -- Spawnpool Map {0, 3, 0, 0, 3, 3, 0, 0, 3, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {2, 3, 1, 1, 1, 3, 1, 1, 3, 2}, {2, 3, 1, 1, 3, 1, 1, 1, 3, 2}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 3, 0, 0, 3, 3, 0, 0, 3, 0}, {0, 0, 0, 0, 2, 2, 0, 0, 0, 0} } )

The Name and Creator should be the name and the creator of the pattern (currently, this doesn't matter, but it is for a potential future update).
The Geometry Pattern will define how far the blocks will stick out from the ground in the pattern. This is a number between 0.00 and 1.00 where 1.00 is 512 in game units higher than the default height.
The Spawn Pattern is the pattern where we define which Spawnpool should be used for our block. This represents the index of the item in the Spawnpool list that we defined earlier (Lua indexes begin at 1!).
0 means that no enemy can spawn on that block. It is required to have at least 1 block be an existing Spawnpool index, or the map will softlock! Ideally you should have at least more than 10-15 blocks spawn an enemy on each pattern you make.

Once you defined your maps, all you have to do, is return with it in a list. Optionally, print a message to verify in game that it loaded correctly:
print("Custom patterns loaded!") return { map0, map1, map2, map3 }

You must have at least 2 Patterns or the map will break!

Here is the default Patterns. Simply copy paste and extend on them if you want to have them included.
-- custom_patterns.lua local MapPattern = include("sourcegrind/mappattern.lua") -- Must Have local map0 = MapPattern:new( "Fort", "Frvr", { {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.40, 0.03, 0.03, 0.40, 0.40, 0.03, 0.03, 0.40, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.40, 0.00, 0.00, 0.00, 0.50, 0.00, 0.00, 0.40, 0.00}, {0.00, 0.40, 0.00, 0.00, 0.50, 0.00, 0.00, 0.00, 0.40, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.00}, {0.00, 0.40, 0.03, 0.03, 0.40, 0.40, 0.03, 0.03, 0.40, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00} }, { {0, 0, 0, 0, 2, 2, 0, 0, 0, 0}, {0, 3, 0, 0, 3, 3, 0, 0, 3, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {2, 3, 1, 1, 1, 3, 1, 1, 3, 2}, {2, 3, 1, 1, 3, 1, 1, 1, 3, 2}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 3, 0, 0, 3, 3, 0, 0, 3, 0}, {0, 0, 0, 0, 2, 2, 0, 0, 0, 0} } ) local map1 = MapPattern:new( "Mortar", "Frvr", { {0.50, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.50}, {0.06, 0.03, 0.03, 0.00, 0.00, 0.00, 0.00, 0.03, 0.03, 0.06}, {0.06, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.06}, {0.06, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.06}, {0.06, 0.00, 0.00, 0.00, 0.50, 0.50, 0.00, 0.00, 0.00, 0.06}, {0.06, 0.00, 0.00, 0.00, 0.50, 0.50, 0.00, 0.00, 0.00, 0.06}, {0.06, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.06}, {0.06, 0.03, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.03, 0.06}, {0.06, 0.03, 0.03, 0.00, 0.00, 0.00, 0.00, 0.03, 0.03, 0.06}, {0.50, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.06, 0.50} }, { {3, 2, 2, 2, 2, 2, 2, 2, 2, 3}, {2, 2, 2, 1, 1, 1, 1, 2, 2, 2}, {2, 2, 1, 1, 1, 1, 1, 1, 2, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 3, 3, 1, 1, 1, 2}, {2, 1, 1, 1, 3, 3, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 2, 1, 1, 1, 1, 1, 1, 2, 2}, {2, 2, 2, 1, 1, 1, 1, 2, 2, 2}, {3, 2, 2, 2, 2, 2, 2, 2, 2, 3} } ) local map2 = MapPattern:new( "The Stairway", "Frvr", { {0.78, 0.00, 0.00, 0.00, 0.00, 0.03, 0.06, 0.09, 0.12, 0.12}, {0.75, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.12}, {0.72, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.15}, {0.69, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.18}, {0.66, 0.00, 0.00, 0.00, 0.70, 0.70, 0.00, 0.00, 0.00, 0.21}, {0.63, 0.00, 0.00, 0.00, 0.70, 0.70, 0.00, 0.00, 0.00, 0.24}, {0.60, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.27}, {0.57, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.30}, {0.54, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.33}, {0.54, 0.54, 0.51, 0.48, 0.45, 0.42, 0.39, 0.36, 0.33, 0.33} }, { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 3, 2, 2, 2, 2, 2, 2, 3, 1}, {1, 2, 2, 2, 2, 2, 2, 2, 2, 1}, {1, 2, 2, 2, 2, 2, 2, 2, 2, 1}, {1, 2, 2, 2, 1, 1, 2, 2, 2, 1}, {1, 2, 2, 2, 1, 1, 2, 2, 2, 1}, {1, 2, 2, 2, 2, 2, 2, 2, 2, 1}, {1, 2, 2, 2, 2, 2, 2, 2, 2, 1}, {1, 3, 2, 2, 2, 2, 2, 2, 3, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1} }) local map3 = MapPattern:new( "The Park", "Frvr", { {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.70, 0.70, 0.70, 0.00, 0.00, 0.70, 0.70, 0.70, 0.00}, {0.00, 0.70, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.70, 0.00}, {0.00, 0.70, 0.00, 0.40, 0.40, 0.40, 0.40, 0.00, 0.70, 0.00}, {0.00, 0.00, 0.00, 0.40, 0.70, 0.70, 0.40, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.40, 0.70, 0.70, 0.40, 0.00, 0.00, 0.00}, {0.00, 0.70, 0.00, 0.40, 0.40, 0.40, 0.40, 0.00, 0.70, 0.00}, {0.00, 0.70, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.70, 0.00}, {0.00, 0.70, 0.70, 0.70, 0.00, 0.00, 0.70, 0.70, 0.70, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00} }, { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 1, 3, 3, 3, 3, 1, 0, 0}, {0, 1, 1, 3, 0, 0, 3, 1, 1, 0}, {0, 1, 1, 3, 0, 0, 3, 1, 1, 0}, {0, 0, 1, 3, 3, 3, 3, 1, 0, 0}, {0, 0, 1, 1, 1, 1, 1, 1, 0, 0}, {0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }) return { map0, map1, map2, map3 }
Empty pattern
You can copy paste this blank MapPattern to start making Patterns from scratch:
local map = MapPattern:new( "", -- Name "", -- Creator { {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, -- Geometry Pattern {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00}, {0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00} }, { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -- Spawn Pattern {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } )
Testing
If you added the optional prints at the end of the files, you can try to find if they fired, to see if your patterns was correctly loaded


You can test your pattern with "lua_run PlayPattern(index)". Replace index with the index of the Pattern (again, Lua indexes from 1, not 0!). You can also omit the index to have a random pattern play.
Tips for designing good Patterns
Some things that I can recommend doing for making new Patterns:
- Avoid having too many non-spawning blocks. This makes the Pattern too predictable.

- Continuing from the previous tip, do try to have as many blocks with enemies as possible. This makes the map more diverse and scaling over harder difficulties.

- Do avoid placing enemies in places where it is hard for them to get into attack position against the player. Avoid putting melee only enemies on high ground.

- If you raise a block very high up, try to have another block nearby that the player can jump to without taking fall damage. Getting stuck and being required to take fall damage when the pattern changes can be frustrating for players. (The default fall damage distance is 240, which is about 0.46 in our blocks dimensions.)

- If you place ranged enemies, make sure to place covers too.

- You may want to try making patterns that work well with the addons that you are using.

Good luck and have fun!