Bunch of stuff, preparing for items
This commit is contained in:
parent
97189fc442
commit
d32d448f31
26 changed files with 425 additions and 241 deletions
|
@ -2,28 +2,16 @@
|
|||
#include "Tilemap.h"
|
||||
#include "BehaviourTree.h"
|
||||
|
||||
int idcounter = 0;
|
||||
int id_counter = 0;
|
||||
|
||||
Actor::Actor(Tilemap * map, vec2i pos) {
|
||||
id = idcounter++;
|
||||
Actor::Actor(Tilemap *map, vec2i pos) : Entity(map, pos) {
|
||||
id = id_counter++;
|
||||
name = "Actor";
|
||||
this->map = map;
|
||||
position = pos;
|
||||
range = 1.5f;
|
||||
collision = true;
|
||||
bt = nullptr;
|
||||
}
|
||||
|
||||
const vec2i Actor::get_position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
bool Actor::Move(int dx, int dy) {
|
||||
vec2i newpos = position + vec2i(dx, dy); //GoTo({0,0}, {dx,dy});
|
||||
//dir = ParseDir(dx, dy);
|
||||
if (!map->IsBlocked(newpos.x, newpos.y)) {
|
||||
position = newpos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
team = TEAM_NONE;
|
||||
sprite_id = 1;
|
||||
}
|
||||
|
||||
void Actor::update() {
|
||||
|
@ -32,16 +20,52 @@ void Actor::update() {
|
|||
if (bt != nullptr) {
|
||||
bt->tick(this);
|
||||
}
|
||||
if (health < maxhealth) {
|
||||
if (health < health_max) {
|
||||
if (healcounter <= 0) {
|
||||
health++;
|
||||
healcounter = 4;
|
||||
}
|
||||
healcounter--;
|
||||
}
|
||||
|
||||
if (health <= 0) {
|
||||
Kill();
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::damage(int strength) {
|
||||
health -= strength;
|
||||
if (health <= 0) {
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::attack(Actor *act) {
|
||||
if (act) {
|
||||
vec2i dpos = get_position() - act->get_position();
|
||||
if (dpos.dist() <= range) {
|
||||
act->damage(strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::attack(vec2i dpos) {
|
||||
if (dpos.dist() <= range) {
|
||||
vec2i pos = get_position();
|
||||
auto acts = get_map()->get_entities(pos.x + dpos.x, pos.y + dpos.y, 0, ENTITY_ACTOR);
|
||||
for (Entity* ent : acts) {
|
||||
auto act = (Actor*)ent;
|
||||
if (act->is_alive() && act->get_actor_team() != team) {
|
||||
act->damage(strength);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Actor::heal(int amount) {
|
||||
health += amount;
|
||||
if (health > health_max) {
|
||||
health = health_max;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
45
src/Actor.h
45
src/Actor.h
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "vec2i.h"
|
||||
#include "Entity.h"
|
||||
#include <string>
|
||||
|
||||
class BehaviourTree;
|
||||
|
@ -11,32 +12,44 @@ enum Actors {
|
|||
ACT_SHAMAN
|
||||
};
|
||||
|
||||
enum ActorTeams {
|
||||
TEAM_NONE,
|
||||
TEAM_PLAYER,
|
||||
TEAM_GOBS
|
||||
};
|
||||
|
||||
class Tilemap;
|
||||
|
||||
class Actor {
|
||||
vec2i position;
|
||||
class Actor : public Entity {
|
||||
int healcounter;
|
||||
|
||||
protected:
|
||||
BehaviourTree* bt;
|
||||
int health;
|
||||
int health_max;
|
||||
int strength;
|
||||
float range;
|
||||
bool alive;
|
||||
ActorTeams team;
|
||||
public:
|
||||
int id;
|
||||
std::string name;
|
||||
Tilemap* map;
|
||||
bool alive;
|
||||
int health;
|
||||
int maxhealth;
|
||||
int strength;
|
||||
|
||||
|
||||
Actor(Tilemap* map, vec2i pos);
|
||||
const vec2i get_position();
|
||||
bool IsAlive(){ return alive; };
|
||||
bool Move(int dx, int dy);
|
||||
int GetHealth() { return health; }
|
||||
void Kill() { alive = false; health = 0; };
|
||||
Actor(Tilemap *map, vec2i pos);
|
||||
bool is_alive(){ return alive; };
|
||||
void attack(vec2i dpos); // basic melee attack
|
||||
void attack(Actor* act);
|
||||
void heal(int amount);
|
||||
void damage(int strength);
|
||||
int get_strength() { return strength; }
|
||||
int get_health() { return health; }
|
||||
int get_health_max() { return health_max; }
|
||||
ActorTeams get_actor_team() { return team; }
|
||||
float get_range() { return range; }
|
||||
void kill() { alive = false; health = 0; collision = false; };
|
||||
void update();
|
||||
virtual bool isTypeOf(Actors actor){ return actor == ACT_BASE; };
|
||||
virtual Actors Type() { return ACT_BASE; };
|
||||
virtual bool is_type_of(Actors actor){ return actor == ACT_BASE; };
|
||||
virtual Actors type() { return ACT_BASE; };
|
||||
EntityTypes entity_type() override { return ENTITY_ACTOR; };
|
||||
~Actor();
|
||||
};
|
||||
|
|
|
@ -7,31 +7,34 @@
|
|||
|
||||
AttackEnemyNode::AttackEnemyNode(BehaviourTreeNode * parent) : BehaviourTreeNode(parent){}
|
||||
|
||||
AttackEnemyNode::~AttackEnemyNode() {}
|
||||
AttackEnemyNode::~AttackEnemyNode() = default;
|
||||
|
||||
BehaviourTreeStatus AttackEnemyNode::tick(BTTick * tick) {
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
std::vector<Actor*> visibleEnemies;
|
||||
|
||||
for (auto actor : *actors) {
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) != ishero) {
|
||||
|
||||
if (actor->is_type_of(ACT_HERO) != ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
visibleEnemies.push_back(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (visibleEnemies.size() == 0) {
|
||||
if (visibleEnemies.empty()) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
|
||||
Actor* closestActor = nullptr;
|
||||
float closestDist;
|
||||
float closestDist = tick->target->get_range();
|
||||
for (Actor* actor : visibleEnemies) {
|
||||
float dist = Pathfinder::distance(tick->target->get_position(), actor->get_position());
|
||||
if (closestActor == nullptr ||
|
||||
|
@ -41,10 +44,9 @@ BehaviourTreeStatus AttackEnemyNode::tick(BTTick * tick) {
|
|||
}
|
||||
}
|
||||
|
||||
if (closestDist < 1.5f) {
|
||||
closestActor->health -= tick->target->strength;
|
||||
if (closestActor->health <= 0) {
|
||||
closestActor->Kill();
|
||||
if (closestDist < tick->target->get_range()) {
|
||||
tick->target->attack(closestActor);
|
||||
if (!closestActor->is_alive()) {
|
||||
return BT_SUCCEEDED;
|
||||
}
|
||||
return BT_RUNNING;
|
||||
|
@ -52,11 +54,11 @@ BehaviourTreeStatus AttackEnemyNode::tick(BTTick * tick) {
|
|||
else {
|
||||
vec2i pos = tick->target->get_position();
|
||||
vec2i goal = closestActor->get_position();
|
||||
auto path = Pathfinder::aStar(tick->target->map, pos, goal);
|
||||
if (path.size() > 0) {
|
||||
auto path = Pathfinder::aStar(tick->target->get_map(), pos, goal);
|
||||
if (!path.empty()) {
|
||||
//path.pop_back();
|
||||
vec2i dpos = path.back() - pos;
|
||||
if (tick->target->Move(dpos.x, dpos.y)) {
|
||||
if (tick->target->move(dpos.x, dpos.y)) {
|
||||
return BT_RUNNING;
|
||||
}
|
||||
}
|
||||
|
|
43
src/Entity.cpp
Normal file
43
src/Entity.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Adrian on 2017-09-25.
|
||||
//
|
||||
|
||||
#include "Entity.h"
|
||||
#include "Tilemap.h"
|
||||
|
||||
Entity::Entity(Tilemap *map, vec2i pos) {
|
||||
this->map = map;
|
||||
position = pos;
|
||||
collision = false;
|
||||
sprite_id = '?';
|
||||
}
|
||||
|
||||
vec2i Entity::get_position() {
|
||||
return position;
|
||||
}
|
||||
|
||||
bool Entity::move(vec2i dpos) {
|
||||
return move(dpos.x, dpos.y);
|
||||
}
|
||||
|
||||
bool Entity::move(int dx, int dy) {
|
||||
vec2i newpos = position + vec2i(dx, dy); //GoTo({0,0}, {dx,dy});
|
||||
//dir = ParseDir(dx, dy);
|
||||
if (!collision || !map->IsBlocked(newpos.x, newpos.y)) {
|
||||
position = newpos;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Entity::set_position(vec2i pos) {
|
||||
position = pos;
|
||||
}
|
||||
|
||||
Tilemap *Entity::get_map() {
|
||||
return map;
|
||||
}
|
||||
|
||||
bool Entity::has_collision() {
|
||||
return collision;
|
||||
}
|
39
src/Entity.h
Normal file
39
src/Entity.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by Adrian on 2017-09-25.
|
||||
//
|
||||
|
||||
#ifndef DUNGEON_ENTITY_H
|
||||
#define DUNGEON_ENTITY_H
|
||||
|
||||
|
||||
#include "vec2i.h"
|
||||
|
||||
class Tilemap;
|
||||
|
||||
enum EntityTypes {
|
||||
ENTITY_BASE, // All entities are objects that can be placed on the map and can be interacted with
|
||||
ENTITY_ACTOR, // Actors are characters with AI or controlled by the player
|
||||
ENTITY_ITEM, // Items can be picked up
|
||||
};
|
||||
|
||||
class Entity {
|
||||
vec2i position;
|
||||
Tilemap* map;
|
||||
protected:
|
||||
unsigned int sprite_id;
|
||||
bool collision;
|
||||
public:
|
||||
Entity(Tilemap* map, vec2i pos);
|
||||
|
||||
Tilemap* get_map();
|
||||
vec2i get_position();
|
||||
bool has_collision();
|
||||
bool move(int dx, int dy); // returns false if movement failed
|
||||
bool move(vec2i dpos);
|
||||
void set_position(vec2i pos);
|
||||
unsigned int get_sprite_id() { return sprite_id; };
|
||||
virtual EntityTypes entity_type() { return ENTITY_BASE; };
|
||||
};
|
||||
|
||||
|
||||
#endif //DUNGEON_ENTITY_H
|
|
@ -49,7 +49,7 @@ BehaviourTreeStatus ExploreNode::tick(BTTick * tick) {
|
|||
int i = std::rand() % options.size();
|
||||
vec2i next = options[i];
|
||||
vec2i dp = next - pos;
|
||||
if (tick->target->Move(dp.x, dp.y)) {
|
||||
if (tick->target->move(dp.x, dp.y)) {
|
||||
//printf("EXPLORE %f\n", lowestval);
|
||||
return BT_RUNNING;
|
||||
}
|
||||
|
|
|
@ -10,23 +10,25 @@
|
|||
FleeNode::FleeNode(BehaviourTreeNode* parent) : BehaviourTreeNode(parent) {}
|
||||
|
||||
|
||||
FleeNode::~FleeNode() {}
|
||||
FleeNode::~FleeNode() = default;
|
||||
|
||||
BehaviourTreeStatus FleeNode::tick(BTTick * tick) {
|
||||
Pathfinder::DijkstraMap dijkstra;
|
||||
Tilemap * map = tick->target->map;
|
||||
Tilemap * map = tick->target->get_map();
|
||||
std::vector<vec2i> enemyPos;
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
for (Actor* actor : *actors) {
|
||||
if (actor->isTypeOf(ACT_HERO) != ishero) {
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor->is_type_of(ACT_HERO) != ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
enemyPos.push_back(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enemyPos.size() <= 0) {
|
||||
if (enemyPos.empty()) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
Pathfinder::calcDijkstraMap(map, &enemyPos, &dijkstra, 16);
|
||||
|
@ -38,7 +40,7 @@ BehaviourTreeStatus FleeNode::tick(BTTick * tick) {
|
|||
for (int x = 0; x < dijkstra.width; x++) {
|
||||
for (int y = 0; y < dijkstra.height; y++) {
|
||||
if (dijkstra.getValue(x,y) <= 0 && dijkstra.getValue(x, y) >= -10) {
|
||||
safety.push_back(vec2i(x, y));
|
||||
safety.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,16 +67,16 @@ BehaviourTreeStatus FleeNode::tick(BTTick * tick) {
|
|||
//printf("FLEEING SUCCESS\n");
|
||||
return BT_FAILED;
|
||||
}
|
||||
while (options.size() > 0) {
|
||||
while (!options.empty()) {
|
||||
int i = rand() % options.size();
|
||||
vec2i next = options[i];
|
||||
vec2i dp = next - pos;
|
||||
if (tick->target->Move(dp.x, dp.y)) {
|
||||
if (tick->target->move(dp.x, dp.y)) {
|
||||
//printf("FLEEING val:%f\t(%i,%i)\n", lowestval, next.x, next.y);
|
||||
return BT_RUNNING;
|
||||
}
|
||||
options.erase(options.begin() + i);
|
||||
if (options.size() == 0) {
|
||||
if (options.empty()) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,11 @@ Goblin::Goblin(Tilemap* map, vec2i pos) : Actor(map, pos) {
|
|||
name = "Goblin";
|
||||
alive = true;
|
||||
health = 4;
|
||||
maxhealth = 4;
|
||||
health_max = 4;
|
||||
strength = 1;
|
||||
sprite_id = 'g';
|
||||
team = TEAM_GOBS;
|
||||
|
||||
if (gobtree == nullptr) {
|
||||
auto * root = new BehaviourTreeSelector(nullptr);
|
||||
gobtree = new BehaviourTree(root);
|
||||
|
|
|
@ -6,7 +6,7 @@ class Goblin :
|
|||
public:
|
||||
Goblin(Tilemap* map, vec2i pos);
|
||||
~Goblin();
|
||||
bool isTypeOf(Actors actor) { return actor == ACT_GOBLIN || Actor::isTypeOf(actor); };
|
||||
Actors Type() { return ACT_GOBLIN; }
|
||||
bool is_type_of(Actors actor) { return actor == ACT_GOBLIN || Actor::is_type_of(actor); };
|
||||
Actors type() { return ACT_GOBLIN; }
|
||||
};
|
||||
|
||||
|
|
|
@ -7,37 +7,39 @@
|
|||
|
||||
HealFriendNode::HealFriendNode(BehaviourTreeNode * parent) : BehaviourTreeNode(parent){}
|
||||
|
||||
HealFriendNode::~HealFriendNode() {}
|
||||
HealFriendNode::~HealFriendNode() = default;
|
||||
|
||||
BehaviourTreeStatus HealFriendNode::tick(BTTick * tick) {
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
std::vector<Actor*> friends;
|
||||
for (auto actor : *actors) {
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) == ishero && actor->health < actor->maxhealth-1) {
|
||||
if (actor->is_type_of(ACT_HERO) == ishero && actor->get_health() < actor->get_health_max()) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
friends.push_back(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (friends.size() == 0) {
|
||||
if (friends.empty()) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
|
||||
Actor* lowestHpActor = nullptr;
|
||||
int lowestHp;
|
||||
for (Actor* actor : friends) {
|
||||
if (lowestHpActor == nullptr || actor->health < lowestHp) {
|
||||
if (lowestHpActor == nullptr || actor->get_health() < lowestHp) {
|
||||
lowestHpActor = actor;
|
||||
lowestHp = actor->health;
|
||||
lowestHp = actor->get_health();
|
||||
}
|
||||
}
|
||||
|
||||
lowestHpActor->health += 1;
|
||||
lowestHpActor->heal(1);
|
||||
return BT_SUCCEEDED;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,10 @@ Hero::Hero(Tilemap* map, vec2i pos) : Actor(map, pos) {
|
|||
name = "Hero";
|
||||
alive = true;
|
||||
health = 6;
|
||||
maxhealth = 6;
|
||||
health_max = 6;
|
||||
strength = 2;
|
||||
sprite_id = '@';
|
||||
team = TEAM_PLAYER;
|
||||
/*
|
||||
BehaviourTreeSelector* root = new BehaviourTreeSelector(nullptr);
|
||||
bt = new BehaviourTree(root);
|
||||
|
|
|
@ -5,7 +5,7 @@ class Hero : public Actor {
|
|||
public:
|
||||
Hero(Tilemap* map, vec2i pos);
|
||||
~Hero();
|
||||
bool isTypeOf(Actors actor) { return actor == ACT_HERO || Actor::isTypeOf(actor); };
|
||||
Actors Type() { return ACT_HERO; }
|
||||
bool is_type_of(Actors actor) { return actor == ACT_HERO || Actor::is_type_of(actor); };
|
||||
Actors type() { return ACT_HERO; }
|
||||
};
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ IfHealthBelow::IfHealthBelow(BehaviourTreeNode * root, int healthBelow) : Behavi
|
|||
this->healthBelow = healthBelow;
|
||||
}
|
||||
|
||||
IfHealthBelow::~IfHealthBelow() {}
|
||||
IfHealthBelow::~IfHealthBelow() = default;
|
||||
|
||||
BehaviourTreeStatus IfHealthBelow::tick(BTTick * tick) {
|
||||
if (children.size() == 0) return BT_ERROR;
|
||||
if (tick->target->health < healthBelow) {
|
||||
if (children.empty()) return BT_ERROR;
|
||||
if (tick->target->get_health() < healthBelow) {
|
||||
return children[0]->execute(tick);
|
||||
}
|
||||
return BT_FAILED;
|
||||
|
|
|
@ -13,15 +13,17 @@ BehaviourTreeStatus IfNotSeeEnemyNode::tick(BTTick * tick) {
|
|||
if (children.size() <= 0) {
|
||||
return BT_ERROR;
|
||||
}
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
for (auto actor : *actors) {
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) != ishero) {
|
||||
if (actor->is_type_of(ACT_HERO) != ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,15 +13,17 @@ BehaviourTreeStatus IfSeeEnemyNode::tick(BTTick * tick) {
|
|||
if (children.size() <= 0) {
|
||||
return BT_ERROR;
|
||||
}
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
for (auto actor : *actors) {
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) != ishero) {
|
||||
if (actor->is_type_of(ACT_HERO) != ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
return children[0]->execute(tick);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,17 @@ BehaviourTreeStatus IfSeeFriendNode::tick(BTTick * tick) {
|
|||
if (children.size() <= 0) {
|
||||
return BT_ERROR;
|
||||
}
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
for (auto actor : *actors) {
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) == ishero) {
|
||||
if (actor->is_type_of(ACT_HERO) == ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
return children[0]->execute(tick);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include "Renderer.h"
|
||||
#include "Actor.h"
|
||||
#include "App.h"
|
||||
#include "Tilemap.h"
|
||||
#include "Tileset.h"
|
||||
#include "Tilemap.h"
|
||||
#include "FieldOfView.h"
|
||||
#include "imgui.h"
|
||||
#include "Hero.h"
|
||||
|
@ -16,40 +16,6 @@
|
|||
#include "Shaman.h"
|
||||
|
||||
const int mapwidth = 32;
|
||||
const std::string map =
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# @ . . . # # # # # # # # . . . . . . . . . . . . . . . . . # #"
|
||||
"# . . . . . . . . # # # # . # # . # # # # # # . # # # # # . # #"
|
||||
"# . . . . # # # . . . . . . # . g . # # # # # . # # # . . g . #"
|
||||
"# . . . . # # # # # # # # . # . . . # # . . . . . . . . . . . #"
|
||||
"# # # . # # # # # # # # # . . . . g # # . # # # . # # . . g . #"
|
||||
"# . . . . . . . . . . . . . # # # # # . . . # # . # # # # # # #"
|
||||
"# . # # # # # # # # . # # . # # # # # . g . # # . # . . g . . #"
|
||||
"# . . . . g # # . . . # . . . # # # # . . . # # . # . . . . . #"
|
||||
"# . . g . . # # . # # # . s . . . # # # # # # # . . . . s . . #"
|
||||
"# . . . . . # # . . . # . . . # . . . . . . . . . # . g . . . #"
|
||||
"# # . # # # # # . # . # # # # # # # # # . # # # # # # # # . # #"
|
||||
"# . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . #"
|
||||
"# . # # # # # # # # # # . # . # # # # # # # # # # . # # # # . #"
|
||||
"# . . . . . . . . . . . . # . # . . . . # . . . . . # # # . . #"
|
||||
"# # # # # # . # # # . # # # . # . . . . # . . . # . # # # . # #"
|
||||
"# . . . . # . # . . . . . # . . . . . . . . . . # . # # . . . #"
|
||||
"# . . . . # . # . . . . . # . # . . . . # # # # # . . . . . . #"
|
||||
"# . . . . . . # . . . . . # . # # # # # # . . . . . # # . . . #"
|
||||
"# . . . . # . # # # # # # # . . . . . . . . # # # # # # # # # #"
|
||||
"# . . . . # . . . . . . . . . # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #";
|
||||
|
||||
InputAction action;
|
||||
|
||||
|
@ -68,6 +34,10 @@ void PlayState::load() {
|
|||
app->input->bind_key(SDLK_KP_1, ACTION_MOVE_SOUTHWEST);
|
||||
app->input->bind_key(SDLK_KP_3, ACTION_MOVE_SOUTHEAST);
|
||||
app->input->bind_key(SDLK_KP_5, ACTION_WAIT);
|
||||
app->input->bind_key(SDLK_UP, ACTION_MOVE_NORTH);
|
||||
app->input->bind_key(SDLK_DOWN, ACTION_MOVE_SOUTH);
|
||||
app->input->bind_key(SDLK_LEFT, ACTION_MOVE_WEST);
|
||||
app->input->bind_key(SDLK_RIGHT, ACTION_MOVE_EAST);
|
||||
app->input->bind_key(SDLK_F1, ACTION_TOGGLE_DEBUG);
|
||||
|
||||
app->input->bind_key(SDLK_r, ACTION_RESET);
|
||||
|
@ -95,6 +65,41 @@ void PlayState::new_game() {
|
|||
fov = nullptr;
|
||||
}
|
||||
|
||||
std::string map =
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# @ . . . # # # # # # # # . . . . . . . . . . . . . . . . . # #"
|
||||
"# . . . . . . . . # # # # . # # . # # # # # # . # # # # # . # #"
|
||||
"# . . . . # # # . . . . . . # . g . # # # # # . # # # . . g . #"
|
||||
"# . . . . # # # # # # # # . # . . . # # . . . . . . . . . . . #"
|
||||
"# # # . # # # # # # # # # . . . . g # # . # # # . # # . . g . #"
|
||||
"# . . . . . . . . . . . . . # # # # # . . . # # . # # # # # # #"
|
||||
"# . # # # # # # # # . # # . # # # # # . g . # # . # . . g . . #"
|
||||
"# . . . . g # # . . . # . . . # # # # . . . # # . # . . . . . #"
|
||||
"# . . g . . # # . # # # . s . . . # # # # # # # . . . . s . . #"
|
||||
"# . . . . . # # . . . # . . . # . . . . . . . . . # . g . . . #"
|
||||
"# # . # # # # # . # . # # # # # # # # # . # # # # # # # # . # #"
|
||||
"# . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . #"
|
||||
"# . # # # # # # # # # # . # . # # # # # # # # # # . # # # # . #"
|
||||
"# . . . . . . . . . . . . # . # . . . . # . . . . . # # # . . #"
|
||||
"# # # # # # . # # # . # # # . # . . . . # . . . # . # # # . # #"
|
||||
"# . . . . # . # . . . . . # . . . . . . . . . . # . # # . . . #"
|
||||
"# . . . . # . # . . . . . # . # . . . . # # # # # . . . . . . #"
|
||||
"# . . . . . . # . . . . . # . # # # # # # . . . . . # # . . . #"
|
||||
"# . . . . # . # # # # # # # . . . . . . . . # # # # # # # # # #"
|
||||
"# . . . . # . . . . . . . . . # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #"
|
||||
"# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #";
|
||||
|
||||
SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, "Creating tilemap...\n");
|
||||
tilemap = new Tilemap(32, 32);
|
||||
int y = 0;
|
||||
|
@ -114,15 +119,15 @@ void PlayState::new_game() {
|
|||
|
||||
if (i == '@') {
|
||||
hero = new Hero(tilemap, vec2i(x, y));
|
||||
tilemap->add_actor(hero);
|
||||
tilemap->add_entity(hero);
|
||||
tilemap->set_tile(x, y, '.');
|
||||
}
|
||||
else if (i == 'g') {
|
||||
tilemap->add_actor(new Goblin(tilemap, vec2i(x, y)));
|
||||
tilemap->add_entity(new Goblin(tilemap, vec2i(x, y)));
|
||||
tilemap->set_tile(x, y, '.');
|
||||
}
|
||||
else if (i == 's') {
|
||||
tilemap->add_actor(new Shaman(tilemap, vec2i(x, y)));
|
||||
tilemap->add_entity(new Shaman(tilemap, vec2i(x, y)));
|
||||
tilemap->set_tile(x, y, '.');
|
||||
}
|
||||
else {
|
||||
|
@ -139,7 +144,7 @@ void PlayState::new_game() {
|
|||
|
||||
Gamestate *PlayState::update(double delta) {
|
||||
if (action != ACTION_NONE) {
|
||||
if (hero) {
|
||||
if (hero && hero->is_alive()) {
|
||||
vec2i dir;
|
||||
switch (action) {
|
||||
case ACTION_MOVE_NORTH: dir = {0, -1}; break;
|
||||
|
@ -154,17 +159,18 @@ Gamestate *PlayState::update(double delta) {
|
|||
default: action = ACTION_NONE; return nullptr; // abort turn
|
||||
}
|
||||
if (dir != vec2i(0,0)) {
|
||||
if (!hero->Move(dir.x, dir.y)) {
|
||||
if (!hero->move(dir.x, dir.y)) {
|
||||
vec2i heropos = hero->get_position();
|
||||
Actor* act = tilemap->GetActor(heropos.x + dir.x, heropos.y + dir.y, ACT_BASE);
|
||||
if (act) {
|
||||
act->health -= hero->strength;
|
||||
if (act->health <= 0) {
|
||||
act->Kill();
|
||||
}
|
||||
auto acts = tilemap->get_entities(heropos.x + dir.x, heropos.y + dir.y, 0, ENTITY_ACTOR);
|
||||
if(acts.empty()) {
|
||||
return nullptr; // unable to move and nothing to attack == abort turn
|
||||
}
|
||||
else {
|
||||
return nullptr; // abort turn
|
||||
for (auto ent : acts) {
|
||||
auto act = (Actor*)ent;
|
||||
if (act->is_alive() && act->get_actor_team() != hero->get_actor_team()) {
|
||||
hero->attack(act);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,14 +178,17 @@ Gamestate *PlayState::update(double delta) {
|
|||
fov->calc(hero->get_position(), 6);
|
||||
}
|
||||
|
||||
auto actors = tilemap->get_actor_list();
|
||||
for (Actor* var : *actors) {
|
||||
auto actors = tilemap->get_entity_list();
|
||||
for (Entity* var : *actors) {
|
||||
if (var == hero) continue;
|
||||
var->update();
|
||||
if (var->entity_type() == ENTITY_ACTOR) {
|
||||
((Actor*)var)->update();
|
||||
}
|
||||
}
|
||||
/* // We got enough memory, we can leave the corpses on the field.
|
||||
unsigned int actor_size = actors->size();
|
||||
for (unsigned int i = actor_size - 1; i <= actor_size; i--) { // Woo unsigned int underflow abuse!
|
||||
if (!actors->at(i)->alive) {
|
||||
if (!actors->at(i)->is_alive()) {
|
||||
if (actors->at(i) == hero) {
|
||||
hero = nullptr;
|
||||
}
|
||||
|
@ -187,6 +196,7 @@ Gamestate *PlayState::update(double delta) {
|
|||
actors->erase(actors->begin() + i);
|
||||
}
|
||||
}
|
||||
*/
|
||||
action = ACTION_NONE;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -223,17 +233,20 @@ void PlayState::draw(double delta) {
|
|||
if (debug_actors) {
|
||||
ImGui::Begin("Actors", &debug_actors);
|
||||
|
||||
auto actors = tilemap->get_actor_list();
|
||||
auto actors = tilemap->get_entity_list();
|
||||
const char* headers[] {
|
||||
"id", "name", "health", "strength"
|
||||
};
|
||||
static float widths[4]{};
|
||||
ImGui::BeginTable("ActorColumns", headers, widths, 4);
|
||||
for (Actor* act : *actors) {
|
||||
ImGui::Text("%d", act->id); ImGui::NextColumn();
|
||||
ImGui::Text(act->name.c_str()); ImGui::NextColumn();
|
||||
ImGui::Text("%d/%d", act->health, act->maxhealth); ImGui::NextColumn();
|
||||
ImGui::Text("%d", act->strength); ImGui::NextColumn();
|
||||
for (Entity* ent : *actors) {
|
||||
if (ent->entity_type() == ENTITY_ACTOR) {
|
||||
auto act = (Actor*) ent;
|
||||
ImGui::Text("%d", act->id); ImGui::NextColumn();
|
||||
ImGui::Text(act->name.c_str()); ImGui::NextColumn();
|
||||
ImGui::Text("%d/%d", act->get_health(), act->get_health_max()); ImGui::NextColumn();
|
||||
ImGui::Text("%d", act->get_strength()); ImGui::NextColumn();
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
||||
|
@ -264,38 +277,22 @@ void PlayState::draw(double delta) {
|
|||
|
||||
tilemap->draw(app->renderer, ascii, margin.x, margin.y, -offset.x, -offset.y, tilesize.x, tilesize.y, fov);
|
||||
|
||||
auto actors = tilemap->get_actor_list();
|
||||
for (Actor* var : *actors) {
|
||||
auto entities = tilemap->get_entity_list();
|
||||
for (Entity* var : *entities) {
|
||||
vec2i pos = var->get_position();
|
||||
if (fov == nullptr || fov->can_see(pos)) {
|
||||
app->renderer->set_color(0, 0, 0, 255);
|
||||
app->renderer->draw_sprite(ascii->get_sprite(219), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
|
||||
|
||||
int sprite;
|
||||
switch (var->Type()) {
|
||||
case ACT_HERO:
|
||||
app->renderer->set_color(.2f, .6f, 1, 1);
|
||||
sprite = '@';
|
||||
break;
|
||||
case ACT_GOBLIN:
|
||||
app->renderer->set_color(.6f, 1, .2f, 1);
|
||||
sprite = 'g';
|
||||
break;
|
||||
case ACT_SHAMAN:
|
||||
app->renderer->set_color(.2f, 1, .6f, 1);
|
||||
sprite = 's';
|
||||
break;
|
||||
default:
|
||||
app->renderer->set_color(1, 1, 1, 1);
|
||||
sprite = 2;
|
||||
break;
|
||||
}
|
||||
int sprite = var->get_sprite_id();
|
||||
app->renderer->set_color(1, 1, 1, 1);
|
||||
|
||||
app->renderer->draw_sprite(ascii->get_sprite(sprite), margin.x + (offset.x + pos.x) * asciisize.x, margin.y + (offset.y + pos.y) * asciisize.y);
|
||||
}
|
||||
}
|
||||
if (hero != nullptr) {
|
||||
app->renderer->set_color(155, 5, 5, 255);
|
||||
for (int i = 0; i < hero->health; i++) {
|
||||
for (int i = 0; i < hero->get_health(); i++) {
|
||||
app->renderer->set_color(0, 0, 0, 255);
|
||||
app->renderer->draw_sprite(ascii->get_sprite(219), (i+1) * asciisize.x, asciisize.y);
|
||||
app->renderer->set_color(255, 0, 0, 255);
|
||||
|
@ -305,7 +302,21 @@ void PlayState::draw(double delta) {
|
|||
}
|
||||
|
||||
void PlayState::quit() {
|
||||
if (tilemap != nullptr) {
|
||||
delete tilemap;
|
||||
tilemap = nullptr;
|
||||
hero = nullptr;
|
||||
}
|
||||
|
||||
if (hero != nullptr) {
|
||||
delete hero;
|
||||
hero = nullptr;
|
||||
}
|
||||
|
||||
if (fov != nullptr) {
|
||||
delete fov;
|
||||
fov = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayState::inputevent(InputEvent *event) {
|
||||
|
|
|
@ -8,43 +8,39 @@
|
|||
RangedAttackNode::RangedAttackNode(BehaviourTreeNode* parent) : BehaviourTreeNode(parent) {}
|
||||
|
||||
|
||||
RangedAttackNode::~RangedAttackNode() {}
|
||||
RangedAttackNode::~RangedAttackNode() = default;
|
||||
|
||||
BehaviourTreeStatus RangedAttackNode::tick(BTTick * tick) {
|
||||
if (children.size() <= 0) {
|
||||
return BT_ERROR;
|
||||
}
|
||||
bool ishero = tick->target->isTypeOf(ACT_HERO);
|
||||
bool ishero = tick->target->is_type_of(ACT_HERO);
|
||||
vec2i targetpos = tick->target->get_position();
|
||||
|
||||
auto actors = tick->target->map->get_actor_list();
|
||||
auto actors = tick->target->get_map()->get_entities(targetpos.x, targetpos.y, 6, ENTITY_ACTOR);
|
||||
std::vector<Actor*> enemies;
|
||||
for (auto actor : *actors) {
|
||||
for (auto ent : actors) {
|
||||
auto actor = (Actor*)ent;
|
||||
if (actor == tick->target) continue;
|
||||
|
||||
if (actor->isTypeOf(ACT_HERO) != ishero) {
|
||||
if (actor->is_type_of(ACT_HERO) != ishero) {
|
||||
vec2i pos = actor->get_position();
|
||||
if (line_of_sight(tick->target->map, tick->target->get_position(), pos)) {
|
||||
if (line_of_sight(tick->target->get_map(), tick->target->get_position(), pos)) {
|
||||
enemies.push_back(actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enemies.size() == 0) {
|
||||
if (enemies.empty()) {
|
||||
return BT_FAILED;
|
||||
}
|
||||
|
||||
Actor* lowestHpActor = nullptr;
|
||||
int lowestHp;
|
||||
for (Actor* actor : enemies) {
|
||||
if (lowestHpActor == nullptr || actor->health < lowestHp) {
|
||||
if (lowestHpActor == nullptr || actor->get_health() < lowestHp) {
|
||||
lowestHpActor = actor;
|
||||
lowestHp = actor->health;
|
||||
lowestHp = actor->get_health();
|
||||
}
|
||||
}
|
||||
|
||||
lowestHpActor->health -= tick->target->strength;
|
||||
if (lowestHpActor->health <= 0) {
|
||||
lowestHpActor->Kill();
|
||||
}
|
||||
tick->target->attack(lowestHpActor);
|
||||
return BT_SUCCEEDED;
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
RestNode::RestNode(BehaviourTreeNode * parent) : BehaviourTreeNode(parent) {}
|
||||
|
||||
RestNode::~RestNode() {}
|
||||
RestNode::~RestNode() = default;
|
||||
|
||||
BehaviourTreeStatus RestNode::tick(BTTick * tick) {
|
||||
if (tick->target->health < tick->target->maxhealth) {
|
||||
if (tick->target->get_health() < tick->target->get_health_max()) {
|
||||
return BT_SUCCEEDED;
|
||||
}
|
||||
return BT_FAILED;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "RestNode.h"
|
||||
#include "IfSeeFriendNode.h"
|
||||
#include "HealFriendNode.h"
|
||||
#include "RangedAttackNode.h"
|
||||
#include "AttackEnemyNode.h"
|
||||
#include "FleeNode.h"
|
||||
|
||||
|
||||
|
@ -15,8 +15,11 @@ Shaman::Shaman(Tilemap* map, vec2i pos) : Actor(map, pos) {
|
|||
name = "Shaman";
|
||||
alive = true;
|
||||
health = 2;
|
||||
maxhealth = 2;
|
||||
health_max = 2;
|
||||
strength = 1;
|
||||
range = 6;
|
||||
sprite_id = 's';
|
||||
team = TEAM_GOBS;
|
||||
|
||||
if (shamtree == nullptr) {
|
||||
auto * root = new BehaviourTreeSelector(nullptr);
|
||||
|
@ -26,7 +29,7 @@ Shaman::Shaman(Tilemap* map, vec2i pos) : Actor(map, pos) {
|
|||
auto * fsel = new BehaviourTreeSelector(seefriend);
|
||||
{
|
||||
new HealFriendNode(fsel);
|
||||
//new RangedAttackNode(fsel);
|
||||
new AttackEnemyNode(fsel);
|
||||
}
|
||||
|
||||
new FleeNode(root);
|
||||
|
|
|
@ -5,7 +5,7 @@ class Shaman :
|
|||
public:
|
||||
Shaman(Tilemap* map, vec2i pos);
|
||||
~Shaman();
|
||||
bool isTypeOf(Actors actor) { return actor == ACT_SHAMAN || Actor::isTypeOf(actor); };
|
||||
Actors Type() { return ACT_SHAMAN; }
|
||||
bool is_type_of(Actors actor) override { return actor == ACT_SHAMAN || Actor::is_type_of(actor); };
|
||||
Actors type() override { return ACT_SHAMAN; }
|
||||
};
|
||||
|
||||
|
|
29
src/Stats.h
Normal file
29
src/Stats.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Created by Adrian on 2017-09-25.
|
||||
//
|
||||
|
||||
#ifndef DUNGEON_STATS_H
|
||||
#define DUNGEON_STATS_H
|
||||
|
||||
struct Stats {
|
||||
int vitality;
|
||||
int endurance;
|
||||
int intelligence;
|
||||
int strength;
|
||||
int dexterity;
|
||||
int perception;
|
||||
};
|
||||
|
||||
struct SecondaryStats { // derived from the primary stats
|
||||
int health;
|
||||
int health_max;
|
||||
int mana;
|
||||
int mana_max;
|
||||
int damage_melee;
|
||||
int damage_magic;
|
||||
int damage_ranged;
|
||||
int defence;
|
||||
int resistance;
|
||||
};
|
||||
|
||||
#endif //DUNGEON_STATS_H
|
|
@ -21,7 +21,7 @@ Tilemap::Tilemap(int width, int height)
|
|||
Tilemap::~Tilemap()
|
||||
{
|
||||
delete tilemap;
|
||||
for (auto var : actors) {
|
||||
for (auto var : entities) {
|
||||
delete var;
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ std::vector<vec2i> Tilemap::getNeighbours(int x, int y, int range)
|
|||
std::vector<vec2i> neigh;
|
||||
if (range == 0)
|
||||
{
|
||||
neigh.push_back({x,y});
|
||||
neigh.emplace_back(x,y);
|
||||
return neigh;
|
||||
}
|
||||
for (int dx = -range; dx <= range; dx++)
|
||||
|
@ -55,14 +55,14 @@ std::vector<vec2i> Tilemap::getNeighbours(int x, int y, int range)
|
|||
{
|
||||
if ((dx != 0 || dy != 0) && IsInsideBounds(x + dx, y + dy))
|
||||
{
|
||||
neigh.push_back({x+dx,y+dy});
|
||||
neigh.emplace_back(x+dx,y+dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return neigh;
|
||||
}
|
||||
|
||||
void Tilemap::set_tile(int x, int y, int tile)
|
||||
void Tilemap::set_tile(int x, int y, unsigned int tile)
|
||||
{
|
||||
if (IsInsideBounds(x, y))
|
||||
{
|
||||
|
@ -86,57 +86,56 @@ bool Tilemap::IsBlocked(int x, int y)
|
|||
if (tilemap[GetIndex(x,y)] == '#') { // TODO: Replace hardcoded tiles
|
||||
return true;
|
||||
}
|
||||
for (Actor* var : actors) {
|
||||
for (Entity* var : entities) {
|
||||
vec2i pos = var->get_position();
|
||||
if (var->IsAlive() && pos.x == x && pos.y == y) {
|
||||
if (var->has_collision() && pos == vec2i(x, y))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tilemap::add_actor(Actor *actor) {
|
||||
for (Actor* var : actors) {
|
||||
void Tilemap::add_entity(Entity *actor) {
|
||||
for (Entity* var : entities) {
|
||||
if (var == actor) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
actors.push_back(actor);
|
||||
entities.push_back(actor);
|
||||
}
|
||||
|
||||
void Tilemap::RemoveActor(Actor * actor) {
|
||||
for (auto it = actors.begin(); it != actors.end(); it++) {
|
||||
void Tilemap::remove_entity(Entity * actor) {
|
||||
for (auto it = entities.begin(); it != entities.end(); it++) {
|
||||
if ((*it) == actor) {
|
||||
actors.erase(it);
|
||||
entities.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Actor * Tilemap::GetActor(int x, int y, Actors type) {
|
||||
Entity * Tilemap::get_entity(int x, int y, EntityTypes type) {
|
||||
vec2i pos = { x,y };
|
||||
for (Actor* act : actors) {
|
||||
if (act->isTypeOf(type)) {
|
||||
vec2i apos = act->get_position();
|
||||
for (Entity* ent : entities) {
|
||||
if (ent->entity_type() == type) {
|
||||
vec2i apos = ent->get_position();
|
||||
if (apos == pos) {
|
||||
return act;
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Actor*> Tilemap::GetActors(int x, int y, int range, Actors type) {
|
||||
std::vector<Actor*> found;
|
||||
std::vector<Entity*> Tilemap::get_entities(int x, int y, int range, EntityTypes type) {
|
||||
std::vector<Entity*> found;
|
||||
std::vector<vec2i> neigh = getNeighbours(x, y, range);
|
||||
for (Actor* act : actors) {
|
||||
for (Entity* ent : entities) {
|
||||
for (vec2i pos : neigh) {
|
||||
if (act->isTypeOf(type)) {
|
||||
vec2i apos = act->get_position();
|
||||
if (ent->entity_type() == type) {
|
||||
vec2i apos = ent->get_position();
|
||||
if (apos == pos) {
|
||||
found.push_back(act);
|
||||
found.emplace_back(ent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -145,8 +144,8 @@ std::vector<Actor*> Tilemap::GetActors(int x, int y, int range, Actors type) {
|
|||
return found;
|
||||
}
|
||||
|
||||
std::vector<Actor*>* Tilemap::get_actor_list() {
|
||||
return &actors;
|
||||
std::vector<Entity*>* Tilemap::get_entity_list() {
|
||||
return &entities;
|
||||
}
|
||||
|
||||
void Tilemap::draw(Renderer *renderer, Tileset* tileset, int x, int y, int tx, int ty, int tw, int th, FieldOfView* view) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "Actor.h"
|
||||
#include "Tileset.h"
|
||||
#include "Entity.h"
|
||||
|
||||
struct vec2i;
|
||||
class Renderer;
|
||||
|
@ -9,7 +9,7 @@ class FieldOfView;
|
|||
|
||||
class Tilemap {
|
||||
unsigned int* tilemap;
|
||||
std::vector<Actor*> actors;
|
||||
std::vector<Entity*> entities;
|
||||
int width;
|
||||
int height;
|
||||
public:
|
||||
|
@ -20,19 +20,19 @@ public:
|
|||
int GetIndex(int x, int y); // Converts [x,y] to a 1D index.
|
||||
bool IsInsideBounds(int x, int y);
|
||||
std::vector<vec2i> getNeighbours(int x, int y, int range = 1);
|
||||
void set_tile(int x, int y, int tile); // "Tile" is inteded for tile ids, but can be anything really.
|
||||
void set_tile(int x, int y, unsigned int tile); // "Tile" is inteded for tile ids, but can be anything really.
|
||||
int GetTile(int x, int y);
|
||||
bool IsBlocked(int x, int y); // Checks if there is an actor blocking the tile.
|
||||
|
||||
void draw(Renderer *renderer, Tileset *tileset, int x, int y, int tx, int ty, int tw, int th, FieldOfView* view);
|
||||
|
||||
void add_actor(Actor *actor);
|
||||
void RemoveActor(Actor* actor);
|
||||
void add_entity(Entity *actor);
|
||||
void remove_entity(Entity *actor);
|
||||
|
||||
void debug_print();
|
||||
|
||||
Actor* GetActor(int x, int y, Actors type);
|
||||
std::vector<Actor*> GetActors(int x, int y, int range, Actors type);
|
||||
std::vector<Actor*>* get_actor_list();
|
||||
Entity* get_entity(int x, int y, EntityTypes type);
|
||||
std::vector<Entity*> get_entities(int x, int y, int range, EntityTypes type);
|
||||
std::vector<Entity*>* get_entity_list();
|
||||
};
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
WanderNode::WanderNode(BehaviourTreeNode* parent) : BehaviourTreeNode(parent){}
|
||||
|
||||
|
||||
WanderNode::~WanderNode() {}
|
||||
WanderNode::~WanderNode() = default;
|
||||
|
||||
BehaviourTreeStatus WanderNode::tick(BTTick * tick) {
|
||||
vec2i pos = tick->target->get_position();
|
||||
std::vector<vec2i> neighbours = tick->target->map->getNeighbours(pos.x, pos.y);
|
||||
std::vector<vec2i> neighbours = tick->target->get_map()->getNeighbours(pos.x, pos.y);
|
||||
while (true) {
|
||||
if (neighbours.size() <= 0) {
|
||||
if (neighbours.empty()) {
|
||||
previous.clear();
|
||||
return BT_FAILED;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ BehaviourTreeStatus WanderNode::tick(BTTick * tick) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (valid && tick->target->Move(dp.x, dp.y)) {
|
||||
if (valid && tick->target->move(dp.x, dp.y)) {
|
||||
previous.push_back(neighbours[i]);
|
||||
if (previous.size() > 5) {
|
||||
previous.erase(previous.begin());
|
||||
|
|
10
src/vec2i.h
10
src/vec2i.h
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
|
||||
struct vec2i {
|
||||
int x, y;
|
||||
|
||||
|
@ -13,6 +15,14 @@ struct vec2i {
|
|||
this->y = y;
|
||||
}
|
||||
|
||||
double dist() {
|
||||
return sqrt(dist_squared());
|
||||
}
|
||||
|
||||
int dist_squared() {
|
||||
return x*x + y*y;
|
||||
}
|
||||
|
||||
bool operator==(vec2i a) {
|
||||
return a.x == x && a.y == y;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue