# Feature Add-ins

Feature Add-ins expand almostLua functionality by adding libraries, functions or properties that may not arrive out of the box. Add-ins are snippets of almostLua code that go at the top of your script.

### Table Add-in

By default, the almostLua `table` library only has three functions: `find`, `insert` and `remove`. However, this add-in expands it to `clear, clone, concat, create, find, freeze, isfrozen, insert, maxn, move, remove`:

```lua
local table = {
	clear = function(tbl)
		for i, _ in pairs(tbl) do
			tbl[i] = nil
		end
	end,
	clone = function(tbl)
		local newTbl = {}
		for i, v in pairs(tbl) do
			newTbl[i] = v
		end
		return newTbl
	end,
	concat = function(tbl, sep, i, j)
		local newString = ""
		i = i or 1
		j = j or #tbl
		for x = i, j do
			newString = newString .. tbl[x] .. (sep or "")
		end
		return newString
	end,
	create = function(count, value)
		local newTbl = {}
		for i = 1, count do
			newTbl[i] = value
		end
		return newTbl
	end,
	freeze = function(tbl)
		-- Do nothing
		return tbl
	end,
	isfrozen = function(tbl)
		-- Cannot freeze RetroStudio tables
		return false
	end,
	maxn = function(tbl)
		local max = 0
		for i, _ in pairs(tbl) do
			if i > max then
				max = i
			end
		end
		return max
	end,
	move = function(src, a, b, t, dst)
		if dst == nil then
			dst = src
		end
		for i = a, b do
			dst[t + i] = src[i]
		end
	end,
}
```

### Shared Tables Add-in

This add-in adds the `_G` and `shared` tables, which allow you to share variables between scripts more efficiently. To use this add-in, you must be using almostLua 1.1 or higher.

**Step 1:** Import this model code into your RetroStudio game: `971466458` and place it in Lighting.\
**Step 2:** At the top of the Lua script that needs shared tables, insert the following:

```lua
local _G = require(game.Lighting:WaitForChild("Almost Lua Shared").G)
local shared = require(game.Lighting:WaitForChild("Almost Lua Shared").Shared)
```

### Terrain Add-in

The default Terrain class in almostLua is very limited. However, with this add-in, you can expand it to its full functionality set. Note that the add-in makes only bare effort to recreate terrain, there are no textures, shapes nor special materials like water.

```lua
local Vector3int16 = {
	new = function(x, y, z)
		return Vector3.new(math.round(x), math.round(y), math.round(z))
	end,
}

local Region3int16 = {
	new = function(min, max)
		return {Min=min, Max=max}
	end,
}

local terrain = {
	colors = {
		Grass = BrickColor.new("Dark green"),
		Sand = BrickColor.new("New Yeller"),
		Brick = BrickColor.new("Reddish brown"),
		Granite = BrickColor.new("Medium stone grey"),
		Asphalt = BrickColor.new("Black"),
		Iron = BrickColor.new("Silver"),
		Aluminum = BrickColor.new("Ghost grey"),
		Gold = BrickColor.new("Bright yellow"),
		WoodPlank = BrickColor.new("Brown"),
		WoodLog = BrickColor.new("Reddish brown"),
		Gravel = BrickColor.new("Dark stone grey"),
		CinderBlock = BrickColor.new("Medium stone grey"),
		MossyStone = BrickColor.new("Earth green"),
		Cement = BrickColor.new("Light stone grey"),
		RedPlastic = BrickColor.new("Bright red"),
		BluePlastic = BrickColor.new("Bright blue"),
		Water = BrickColor.new("Bright blue")
	},
	terrainFolder = Instance.new("Folder", workspace),
	SetCell = function(self, xRaw, yRaw, zRaw, material, block, orientation)
		local x = math.round(xRaw)
		local y = math.round(yRaw)
		local z = math.round(zRaw)
		-- TODO: respect CellBlock and CellOrientation
		local newPosition = Vector3.new(x,y,z) * 4
		local oldCell = self.terrainFolder:FindFirstChild(tostring(newPosition))
		if oldCell then
			oldCell:Destroy()
		end
		if material == "Empty" then
			return
		end
		local newCell = Instance.new("Part", self.terrainFolder)
		newCell.Anchored = true
		newCell.Size = Vector3.new(4, 4, 4)
		newCell.Name = tostring(newPosition)
		newCell.Position = newPosition
		newCell.BrickColor = self.colors[material]
	end,
	SetCells = function(self, region, material, block, orientation)
		-- TODO: respect CellBlock and CellOrientation
		print("setcells called")
		local min, max = region.Min, region.Max
		local minX, minY, minZ, maxX, maxY, maxZ = min.X, min.Y, min.Z, max.X, max.Y, max.Z
		local iterX = 4
		local iterY = 4
		local iterZ = 4
		if minX > maxX then
			iterX = -4
		end
		if minY > maxY then
			iterY = -4
		end
		if minZ > maxZ then
			iterZ = -4
		end
		for x = minX, maxX, iterX do
			for y = minY, maxY, iterY do
				for z = minZ, maxZ, iterZ do
					self:SetCell(x/4, y/4, z/4, material, block, orientation)
				end
			end
		end
	end,
	GetCell = function(self, xRaw, yRaw, zRaw)
		local x = math.round(xRaw)
		local y = math.round(yRaw)
		local z = math.round(zRaw)
		local newPosition = Vector3.new(x,y,z) * 4
		local oldCell = self.terrainFolder:FindFirstChild(tostring(newPosition))
		if oldCell then
			local materialName = "Unknown"
			for material, color in pairs(self.colors) do
				if color == oldCell.BrickColor then
					materialName = material
				end
			end
			return materialName, "Solid", "X"
		else
			return "Empty", "Solid", "X"
		end
	end,
	Clear = function(self)
		self.terrainFolder:ClearAllChildren()
	end,
	AutowedgeCell = function(self)
		warn("STUB: AutowedgeCell")
	end,
	AutowedgeCells = function(self)
		warn("STUB: AutowedgeCells")
	end,
	CellCornerToWorld = function(self, x, y, z)
		return Vector3.new(x * 4, y * 4, z * 4)
	end,
	CellCenterToWorld = function(self, x, y, z)
		return Vector3.new((x + 0.5) * 4, (y + 0.5) * 4, (z + 0.5) * 4)
	end,
	CountCells = function(self)
		local cells = self.terrainFolder:GetChildren()
		local count = #cells
		return count
	end,
	GetWaterCell = function(self)
		return "None", "NegX"
	end,
	SetWaterCell = function(self, x, y, z, force, direction)
		self:SetCell(x, y, z, "Water")
	end,
	WorldToCell = function(self, position)
		local result = Vector3.new(
			math.floor(position.X / 4),
			math.floor(position.Y / 4),
			math.floor(position.Z / 4)
		)
		return result
	end,
	WorldToCellPreferEmpty = function(self, position)
		local result = self:WorldToCell(position)
		return result
	end,
	WorldToCellPreferSolid = function(self, position)
		local result = self:WorldToCell(position)
		return result
	end,
}
terrain.terrainFolder.Name = "Terrain"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vopwn55.gitbook.io/almostlua/expanding-almostlua/feature-add-ins.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
