Complete roguelike tutorial using C++ and libtcod - part 9: spells and ranged combat
Complete roguelike tutorial using C++ and libtcod -originally written by Jice Text in this tutorial was released under the Creative Commons Attribution-ShareAlike 3.0 Unported and the GNU Free Documentation License (unversioned, with no invariant sections, front-cover texts, or back-cover texts) on 2015-09-21. |
---|
|
In this article, we'll start to add diversity to the gameplay by adding three new spells :
- lightning bolt : deals damages to the closest enemy
- fireball : powerful area effect spell
- confusion : turns the selected enemy into a randomly wandering zombie for a few turns
The scroll of lightning bolt
This dreadful spell will deal 20 damage to the closest monster, up to a distance of 5 tiles. So the first thing we need is some helper functions to get the closest monster within a range.
Some helpers
The easiest is a function to get the distance from an actor to a specific tile of the map :
Actor.hpp
float getDistance(int cx, int cy) const;
Actor.cpp
float Actor::getDistance(int cx, int cy) const { int dx=x-cx; int dy=y-cy; return sqrtf(dx*dx+dy*dy); }
Well that was a small warmup. Don't forget to include math.h for the sqrtf function. Now let's do something manlier.
Engine.hpp
Actor *getClosestMonster(int x, int y, float range) const;
This function returns the closest monster from position x,y within range. If range is 0, it's considered infinite. If no monster is found within range, it returns NULL.
Engine.cpp
Actor *Engine::getClosestMonster(int x, int y, float range) const { Actor *closest=NULL; float bestDistance=1E6f;
First we declare some variable. closest is the closest monster found so far. bestDistance is the distance for the closest monster found so far. We initialize it with a value higher than any possible value (1E6 == 1000000) so that the first monster in the range will be a candidate. So let's iterate over the actors list and check alive monsters :
for (Actor **iterator=actors.begin(); iterator != actors.end(); iterator++) { Actor *actor=*iterator; if ( actor != player && actor->destructible && !actor->destructible->isDead() ) { Now let's check if the guy is within range and closer than what we found so far.
float distance=actor->getDistance(x,y); if ( distance < bestDistance && ( distance <= range || range == 0.0f ) ) { bestDistance=distance; closest=actor; } } } return closest; }