### Find Player Path and Move Kobold (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Demonstrates finding a path to the player using Level.findPath and moving the kobold along it using Path.pop. Requires the Mover component and the player's position. Returns a Wait action if no path is found or movement is not possible. ```lua local mover = actor:get(prism.components.Mover) if not mover then return prism.actions.Wait(actor) end -- we can't move! local path = level:findPath(actor:getPosition(), player:getPosition(), actor, mover.mask, 1) if path then local move = prism.actions.Move(actor, path:pop()) if level:canPerform(move) then return move end end ``` -------------------------------- ### Complete Kick Action Implementation (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Provides the full implementation of the 'Kick' action, including target definition, action properties, and the logic for validating and performing the kick. It allows kicking actors up to 3 tiles away with flying movement. ```lua local KickTarget = prism.Target(prism.components.Collider):range(1):sensed() ---@class Kick : Action local Kick = prism.Action:extend("Kick") Kick.targets = { KickTarget } Kick.requiredComponents = { prism.components.Controller, } function Kick:canPerform(level) return true end local mask = prism.Collision.createBitmaskFromMovetypes { "fly" } --- @param level Level --- @param kicked Actor function Kick:perform(level, kicked) local direction = (kicked:getPosition() - self.owner:getPosition()) local final = kicked:expectPosition() for _ = 1, 3 do local nextpos = final + direction if not level:getCellPassable(nextpos.x, nextpos.y, mask) then break end final = nextpos end level:moveActor(kicked, final) end return Kick ``` -------------------------------- ### Register Kobold Actor with Basic Components (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Registers a new actor named 'Kobold' using prism.registerActor. It initializes the actor with a position and a drawable component, setting its color to red. This is the initial setup before adding more complex behaviors. ```lua prism.registerActor("Kobold", function() return prism.Actor.fromComponents { prism.components.Position(), prism.components.Drawable{ index = "k", color = prism.Color4.RED }, } end) ``` -------------------------------- ### Initialize Game Start State (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst Creates a new GameStartState, initializes display, and attempts to read the save game from disk. Handles cases where the save file does not yet exist. ```lua local controls = require "controls" --- -- @class GameStartState : GameState -- @field display Display -- @overload fun(display: Display): GameStartState local GameStartState = spectrum.GameState:extend("GameStartState") function GameStartState:__new(display) self.display = display self.save = love.filesystem.read("save.lz4") end ``` -------------------------------- ### Draw Game Start Menu (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst Renders the main menu for the game start state. Displays the game title, and options to start a new game, load a game (if a save exists), or quit. ```lua function GameStartState:draw() local midpoint = math.floor(self.display.height / 2) self.display:clear() self.display:print(1, midpoint, "Kicking Kobolds", nil, nil, nil, "center", self.display.width) self.display:print(1, midpoint + 3, "[n] for new game", nil, nil, nil, "center", self.display.width) local i = 0 if self.save then i = i + 1 self.display:print(1, midpoint + 3 + i, "[l] to load game", nil, nil, nil, "center", self.display.width) end self.display:print(1, midpoint + 4 + i, "[q] to quit", nil, nil, nil, "center", self.display.width) self.display:draw() end ``` -------------------------------- ### Handle Game Start Input and State Transitions (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst Processes player input for new game, load game, or quit actions. Loads game state from disk if available, or starts a new game by clearing the save and generating a new level. Quits the game on user request. ```lua function GameStartState:update(dt) controls:update() if controls.newgame.pressed then love.filesystem.remove("save.lz4") local builder = Game:generateNextFloor(prism.actors.Player()) self.manager:enter( spectrum.gamestates.GameLevelState(self.display, builder, Game:getLevelSeed()) ) elseif controls.loadgame.pressed and self.save then local mp = love.data.decompress("string", "lz4", self.save) local save = prism.Object.deserialize(prism.messagepack.unpack(mp)) Game = save self.manager:enter(spectrum.gamestates.GameLevelState(self.display, Game.level)) elseif controls.quit.pressed then love.quit() end end return GameStartState ``` -------------------------------- ### Complete Kobold Actor Registration with All Components (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Provides the final version of the Kobold actor registration, consolidating all previously added components: Name, Position, Collider, Drawable, Senses, Sight, Mover, and KoboldController. This represents a fully featured Kobold actor. ```lua prism.registerActor("Kobold", function() return prism.Actor.fromComponents { prism.components.Name("Kobold"), prism.components.Position(), prism.components.Collider(), prism.components.Drawable{ index = "k", color = prism.Color4.RED }, prism.components.Senses(), prism.components.Sight{ range = 12, fov = true }, prism.components.Mover{ "walk" }, prism.components.KoboldController() } end) ``` -------------------------------- ### Chained Query Construction Example Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/query.rst Demonstrates how to chain multiple query methods together for a more complex and efficient search. This example combines component requirements, additional filters, and location restrictions. ```lua local query = level:query(prism.components.Controller, prism.components.Senses) :with(prism.components.Senses) :at(x, y) for actor, controller, collider, senses in query:iter() do -- do stuff end ``` -------------------------------- ### Kobold Controller Logic (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Implements the AI for a kobold, enabling it to sense the player, find a path, and move towards them. It utilizes Senses, Mover, and Level components. Returns a Wait action if the player is not sensed or movement is blocked. ```lua --- @class KoboldController : Controller --- @overload fun(): KoboldController local KoboldController = prism.components.Controller:extend("KoboldController") function KoboldController:act(level, actor) local senses = actor:get(prism.components.Senses) if not senses then return prism.actions.Wait(actor) end -- we can't see! local player = senses:query(level, prism.components.PlayerController):first() if not player then return prism.actions.Wait(actor) end local mover = actor:get(prism.components.Mover) if not mover then return prism.actions.Wait(actor) end local path = level:findPath(actor:getPosition(), player:getPosition(), actor, mover.mask, 1) if path then local move = prism.actions.Move(actor, path:pop()) if level:canPerform(move) then return move end end return prism.actions.Wait(actor) end return KoboldController ``` -------------------------------- ### Find Player Actor using Senses Component (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Demonstrates how to find the player actor within the game world using the Kobold's Senses component. It checks if the Senses component exists and then queries for the PlayerController, returning a default action if the player cannot be found or perceived. ```lua local senses = actor:get(prism.components.Senses) if not senses then return prism.actions.Wait(actor) end -- we can't see! local player = senses:query(level, prism.components.PlayerController):first() if not player then return prism.actions.Wait(actor) end ``` -------------------------------- ### Clone Prism Project Template (Shell) Source: https://github.com/prismrl/prism/blob/master/docs/source/installation.rst Clones the PrismRL project template locally, including submodules. This is the recommended way to start a new game project with PrismRL. Ensure you have Git installed. ```sh git clone --recursive --depth 1 https://github.com/PrismRL/prism-template.git ``` -------------------------------- ### Add Movement and Perception Components to Kobold (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Enhances the Kobold actor by adding Senses, Sight, and Mover components. Senses allows the Kobold to perceive its environment, Sight defines its visual range and field of view, and Mover enables movement capabilities. ```lua prism.components.Senses(), prism.components.Sight{ range = 12, fov = true }, prism.components.Mover{ "walk" } ``` -------------------------------- ### Initialize Game State in main.lua (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst Replaces the default love.load function to initialize the game. It pushes the GameStartState onto the manager stack, allowing the start menu to be displayed. Includes a debug mode for map generation. ```lua function love.load(args) if args[1] == "--debug" then local builder = prism.LevelBuilder() local function generator() Game:generateNegamextFloor(prism.actors.Player(), builder) end manager:push(spectrum.gamestates.MapGeneratorState(generator, builder, display)) else manager:push(spectrum.gamestates.GameStartState(display)) end manager:hook() spectrum.Input:hook() end ``` -------------------------------- ### Perform Kick Action Logic (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Implements the logic for the 'Kick' action. It calculates the direction to the target, determines the final position up to 3 tiles away considering 'fly' movement passability, and then moves the actor. The canPerform method always returns true, indicating the action is always possible. ```lua function Kick:canPerform(level) return true end local mask = prism.Collision.createBitmaskFromMovetypes{ "fly" } --- @param level Level --- @param kicked Actor function Kick:perform(level, kicked) local direction = (kicked:getPosition() - self.owner:getPosition()) local final = kicked:expectPosition() for _ = 1, 3 do local nextpos = final + direction if not level:getCellPassable(nextpos.x, nextpos.y, mask) then break end final = nextpos end level:moveActor(kicked, final) end ``` -------------------------------- ### Integrate Kick Action on Blocked Movement (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst This Lua code snippet demonstrates how to modify the GameLevelState to perform a kick action when the player attempts to move into a blocked destination. It checks for a valid, kickable target at the destination before attempting the kick. Dependencies include the 'prism.actions.Move' and 'prism.actions.Kick' modules, and the 'controls' and 'Level' objects. ```lua function GameLevelState:updateDecision(dt, owner, decision) -- Controls need to be updated each frame. controls:update() -- Controls are accessed directly via table index. if controls.move.pressed then local destination = owner:getPosition() + controls.move.vector local move = prism.actions.Move(owner, destination) if self:setAction(move) then return end local target = self.level:query() -- grab a query object :at(destination:decompose()) -- restrict the query to the destination :first() -- grab one of the kickable things, or nil local kick = prism.actions.Kick(owner, target) self:setAction(kick) end ``` -------------------------------- ### Kick Action Definition (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Defines the 'Kick' action, setting its targets and required components. It requires actors performing this action to have a Controller component and can target actors within range 1 with a Collider. ```lua ---@class KickAction : Action local Kick = prism.Action:extend("Kick") Kick.targets = { KickTarget } Kick.requiredComponents = { prism.components.Controller } return Kick ``` -------------------------------- ### Add Kobold Controller Component to Actor (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Attaches the custom KoboldController component to the Kobold actor. This links the defined AI logic to the Kobold, enabling it to execute its intended behavior within the game world. ```lua prism.components.KoboldController() ``` -------------------------------- ### Simplify MapGeneratorState Setup in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part9.rst Simplifies the setup for `MapGeneratorState` by creating a `LevelBuilder` and defining a generator function that calls `Game:generateNextFloor`. ```lua local builder = prism.LevelBuilder(prism.cells.Pit) local function generator() Game:generateNextFloor(prism.actors.Player(), builder) end ``` -------------------------------- ### Define Kobold AI Controller Logic (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Implements a custom Controller for the Kobold named KoboldController. This controller defines the 'act' function, which dictates the Kobold's behavior by attempting to move right or wait if movement is not possible. It adheres to the Controller's contract of not modifying the level directly. ```lua --- @class KoboldController : Controller --- @overload fun(): KoboldController local KoboldController = prism.components.Controller:extend("KoboldController") function KoboldController:act(level, actor) local destination = actor:getPosition() + prism.Vector2.RIGHT local move = prism.actions.Move(actor, destination) if level:canPerform(move) then return move end return prism.actions.Wait(actor) end return KoboldController ``` -------------------------------- ### Clone Prism Repository Directly (Shell) Source: https://github.com/prismrl/prism/blob/master/docs/source/installation.rst Clones the PrismRL repository into your project directory. This method is used when not utilizing the project template and requires manual setup of Prism within your game's structure. ```sh git clone https://github.com/PrismRL/prism.git ``` -------------------------------- ### Spawn Player in a Random Room in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Selects a random room from the generated `rooms` table and places the player actor at its center tile. A `while` loop ensures that a valid starting room is always found before proceeding. This is a critical step for initializing player position. ```lua local startRoom while not startRoom do local x, y = rng:random(0, PARTITIONS - 1), rng:random(0, PARTITIONS - 1) startRoom = rooms[prism.Vector2._hash(x, y)] end local playerPos = startRoom:center():floor() coroutine.yield() builder:addActor(player, playerPos.x, playerPos.y) ``` -------------------------------- ### Compute and Apply Component State Changes (Lua) Source: https://context7.com/prismrl/prism/llms.txt This snippet illustrates component diffing and patching, which is useful for synchronization and serialization. It shows how to create two component states, compute the differences between them, and then apply these differences to update a component. Examples for cloning components and use cases like network synchronization and undo systems are also provided. ```lua -- Create original component local health1 = Health(100) health1.currentHealth = 75 health1.maxHealth = 100 health1.customField = "value" -- Create modified version local health2 = Health(100) health2.currentHealth = 50 -- changed health2.maxHealth = 120 -- changed -- customField removed -- Compute diff local diff = health1:diff(health2) -- Diff structure: { set = {...}, unset = {...} } if diff then if diff.set then for key, value in pairs(diff.set) do print("Changed: " .. key .. " = " .. tostring(value)) end end if diff.unset then for key, _ in pairs(diff.unset) do print("Removed: " .. key) end end end -- Apply diff to component health1:applyDiff(diff) -- Now health1 matches health2 print(health1.currentHealth) -- 50 print(health1.maxHealth) -- 120 print(health1.customField) -- nil -- Clone component local healthClone = health1:clone() -- Use case: Network synchronization local function syncComponent(original, updated) local diff = original:diff(updated) if diff then -- Send minimal diff over network instead of full state return diff end return nil -- no changes end -- Use case: Undo system local previousState = component:clone() -- ... make changes ... local diff = component:diff(previousState) -- Store diff for undo ``` -------------------------------- ### Spawn Kobolds in Non-Start Rooms in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Iterates through all generated rooms and spawns a `Kobold` actor in each room, excluding the room designated as the player's starting room. The kobold is placed at the center tile of the room. This populates the level with enemies. ```lua for _, room in pairs(rooms) do if room ~= startRoom then local cx, cy = room:center():floor():decompose() coroutine.yield() builder:addActor(prism.actors.Kobold(), cx, cy) end end ``` -------------------------------- ### Start a Prism RL Query with Components Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/query.rst Initiates a query by specifying the required component types. This is the first step in finding actors that possess all listed components. Implemented by Level, LevelBuilder, and ActorStorage. ```lua local query = level:query(prism.components.Controller, prism.components.Collider) ``` -------------------------------- ### Add Damage to Kick Action in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part3.rst Integrates the Damage action into the existing Kick action. When a kick occurs, this code creates and attempts to perform a Damage action on the kicked actor, dealing 1 point of damage. ```lua function Kick:perform(level, kicked) ... local damage = prism.actions.Damage(kicked, 1) level:tryPerform(damage) end ``` -------------------------------- ### Actor Creation and Component Management in Lua Source: https://context7.com/prismrl/prism/llms.txt Demonstrates how to create actors, attach, check for, remove, and get components in Prism. Actors are fundamental game entities, and components add dynamic functionality. This snippet showcases the basic lifecycle of components on an actor. ```lua -- Create a basic actor local player = prism.Actor() -- Add components to define behavior and state player:give(prism.components.Position(prism.Vector2(5, 5))) player:give(prism.components.Collider(1)) -- size 1x1 player:give(prism.components.Name("Hero")) player:give(prism.components.PlayerController()) -- Create actor from multiple components at once local components = { prism.components.Position(prism.Vector2(10, 10)), prism.components.Name("Goblin"), prism.components.Collider(1) } local enemy = prism.Actor.fromComponents(components) -- Check if actor has component if player:has(prism.components.Position) then local pos = player:getPosition() print("Player at: " .. pos.x .. ", " .. pos.y) end -- Remove component player:remove(prism.components.Collider) -- Get component reference local nameComp = player:get(prism.components.Name) if nameComp then print(nameComp.name) end ``` -------------------------------- ### Default Actor Turn Handling in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/explainers/game-loop.rst Demonstrates the default behavior for handling an actor's turn in the game loop. It calls the actor's controller to get an action and then performs that action within the level. Asserts that an action is returned, preventing nil actions from causing errors. ```lua local action = controller:act(level, actor) -- we make sure we got an action back from the controller for sanity's sake assert(action, "Actor " .. actor:getName() .. " returned nil from act()") level:perform(action) ``` -------------------------------- ### Complete inventorystate.lua File Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Provides the full source code for the InventoryState game state, integrating initialization, drawing, and input handling logic for managing player inventory. ```lua local keybindings = require "keybindingschema" --- -- @class InventoryState : GameState -- @field previousState GameState -- @overload fun(display: Display, decision: ActionDecision, level: Level, inventory: Inventory) local InventoryState = spectrum.GameState:extend "InventoryState" --- -- @param display Display ``` -------------------------------- ### Define Kick Target (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Defines a target for the 'Kick' action, specifying that only actors with a Collider component within a range of 1 can be targeted. This is used to ensure valid targets for the kick action. ```lua local KickTarget = prism.Target(prism.components.Collider) :range(1) :sensed() ``` -------------------------------- ### Define Inventory Keybindings Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Sets up keybindings in the schema for interacting with the inventory. This includes keys for opening the inventory, going back, and picking up items. ```lua -- inventory inventory = "tab", back = "backspace", pickup = "p" ``` -------------------------------- ### Lua: Room and Actor Placement Logic Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Iterates through generated rooms to create hallways and place actors. It strategically places the player in the first room and kobolds in other rooms. Finally, it pads the map with walls. ```lua for hash, currentRoom in pairs(rooms) do local px, py = prism.Vector2._unhash(hash) createLShapedHallway(currentRoom, rooms[prism.Vector2._hash(px + 1, py)]) createLShapedHallway(currentRoom, rooms[prism.Vector2._hash(px, py + 1)]) end -- Choose the first room (top-left partition) to place the player. local startRoom while not startRoom do local x, y = rng:random(0, PARTITIONS - 1), rng:random(0, PARTITIONS - 1) startRoom = rooms[prism.Vector2._hash(x, y)] end local playerPos = startRoom:center():floor() builder:addActor(player, playerPos.x, playerPos.y) for _, room in pairs(rooms) do if room ~= startRoom then local cx, cy = room:center():floor():decompose() builder:addActor(prism.actors.Kobold(), cx, cy) end end builder:pad(1, prism.cells.Wall) return builder ``` -------------------------------- ### Add Collider Component to Kobold (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part1.rst Adds a Collider component to the Kobold actor definition. This enables collision detection, preventing other actors from passing through the Kobold. It's a crucial step for physical interaction in the game. ```lua prism.components.Collider() ``` -------------------------------- ### Create Inventory Game State (Initialization) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Defines a new GameState for the inventory screen. It initializes by storing references to display, decision, level, and inventory objects, and pre-populates item and letter mappings. ```lua local utf8 = require "utf8" local keybindings = require "keybindingschema" --- -- @class InventoryState : GameState -- @overload fun(display: Display, decision: ActionDecision, level: Level, inventory: Inventory) local InventoryState = spectrum.GameState:extend "InventoryState" --- -- @param display Display -- @param decision ActionDecision -- @param level Level -- @param inventory Inventory function InventoryState:__new(display, decision, level, inventory) self.display = display self.decision = decision self.level = level self.inventory = inventory self.items = inventory.inventory:getAllActors() self.letters = {} for i = 1, #self.items do self.letters[i] = utf8.char(96 + i) -- a, b, c, ... end end ``` -------------------------------- ### Pathfinding with A* in Lua Source: https://context7.com/prismrl/prism/llms.txt Demonstrates how to use the A* pathfinding algorithm in Lua. It includes setting up custom callbacks for passability and movement costs, finding paths between actors, and following the calculated path. It also shows direct A* search with configurable parameters like distance type. ```lua -- Define passability callback local function passableCallback(x, y) -- Check if position is within bounds if x < 1 or y < 1 or x > level.map.w or y > level.map.h then return false end -- Check if cell is walkable local cell = level:getCell(x, y) return cell and not cell.blocksMovement end -- Optional: Define custom cost callback local function costCallback(x, y) local cell = level:getCell(x, y) -- Difficult terrain costs more if cell and cell.isDifficultTerrain then return 2 end return 1 end -- Find path using level method local actor = prism.Actor() actor:give(prism.components.Position(prism.Vector2(5, 5))) actor:give(prism.components.Collider(1)) local start = actor:expectPosition() local goal = prism.Vector2(15, 15) local path = level:findPath(actor, goal, 0) -- minDistance = 0 if path then -- Follow the path for i, step in ipairs(path.path) do local cost = path.costs[i] or 1 print("Step " .. i .. ": (" .. step.x .. ", " .. step.y .. ") cost: " .. cost) end -- Get next step local nextPos = path:peek() if nextPos then level:moveActor(actor, nextPos) end else print("No path found") end -- Direct A* search with custom parameters local path = prism.astar( start, goal, passableCallback, costCallback, 1, -- minimum distance from goal "euclidean" -- distance type: "euclidean", "manhattan", or "chebyshev" ) ``` -------------------------------- ### Load Prism Inventory Module Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Loads the optional inventory module from the Prism engine's extra modules. This is the initial step to enable inventory functionality. ```lua prism.loadModule("prism/extra/inventory") ``` -------------------------------- ### Define Control Mappings (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst Sets up key bindings for game actions within the 'controls' module. Maps 'n' to newgame and 'l' to loadgame. ```lua newgame = "n", loadgame = "l", ``` -------------------------------- ### Calculate Room Dimensions and Offsets Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Calculates the dimensions for partitions and sets limits for minimum and maximum room width and height. It also determines a random partition to omit for variance. ```lua local missing = prism.Vector2( rng:random(0, PARTITIONS - 1), rng:random(0, PARTITIONS - 1) ) local pw, ph = math.floor(width / PARTITIONS), math.floor(height / PARTITIONS) local minrw, minrh = math.floor(pw / 3), math.floor(ph / 3) local maxrw, maxrh = pw - 2, ph - 2 -- Subtract 2 to ensure there's a margin. ``` -------------------------------- ### Initialize and Run Game with State Management (Lua) Source: https://context7.com/prismrl/prism/llms.txt This snippet demonstrates how to set up and run the main game loop using a state manager. It initializes the rendering system, creates a level state, and pushes it to the state manager. The `love.update` and `love.draw` functions are defined to update and render the current state, respectively. Input handling for player movement and waiting is also shown within a custom update function. ```lua -- Initialize spectrum (rendering/input system) local display = spectrum.Display(level, 16, 16) -- tile size 16x16 display:setCameraTarget(player) -- Create level state local levelState = spectrum.gamestates.LevelState(level, display) -- Create state manager local stateManager = spectrum.StateManager() stateManager:push(levelState) -- In love2d main loop function love.update(dt) spectrum.Input:update() -- Update input system stateManager:update(dt) -- Update current state end function love.draw() stateManager:draw() -- Render current state end -- Handle player input in custom update function function levelState:updateDecision(dt, actor, decision) local input = spectrum.Input -- Movement if input.key.up.pressed then local moveAction = prism.actions.Move(actor, prism.Vector2(0, -1)) decision:setAction(moveAction, level) elseif input.key.down.pressed then local moveAction = prism.actions.Move(actor, prism.Vector2(0, 1)) decision:setAction(moveAction, level) elseif input.key.left.pressed then local moveAction = prism.actions.Move(actor, prism.Vector2(-1, 0)) decision:setAction(moveAction, level) elseif input.key.right.pressed then local moveAction = prism.actions.Move(actor, prism.Vector2(1, 0)) decision:setAction(moveAction, level) end -- Wait action if input.key.space.pressed then local waitAction = prism.actions.Wait(actor) decision:setAction(waitAction, level) end end ``` -------------------------------- ### Register Fall System in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part2.rst Demonstrates how to register the newly created 'FallSystem' within the game's level state by adding it to a system builder. ```lua builder:addSystems( prism.systems.SensesSystem(), prism.systems.SightSystem(), prism.systems.FallSystem() ) ``` -------------------------------- ### Check Target Lua Type (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/targets.rst Checks the fundamental Lua type of the target object, for example, if it is a 'number'. This is a lower-level type check. ```lua myTarget:isType("number") ``` -------------------------------- ### Initialize Game in love.load() in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part9.rst In `love.load()`, generates the first level using `Game:generateNextFloor` with a new player actor and initializes the `GameLevelState` with the created level builder and a seed. ```lua local builder = Game:generateNextFloor(prism.actors.Player()) manager:push(spectrum.gamestates.GameLevelState(display, builder, Game:getLevelSeed())) ``` -------------------------------- ### Gather All Query Results into a List Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/query.rst Collects all actors that match the query into a table (list). This is useful when you need all results at once, for example, to process them in a batch. ```lua local results = query:gather() for _, actor in ipairs(results) do -- Do something with them end ``` -------------------------------- ### Initialize Room Table Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Creates a Lua table to store Rectangle objects representing rooms. This table is typed to hold numbers as keys and Rectangle objects as values, preparing for room generation. ```lua -- Create rooms in each of the partitions. -- @type table local rooms = {} ``` -------------------------------- ### Getting Sprite Quad by Name (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/spriteatlas.rst Retrieves a specific sprite quad from a SpriteAtlas using its assigned name. This is used after creating an atlas with custom sprite names. ```lua local quad = atlas:getQuadByName("tree") ``` -------------------------------- ### Inventory Game State: Draw Method Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Renders the inventory screen. It first draws the previous state, clears the screen, displays a header, and then iterates through inventory items, drawing each with its assigned letter and details. ```lua function InventoryState:draw() self.previousState:draw() self.display:clear() self.display:print(1, 1, "Inventory", nil, nil, 2, "right") for i, actor in ipairs(self.items) do local name = actor:getName() local letter = self.letters[i] local item = actor:expect(prism.components.Item) local countstr = "" if item.stackCount and item.stackCount > 1 then countstr = ("%sx "):format(item.stackCount) end local itemstr = ("[%s] %s%s"):format(letter, countstr, name) self.display:print(1, 1 + i, itemstr, nil, nil, 2, "right") end self.display:draw() end ``` -------------------------------- ### Define Animation with Function Frames in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/animation.rst Defines an animation where individual frames are functions that take display, x, and y coordinates. This example creates an animation that places '!' sprites around a central point. ```lua local on = { index = "!", color = prism.Color4.YELLOW } local off = { index = " ", color = prism.Color4.BLACK } local function putAround(display, x, y) display:putSprite(x + 1, y, "!", on) display:putSprite(x - 1, y, "!", on) display:putSprite(x, y + 1, "!", on) display:putSprite(x, y - 1, "!", on) end spectrum.registerAnimation("Exclamation", function() return spectrum.Animation( { putAround, off, putAround }, 0.2, "pauseAtEnd" ) end) ``` -------------------------------- ### Implement Pickup Action in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part11.rst Implements the pickup functionality in GameLevelState. It queries the level for an item at the owner's position and creates a Pickup action. If the action can be performed, it's set as the current action. ```lua if controls.pickup.pressed then local target = self.level:query(prism.components.Item) :at(owner:getPosition():decompose()) :first() local pickup = prism.actions.Pickup(owner, target) if self:setAction(pickup) then return end end ``` -------------------------------- ### Update VitalityPotion for TickedCondition Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part13.rst Modifies the 'VitalityPotion' component to use the 'TickedCondition' instead of the base 'Condition'. This makes the health bonus a temporary effect lasting for a specified duration (10 turns in this example). ```lua prism.components.Drinkable { healing = 5, condition = prism.conditions.TickedCondition(10, prism.modifiers.HealthModifier(5)) }, ``` -------------------------------- ### Create Complex Target Definition (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/targets.rst Constructs a sophisticated target definition by chaining multiple builder methods. This example targets a wounded enemy actor within range and that is sensed. ```lua local woundedEnemyTarget = prism.Target:new(prism.components.Health) :isPrototype(prism.Actor) :sensed() :range(3) :filter(function(level, owner, target) local health = target:expect(prism.components.Health) return health and health.current < health.max end) ``` -------------------------------- ### Populate Map with Perlin Noise Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Fills the game map with a noise pattern of pits and walls using Perlin noise. It offsets the noise calculation to ensure random patterns and sets cells based on noise values greater than 0.5. ```lua -- Fill the map with random noise of pits and walls. local nox, noy = rng:random(1, 10000), rng:random(1, 10000) for x = 1, width do for y = 1, height do local noise = love.math.perlinNoise(x / 5 + nox, y / 5 + noy) local cell = noise > 0.5 and prism.cells.Wall or prism.cells.Pit builder:set(x, y, cell()) end end ``` -------------------------------- ### Get the First Matching Actor from a Query Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/query.rst Retrieves only the first actor that matches the query criteria. This is efficient for queries expected to yield a single result, such as finding a unique player-controlled character. ```lua local actor, playerController = level:query(prism.components.PlayerController):first() ``` -------------------------------- ### Action System and Command Pattern Implementation in Lua Source: https://context7.com/prismrl/prism/llms.txt Shows how to implement custom actions using the command pattern in Prism, including defining required components, target requirements, validation, and execution logic. Actions represent discrete game state changes. ```lua -- Define a custom Attack action local AttackAction = prism.Action:extend("AttackAction") -- Define required components for the actor performing this action AttackAction.requiredComponents = { prism.components.Position, prism.components.Controller } -- Define target requirements local AttackTarget = prism.Target(prism.components.Position) :range(1) -- must be within 1 tile :filter(function(level, owner, target) -- Can't attack self return owner ~= target end) AttackAction.targets = { AttackTarget } -- Validate if action can be performed function AttackAction:canPerform(level) local target = self:getTargeted(1) if not target then return false, "No target selected" end -- Additional validation logic return true end -- Execute the action function AttackAction:perform(level) local attacker = self.owner local target = self:getTargeted(1) -- Get health component from target local targetHealth = target:get(Health) if targetHealth then local damage = 10 local died = targetHealth:takeDamage(damage) if died then level:removeActor(target) end end end -- Use the action local player = prism.Actor() player:give(prism.components.Position(prism.Vector2(5, 5))) player:give(prism.components.Controller()) local enemy = prism.Actor() enemy:give(prism.components.Position(prism.Vector2(6, 5))) enemy:give(Health(50)) local attack = AttackAction(player, enemy) if attack:canPerform(level) then attack:perform(level) end ``` -------------------------------- ### Debug Level Generation in main.lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part7.rst Sets up a debug mode in main.lua to preview level generation. It loads a MapGeneratorState, passing it a level generation function, a LevelBuilder, and the display. This allows visualization of the generation process. ```lua function love.load(args) if args[1] == "--debug" then local levelgen = require "levelgen" local builder = prism.LevelBuilder() local seed = prism.RNG(love.timer.getTime()) local function generator() levelgen(seed, prism.actors.Player(), 60, 30, builder) end manager:push(spectrum.gamestates.MapGeneratorState(generator, builder, display) else manager:push(GameLevelState(display)) end manager:hook() spectrum.Input:hook() end ``` -------------------------------- ### Define Complex Time-Based Animation in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/how-tos/animation.rst Creates a complex animation using a function that calculates frame content based on elapsed time. This example draws a line segment by segment, simulating a projectile trajectory. ```lua spectrum.registerAnimation("Projectile", function(owner, targetPosition) --- @cast owner Actor --- @cast targetPosition Vector2 local x, y = owner:expectPosition():decompose() local line = prism.Bresenham(x, y, targetPosition.x, targetPosition.y) return spectrum.Animation(function(t, display) local index = math.floor(t / 0.05) + 1 display:put(line[index][1], line[index][2], "*", prism.Color4.ORANGE) if index == #line then return true end return false end) end) ``` -------------------------------- ### Manage Inventory with Stacking, Weight, and Volume Limits in Lua Source: https://context7.com/prismrl/prism/llms.txt This Lua snippet demonstrates how to create and manage items within an inventory system. It covers item creation with properties like weight, volume, and stackability, actor initialization with inventory limits, checking item addition feasibility, querying for specific items, removing quantities from stacks, and reporting inventory status. Dependencies include the prism.Actor, prism.components.Name, prism.components.Position, prism.components.Item, and prism.components.Inventory. ```lua -- Create an item local potion = prism.Actor() potion:give(prism.components.Name("Health Potion")) potion:give(prism.components.Position(prism.Vector2(10, 10))) potion:give(prism.components.Item({ weight = 0.5, volume = 1.0, stackable = "health_potion", stackLimit = 10, stackCount = 1 })) -- Create actor with inventory local player = prism.Actor() player:give(prism.components.Position(prism.Vector2(10, 10))) player:give(prism.components.Inventory({ limitCount = 20, -- max 20 item stacks limitWeight = 50.0, -- max 50 weight units limitVolume = 100.0, -- max 100 volume units multipleStacks = true -- allow multiple stacks of same item })) local inventory = player:expect(prism.components.Inventory) -- Check if can add item local canAdd, err = inventory:canAddItem(potion) if canAdd then inventory:addItem(potion) else print("Cannot add item: " .. err) end -- Query inventory for specific items for actor in inventory:query(prism.components.Item):iter() do local item = actor:get(prism.components.Item) local name = actor:get(prism.components.Name) print(name.name .. " (x" .. item.stackCount .. ")") end -- Remove quantity from stack local removed = inventory:removeQuantity(potion, 3) -- Check inventory status print("Total items: " .. inventory.totalCount) print("Total weight: " .. inventory.totalWeight) print("Total volume: " .. inventory.totalVolume) ``` -------------------------------- ### Require Game Modules (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part16.rst This Lua code snippet demonstrates how to load external modules into the current script. It requires 'debugger', 'prism', and 'game', making their functionality available for use. This is typically placed at the beginning of a main script file. ```lua require "debugger" require "prism" require "game" ``` -------------------------------- ### Implement Die Action in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part3.rst Creates a Die action that encapsulates the logic for removing an actor from the game level. It extends Prism's base Action class and takes the actor to be removed as its owner. ```lua ---@class Die : Action ---@overload fun(owner: Actor): Die local Die = prism.Action:extend("Die") function Die:perform(level) level:removeActor(self.owner) end return Die ``` -------------------------------- ### Require Prism in Lua Project (Lua) Source: https://github.com/prismrl/prism/blob/master/docs/source/installation.rst Includes the Prism library into your Lua project. This assumes Prism has been cloned or installed in a location accessible by the Lua require function. Note that Prism utilizes global variables. ```lua -- prism uses globals, sorry! require "path.to.prism" ``` -------------------------------- ### Initialize EquipmentState Constructor in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part15.rst The constructor for EquipmentState. It initializes the state's fields and builds data structures ('entries', 'letters') to represent the equipment slots and their contents, preparing the data for display. ```lua -- @param display Display --- @param decision ActionDecision --- @param level Level --- @param equipper Equipper function EquipmentState:__new(display, decision, level, equipper) self.display = display self.decision = decision self.level = level self.equipper = equipper self.entries = {} self.letters = {} for i, slot in ipairs(equipper.slots or {}) do self.entries[i] = { slot = slot.label, actor = equipper:get(slot.name) } self.letters[i] = string.char(96 + i) -- a, b, c, ... end end ``` -------------------------------- ### Create Health Component in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part3.rst Defines a reusable Health component for actors, managing maximum and current hit points. It extends Prism's base Component class and includes a constructor for initializing health. ```lua --- @class Health : Component --- @field maxHP integer --- @field hp integer --- @overload fun(hp: integer): Health local Health = prism.Component:extend("Health") function Health:__new(maxHP) self.maxHP = maxHP self.hp = maxHP end return Health ``` -------------------------------- ### Initialize Git Submodules (Shell) Source: https://github.com/prismrl/prism/blob/master/docs/source/installation.rst Initializes and updates Git submodules for a project. This command is necessary if the `--recursive` flag was omitted during the initial clone of a project with submodules, such as the Prism project template. ```sh git submodule update --init --recursive ``` -------------------------------- ### Implement Damage Action in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part3.rst Introduces a Damage action that applies a specified amount of damage to an actor's health. It validates the damage amount using `prism.Target` and triggers the Die action if health drops to or below zero. Requires the Health component. ```lua local DamageTarget = prism.Target():isType("number") --- @class Damage : Action --- @overload fun(owner: Actor, damage: number): Damage local Damage = prism.Action:extend("Damage") Damage.targets = { DamageTarget } Damage.requiredComponents = { prism.components.Health } function Damage:perform(level, damage) local health = self.owner:expect(prism.components.Health) health.hp = health.hp - damage if health.hp <= 0 then level:perform(prism.actions.Die(self.owner)) end end return Damage ``` -------------------------------- ### Display Restart and Quit Instructions in Lua Source: https://github.com/prismrl/prism/blob/master/docs/source/making-a-roguelike/part6.rst Adds instructions for restarting and quitting the game to the 'GameOverState' display. It uses 'self.display:print' to show '[r] to restart' and '[q] to quit' centered on the screen, below the 'Game over!' message. This enhances user experience by informing them of available actions. ```lua self.display:print( 1, midpoint + 3, "[r] to restart", nil, nil, nil, "center", self.display.width ) self.display:print( 1, midpoint + 4, "[q] to quit", nil, nil, nil, "center", self.display.width ) self.display:draw() ```