1. Embeddability. You can create a game engine in a performant systems language like c++ and embed lua in it for the scripting.
2. Speed. The lua interpreter is much faster than python in general. When you throw luajit into the fix, they are not really comparable at all.
3. simplicity: lua is tiny. and one of the easier languages for non coders (game designers, artists) to get started with.
4. Effortless C interop. You can make lua bindings for anything written in c with minimal effort.
Now to this specific engine. lua has one of the simplest and most beloved game frameworks out there - Love2d. its almost a foundational game framework for so many people (like pygame in python, XNA etc), including yours truly. Its been a beginners choice for over a decade now. Grid is built on top of Love2d.
btw, just in case you are interested in a python game engine, you should try out Arcade. Its pretty feature rich and aimed at beginners.
"I believe that word was used very precisely"
The only benchmarks I could find claims that it is significantly slower than Luajit. The official docs claim that the fastest implementation is available on fewer platforms than Luajit.
Regarding the lack of structs, the official docs say "pawn has no "struct"s, but it extends arrays so that it can mimic light-weight structures with arrays; as an example of those extensions, pawn supports array assignment and array indices can be assigned an individual "identify" (or "purpose") and even form a sub-array." but the manual's mentions of array assignment make it seem like that's just memcpy. One could imagine having bullet objects and declaring BULLET_X=0, BULLET_Y=1, BULLET_SPRITE_IDX=2, and so on, just so that when one has a bullet object and they would like to draw it at the right location they could avoid writing draw(b[2], b[0], b[1]). Having an array of untyped cells and memcpy isn't really the same as having a struct with named members. Please correct me if I'm wrong.
A lot of useful patterns become less possible when one does not have a map or set type and when one does not have coroutines. It seems like instead of coroutines Pawn includes a syntactic sugar for a switch statement that depends on a single global state variable, in which the cases can be declared like functions. This is interesting but not particularly helpful. Why can one not have multiple different state machines, multiple instances of a state machine, and so on?
Regarding the specifics: Lua is very simple, you can keep the whole language in your head easily, the table mechanism is very powerful, and the whole thing is easy to embed. Which is why it was used in commercial games and thus is industry/genre-relevant.
Lua's https://love2d.org/ is amazing.
https://pygame-zero.readthedocs.io
https://github.com/mjbrusso/game2dboard
Disclosure: I am the author of game2dboard
There's not even a note on the website that it's entirely broken in Mojave. It's just _always_ something.
Compared to LOVE and numerous other projects which just worked right out of the box. I'm a total Python guy, but Pygame has always been frustrating.
Never gotten a satisfactory answer.
Another reason for using Lua in games is that its garbage collection strategy is well-suited for the task.
Python uses reference counting (which has a predictable performance profile but can lead to long pauses if a large object graph is deallocated at once) and stop-the-world GC for reference cycles.
Lua is both easier to embed and allows you to have a strict interface. Look up the history of bastion/rexec in Python - with python there's no possibility of controlling untrusted code.
The cost is a less elegant syntax. I understand a lot of folks hate working with Lua, but it fits a certain niche.
Much like many people turn to Python for scientific scripting, for example, Lua has gained a reputation for being easy to use in the game development world.