Use IS-A and inheritance to model functional interfaces and abstractions that you program against, e.g. FmodAudioService IS-A(n) AudioService, and not to model your real-world taxonomies.
Another that may be more familiar to developers on the board is graphics cards.
You request a Direct3D device and the system provides it. It doesn't matter what the device is, as long as it satisfies the requirements.
He used this example:
if (theBaddie is Knight) { ... }
if (theBaddie is Wizard) { ... }
...
which in practice is extremely rare for properly written inheritance.
Imagine the rough equivalent:
if( myD3DDevice is GeForce980) {...}
if( myD3DDevice is GeForce970) {...}
if( myD3DDevice is RadeonR9295) {...}
if( myD3DDevice is RadeonR9290) {...}
... repeated for many different cards ...
About the only time you would do something like that is if you had some extremely specific bug on a card, and you'd likely be testing both the card and the firmware version. If you've done everything correctly you don't need to know any of it. You just call CreateTexture2D() or whatever you need on the device and it just works.
When it comes to inheritance in c++, the Liskov Substitution principle (already mentioned above) is very closely related to the Dependency Inversion Principle. You should be able to specify an interface and the consumers of the class should be able to do all their work only by using that interface.
I should be able to obtain a ID3D11Device and not care what the actual concrete class is; it satisfies the description and therefore I am satisfied. The actual driver may present me with many different varieties of devices that work. It might be a card that just barely meets the specification. It might be a super fancy new card. It might be a card released five years from now. It might be a software-based reference implementation. The code should not know or care, all it needs to know is that the object meets the interface requirements.
Moving the analogue back to the question:
I should be able to create a Baddie object (whatever that is) and not care what the actual concrete class is; it may be a Wizard or Knight or anything else, I don't care and I'll never bother to check, it satisfies the description and I am satisfied.
I do not know if the Baddie object is a low-level grunt or an end of level boss. I don't know if the Baddie object is a tank or a turret or a dragon or a paratrooper. All I know is that it satisfies the Baddie object interface, and I can use it in exactly the same way I use every other Baddie object.
If it becomes necessary to know details, such as if it is a Wizard or Knight or some other type, that is almost certainly a defect. It may be a design defect (you shouldn't have used inheritance) or it may be an implementation defect (you shouldn't peek inside the implementation details), but either way it stays a defect.