You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.3 KiB
C++

#include "NPC.hpp"
#include "RLGame.hpp"
#include "utils.hpp"
#include "ItemList.hpp"
#ifdef _DEBUG
#include <iostream>
#endif
NPC::NPC()
: NPC{ "", SPECIES::UNDEFINED, Position{} }
{
}
NPC::NPC(const std::string& name, SPECIES species, Position position)
: Entity{ name, species, position }
{
// give random items
unsigned int randomItem{ uint32_t(utils::RandomBetween(0, G_ITEM_LIST->GetAmountOfWeapons() + 5)) };
if(randomItem < G_ITEM_LIST->GetAmountOfWeapons())
{
m_pWeapon = nullptr;
#ifdef _DEBUG
//std::cout << name << " (" << GetSpeciesString() << ") got weapon " << m_pWeapon->itemName << '\n';
#endif
}
randomItem = uint32_t(utils::RandomBetween(0, G_ITEM_LIST->GetAmountOfArmors() + 7));
if(randomItem < G_ITEM_LIST->GetAmountOfArmors())
{
m_pArmor = nullptr;
#ifdef _DEBUG
//std::cout << name << " (" << GetSpeciesString() << ") got armor " << m_pArmor->itemName << '\n';
#endif
}
}
void NPC::Update(const std::vector<Entity*>& entities)
{
/*if(m_Species == SPECIES::HUMAN)
{
if(GetDistanceFrom(*m_pPlayer) > 1)
MoveTo(*m_pPlayer);
else
Fight(*m_pPlayer);
}
else if(m_HugCounter > 0)
{
if(GetDistanceFrom(*m_pPlayer) > 1)
MoveTo(*m_pPlayer);
else if(utils::RandomBetween(0, 100) < 5)
Hug(*m_pPlayer);
}*/
/*
auto closeNPCs{ GetClosestWithState(entities, (m_Faction == ENTITY_FACTION::FRIENDLY || m_Faction == ENTITY_FACTION::DEVOTED) ? ENTITY_FACTION::EVIL : ENTITY_FACTION::FRIENDLY) };
if(m_Faction == ENTITY_FACTION::EVIL)
{
auto otherCloseNPCs{ GetClosestWithState(entities, ENTITY_FACTION::DEVOTED) };
for(auto& npc : otherCloseNPCs)
closeNPCs.push_back(npc);
}
*/
switch(m_Faction)
{
case ENTITY_FACTION::NEUTRAL:
{
if(m_Health < m_MaxHealth / 2)
CheckInventory(ITEM_TYPE::CONSUMABLE);
else if(utils::RandomBetweenSimple(0, 10) < 2)
Move(DIRECTION(utils::RandomBetweenSimple(0, 7)));
break;
}
case ENTITY_FACTION::FRIENDLY:
case ENTITY_FACTION::DEVOTED:
{
std::vector<Entity*> closeNPCs{ GetClosestWithState(entities, ENTITY_FACTION::EVIL) };
if(m_Health < m_MaxHealth / 2)
CheckInventory(ITEM_TYPE::CONSUMABLE);
else if(closeNPCs.size() > 0)
Fight(*closeNPCs[utils::RandomBetween(0, closeNPCs.size() - 1)]);
else if(GetDistanceFrom(*m_pPlayer) > 1)
MoveTo(*m_pPlayer);
else if(utils::RandomBetween(0, 10) < 1)
Hug(*m_pPlayer);
break;
}
case ENTITY_FACTION::EVIL:
{
std::vector<Entity*> closeNPCs{ GetClosestWithState(entities, ENTITY_FACTION::FRIENDLY) };
std::vector<Entity*> otherCloseNPCs{ GetClosestWithState(entities, ENTITY_FACTION::DEVOTED) };
for(auto& npc : otherCloseNPCs) // put them all in one vector
closeNPCs.push_back(npc);
if(m_Health < m_MaxHealth / 2)
CheckInventory(ITEM_TYPE::CONSUMABLE);
else if(closeNPCs.size() > 0 && utils::RandomBetweenSimple(0, 1)) // fight close npcs or player but closeNPCs also contains the player EDIT 2020-08-01: player isn't actually included, was wrong
Fight(*closeNPCs[utils::RandomBetween(0, closeNPCs.size() - 1)]);
else if(GetDistanceFrom(*m_pPlayer) > 1)
MoveTo(*m_pPlayer);
else
Fight(*m_pPlayer);
break;
}
}
}
void NPC::CheckInventory(ITEM_TYPE itemType)
{
for(size_t id{}; id < m_Inventory.size(); ++id)
{
if(m_Inventory[id]->itemType == itemType)
{
UseItem(id);
break;
}
}
}