Lesson 4 of 10
Tables inside tables
- 12 min
- 6 checks
- 3 hints
- Go to task
Goal
Safe access to deep fields
Explanation
A field's value can be another table, and that's how you build a player's whole state: hero.equipment.weapon.name is the name of their weapon and hero.inventory.items is their list of items. A single variable holds the player with everything that belongs to them, ready to pass to any function.
But player data isn't always complete. The peasant has no weapon and a new player has no bag yet, so peasant.equipment.weapon throws attempt to index a nil value (field 'equipment') and the whole script stops. On a game server, that means one incomplete record is enough to stop the loop that goes over every player.
You protect yourself with a chain of ands, because a and b returns a when it's nil or false without looking at b at all. So player.equipment and player.equipment.weapon stops at the first missing level and returns nil with no error, and then or supplies the fallback value. When you're writing rather than reading, create the missing level before you step into it, like this: player.inventory = player.inventory or {}.
Your task
Fix weaponName(player) so it returns the weapon's name, or "unarmed" if the player has no weapon. Then write itemCount(player), which returns the number of elements in player.inventory.items, or 0 if that list doesn't exist, and addItem(player, item), which adds the item to player.inventory.items and creates whatever is missing along that path without wiping out what's already there.
Checks
6 checks- weaponName reads the weapon's name
- weaponName doesn't crash when a level is missing
- itemCount counts the items
- itemCount returns 0 when there's no bag
- addItem creates the missing levels
- addItem doesn't wipe out what was already there