Writing things down

In this chapter we’re going to focus on exposing information to the player like their HP and the most recent actions that happened to them to make the flow of the game more clear.

Keeping tabs on your health

Head on over to gamelevelstate.lua and in draw replace the following line:

self.display:putString(1, 1, "Hello prism!")

with:

local currentActor = self:getCurrentActor()
local health = currentActor and currentActor:get(prism.components.Health)
if health then
   self.display:putString(1, 1, "HP:" .. health.hp .. "/" .. health.maxHP)
end

Now we have a primitive HP display.

Logging messages

Fortunately, prism provides a Log component in an optional module. Load it before the game module in main.lua:

prism.loadModule("prism/spectrum")
prism.loadModule("prism/extra/sight")
prism.loadModule("prism/extra/log")
prism.loadModule("modules/game")

Now head over to player.lua and give them a Log component.

prism.components.Log()

Logging kick

Head to modules/game/actions/kick.lua and at the top of the file we’ll define some shorthands:

local Log = prism.components.Log
local Name = prism.components.Name
local sf = string.format

These are mainly for convenience and brevity. Now head to the bottom of perform and add the following.

local kickName = Name.lower(kicked)
local ownerName = Name.lower(self.owner)
Log.addMessage(self.owner, sf("You kick the %s.", kickName))
Log.addMessage(kicked, sf("The %s kicks you!", ownerName))
Log.addMessageSensed(level, self, sf("The %s kicks the %s.", ownerName, kickName))

We use the convenience methods Log.addMessage() and Log.addMessageSensed() to add messages to the affected and nearby actors.

Drawing logs

Back in gamelevelstate.lua, we’ll draw the message log by grabbing the last 5 messages with Log:iterLast() and writing them to the screen.

local log = currentActor and currentActor:get(prism.components.Log)
if log then
   local offset = 0
   for line in log:iterLast(5) do
      self.display:putString(1, self.display.height - offset, line)
      offset = offset + 1
   end
end

This gives us a really basic message log at the bottom of the screen.

Adding damage

The kick message is nice, but wouldn’t it be better if we could see how much damage we’re doing? Let’s head to modules/game/actions/damage.lua and make a small change.

function Damage:perform(level, damage)
   local health = self.owner:expect(prism.components.Health)
   health.hp = health.hp - damage
   self.dealt = damage -- add this!

   ...
end

We store the damage that was dealt in the Damage action so that we can inspect it in kick. We generate back to kick.lua.

function Kick:perform(level, kicked)
   ...

   local dmgstr = ""
   if damage.dealt then
      dmgstr = sf("Dealing %i damage.", damage.dealt)
   end

   local kickName = Name.lower(kicked)
   local ownerName = Name.lower(self.owner)
   Log.addMessage(self.owner, sf("You kick the %s. %s", kickName, dmgstr))
   Log.addMessage(kicked, sf("The %s kicks you! %s", ownerName, dmgstr))
   Log.addMessageSensed(level, self, sf("The %s kicks the %s. %s", ownerName, kickName, dmgstr))
end

Giving attack the same treatment

Head over to modules/game/actions/attack.lua and add the same shorthands as before.

local Log = prism.components.Log
local Name = prism.components.Name
local sf = string.format

Then give the same treatment to Attack.

function Attack:perform(level, attacked)
   ...

   local dmgstr = ""
   if damage.dealt then
      dmgstr = sf("Dealing %i damage.", damage.dealt)
   end

   local attackName = Name.lower(attacked)
   local ownerName = Name.lower(self.owner)
   Log.addMessage(self.owner, sf("You attack the %s. %s", attackName, dmgstr))
   Log.addMessage(attacked, sf("The %s attacks you! %s", ownerName, dmgstr))
   Log.addMessageSensed(level, self, sf("The %s attacks the %s. %s", ownerName, attackName, dmgstr))
end

And we’re done! You should now see messages for when you kick kobolds and they strike back.

Wrapping up

We now render the player’s health and use the Log component to display a combat log. In the next section we’ll add a game over screen so that the game doesn’t simply quit when we lose.