Commit 19c5b6bf authored by louiz’'s avatar louiz’

Various improvements on the Attack ability

The fs and bs are now expressed as a Duration
We implement non-ranged attacks
And we do not use acquisition anymore
parent 7fdea0a0
......@@ -28,4 +28,9 @@ namespace utils
Duration t = now() - start_time;
return sec(t);
}
std::size_t duration_to_ticks(const Duration& duration)
{
return std::chrono::duration_cast<ticks>(duration).count();
}
}
......@@ -26,6 +26,8 @@ namespace utils
// The duration of a world tick, in microseconds
constexpr Duration tick_duration = std::chrono::duration_cast<Duration>(ticks(1));
std::size_t duration_to_ticks(const Duration& duration);
/**
* Returns the current time, from a steady clock
*/
......
......@@ -11,17 +11,19 @@ const std::string NamedAbility<Attack>::name = "Attack";
template<>
const AbilityType NamedAbility<Attack>::ability_type = AbilityType::Attack;
Attack::Attack(const std::size_t fs, const std::size_t bs):
Attack::Attack(const utils::Duration fs_duration, const utils::Duration bs_duration,
const Fix16 range):
ActiveAbility(TargetType::Both),
frontswing_duration(fs),
backswing_duration(bs)
frontswing_duration(utils::duration_to_ticks(fs_duration)),
backswing_duration(utils::duration_to_ticks(bs_duration)),
range(range)
{
}
void Attack::cast(Entity* entity, World*, const Position& pos, const bool queue)
{
log_debug("Attacking with entity " << entity->get_id() << " until position " << pos);
auto work = std::make_unique<AttackWork>(entity, pos);
auto work = std::make_unique<AttackWork>(entity, pos, this->range);
if (queue)
entity->queue_work(std::move(work));
else
......@@ -31,9 +33,19 @@ void Attack::cast(Entity* entity, World*, const Position& pos, const bool queue)
void Attack::cast(Entity* entity, World *, const std::shared_ptr<Entity>& target, const bool queue)
{
log_debug("Attacking with entity " << entity->get_id() << " the target " << target->get_id());
auto work = std::make_unique<AttackWork>(entity, target);
auto work = std::make_unique<AttackWork>(entity, target, this->range);
if (queue)
entity->queue_work(std::move(work));
else
entity->set_work(std::move(work));
}
std::size_t Attack::get_frontswing_duration() const
{
return this->frontswing_duration;
}
std::size_t Attack::get_backswing_duration() const
{
return this->backswing_duration;
}
......@@ -2,20 +2,25 @@
#define ATTACK_HPP_INCLUDED
#include <world/abilities/active_ability.hpp>
#include <utils/time.hpp>
#include <fixmath/fix16.hpp>
class Attack: public ActiveAbility<Attack>
{
public:
Attack(const std::size_t fs, const std::size_t bs);
Attack(const utils::Duration fs_duration, const utils::Duration bs_duration, const Fix16 range);
~Attack() = default;
void cast(Entity* entity, World *, const Position& pos, const bool queue) override final;
void cast(Entity* entity, World *, const std::shared_ptr<Entity>& target, const bool queue) override final;
protected:
std::size_t get_frontswing_duration() const;
std::size_t get_backswing_duration() const;
private:
std::size_t frontswing_duration;
std::size_t backswing_duration;
Fix16 range;
private:
Attack(const Attack&) = delete;
Attack(Attack&&) = delete;
Attack& operator=(const Attack&) = delete;
......
......@@ -15,6 +15,10 @@
#include <world/abilities/dash.hpp>
#include <world/abilities/concentrate.hpp>
#include <utils/time.hpp>
using namespace std::chrono_literals;
EntityFactory::EntityFactory()
{
}
......@@ -35,10 +39,9 @@ std::unique_ptr<Entity> EntityFactory::make_entity(const EntityType type)
entity->add_component(std::make_unique<Location>(20, true));
entity->add_component(std::make_unique<Team>());
entity->add_component(std::make_unique<Mobility>(3.8_fix));
entity->add_component(std::make_unique<Acquisition>(200_fix));
auto abilities = std::make_unique<Abilities>(6u, 0u, 0u);
abilities->add(0, std::make_unique<Attack>(5u, 2u));
abilities->add(0, std::make_unique<Attack>(300ms, 500ms, 400_fix));
abilities->add(1, std::make_unique<Blink>());
abilities->add(2, std::make_unique<Phase>());
abilities->add(3, std::make_unique<Emp>());
......
......@@ -2,21 +2,21 @@
#include <world/world.hpp>
#include <world/world_callbacks.hpp>
#include <world/entity.hpp>
#include <world/location.hpp>
#include <world/health.hpp>
#include <world/entity.hpp>
#include <world/works/projectile_work.hpp>
AttackTask::AttackTask(Entity* entity, std::weak_ptr<Entity> target):
AttackTask::AttackTask(Entity* entity, std::weak_ptr<Entity> target, const std::size_t fs, const std::size_t bs, const bool ranged):
Task(entity),
target(target),
location(entity->get<Location>()),
frontswing(80u),
backswing(80u),
attack_point_reached(false)
frontswing(fs),
backswing(bs),
attack_point_reached(false),
ranged(ranged)
{
assert(location);
// Set front and backswing from the entity
}
bool AttackTask::tick(World* world)
......@@ -38,21 +38,30 @@ bool AttackTask::tick(World* world)
this->attack_point_reached = true;
world->callbacks->ability_casted(this->entity, AbilityType::Attack,
target.get(), Position::zero);
// Only if ranged entity
Entity* projectile = world->do_new_entity(1, this->location->position(), 1);
projectile->set_work(
std::make_unique<ProjectileWork>(projectile, this->target, [](Entity* target) -> void
{
Health* health = target->get<Health>();
assert(health);
health->add(-10);
}));
this->do_attack(world);
}
if (this->backswing)
if (!this->backswing)
return true;
this->backswing--;
return false;
}
void AttackTask::do_attack(World* world)
{
auto cb = [](Entity* target) -> void
{
this->backswing--;
return false;
Health* health = target->get<Health>();
assert(health);
health->add(-10);
};
if (this->ranged)
{
Entity* projectile = world->do_new_entity(1, this->location->position(), 1);
projectile->set_work(
std::make_unique<ProjectileWork>(projectile,
this->target,
std::move(cb)));
}
else
return true;
cb(this->target.lock().get());
}
......@@ -10,23 +10,28 @@ class Location;
class AttackTask: public Task
{
public:
AttackTask(Entity* entity, std::weak_ptr<Entity> target);
AttackTask(Entity* entity, std::weak_ptr<Entity> target, const std::size_t fs,
const std::size_t bs, const bool ranged);
~AttackTask() = default;
bool tick(World* world) override final;
TaskType get_type() const override final
{ return TaskType::Attack; }
private:
void do_attack(World* world);
/**
* If the target becomes unavailable before the attack point is reached,
* this task is over.
*/
std::weak_ptr<Entity> target;
Location* location;
/**
* Number of ticks needed to complete the front and backswings
*/
std::size_t frontswing;
std::size_t backswing;
bool attack_point_reached;
const bool ranged;
AttackTask(const AttackTask&) = delete;
AttackTask(AttackTask&&) = delete;
......
......@@ -41,7 +41,7 @@ bool EmpTask::tick(World* world)
ManaPool* mana = entity->get<ManaPool>();
if (!health || !mana)
continue;
health->add(-500);
health->add(-120);
mana->add(-500);
}
this->entity->kill();
......
......@@ -4,26 +4,32 @@
#include <world/world.hpp>
#include <world/health.hpp>
#include <world/location.hpp>
#include <world/acquisition.hpp>
#include <world/team.hpp>
#include <world/tasks/attack_task.hpp>
#include <world/tasks/path_task.hpp>
#include <world/tasks/follow_task.hpp>
#include <world/abilities.hpp>
#include <world/abilities/attack.hpp>
#include <logging/logging.hpp>
AttackWork::AttackWork(Entity* entity, const Position& destination):
AttackWork(entity, {}, destination)
AttackWork::AttackWork(Entity* entity, const Position& destination, const Fix16 range):
AttackWork(entity, {}, range, destination)
{
}
AttackWork::AttackWork(Entity* entity, std::weak_ptr<Entity> target, const Position& destination):
AttackWork::AttackWork(Entity* entity, std::weak_ptr<Entity> target, const Fix16 range,
const Position& destination):
Work(entity),
location(entity->get<Location>()),
acquire_distance(380_fix),
destination(destination),
target(target)
target(target),
attack(static_cast<Attack*>(entity->get<Abilities>()->find(AbilityType::Attack))),
range(range)
{
assert(location);
assert(this->location);
assert(this->attack);
}
void AttackWork::try_acquire_target(World* world)
......@@ -48,7 +54,7 @@ void AttackWork::try_acquire_target(World* world)
continue;
Fix16 distance = Position::distance(location->position(),
this->location->position());
if (distance < this->acquire_distance &&
if (distance < this->range &&
(res == world->entities.end() || distance < best_distance))
{
best_distance = distance;
......@@ -56,7 +62,11 @@ void AttackWork::try_acquire_target(World* world)
}
}
if (res != world->entities.end())
this->set_task(world, std::make_unique<AttackTask>(this->entity, *res));
this->set_task(world,
std::make_unique<AttackTask>(this->entity, *res,
this->attack->get_frontswing_duration(),
this->attack->get_backswing_duration(),
this->range > 0_fix));
}
bool AttackWork::tick(World* world)
......@@ -89,8 +99,11 @@ bool AttackWork::tick(World* world)
Location* target_location = this->target.lock()->get<Location>();
assert(target_location);
if (Position::distance(target_location->position(),
this->location->position()) < this->acquire_distance)
this->set_task(world, std::make_unique<AttackTask>(this->entity, this->target));
this->location->position()) < this->range)
this->set_task(world, std::make_unique<AttackTask>(this->entity, this->target,
this->attack->get_frontswing_duration(),
this->attack->get_backswing_duration(),
this->range > 0_fix));
else if (!this->task)
this->set_task(world, std::make_unique<FollowTask>(this->entity, this->target));
}
......
......@@ -9,6 +9,7 @@
class Entity;
class World;
class Location;
class Attack;
/**
* Move until the destination is reached
......@@ -17,8 +18,8 @@ class Location;
class AttackWork: public Work
{
public:
AttackWork(Entity* entity, const Position& destination);
AttackWork(Entity* entity, std::weak_ptr<Entity> target,
AttackWork(Entity* entity, const Position& destination, const Fix16 range);
AttackWork(Entity* entity, std::weak_ptr<Entity> target, const Fix16 range,
const Position& destination = Position::invalid);
~AttackWork() = default;
bool tick(World* world) override final;
......@@ -26,9 +27,10 @@ public:
private:
void try_acquire_target(World* world);
// The entity position, to do the acquire-target thing
/**
* The entity position, to do the acquire-target thing
*/
Location* location;
Fix16 acquire_distance;
/**
* Only used when attacking a position, if we attack a target, it's set to
* Position::invalid.
......@@ -38,6 +40,17 @@ private:
* Only used when attacking a specific target
*/
const std::weak_ptr<Entity> target;
/**
* Pointer on the ability of the attacking entity. We need it to get the
* attack's attributes of this entity (for example the backswing,
* frontswing, damage, etc)
*/
Attack* attack;
/**
* The range of the attack. If it's 0, it's a melee attack (we do not
* spawn any projectile)
*/
const Fix16 range;
AttackWork(const AttackWork&) = delete;
AttackWork(AttackWork&&) = delete;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment