aozhiwei 853d5cd2bc 1
2024-04-25 14:50:50 +08:00

550 lines
16 KiB
C++

#include "precompile.h"
#include <math.h>
#include "ability.h"
#include "buff.h"
#include "creature.h"
#include "netdata.h"
#include "room.h"
#include "attrhelper.h"
#include "mt/Equip.h"
#include "mt/Buff.h"
struct AttrAddition : public std::enable_shared_from_this<AttrAddition>
{
list_head entry;
list_head list_entry;
int attr_id;
float value;
std::shared_ptr<AttrAddition> holder;
std::shared_ptr<std::function<std::string()>> get_source;
AttrAddition(int attr_id, float value)
{
this->attr_id = attr_id;
this->value = value;
INIT_LIST_HEAD(&entry);
}
bool IsAdd()
{
return a8::GtOrEqZero(value);
}
};
static bool IsMulCalc(int attr_id)
{
switch (attr_id) {
case kHAT_pHealthRateIn:
case kHAT_vHealthRateIn:
case kHAT_pAttackRateIn:
case kHAT_vAttackRateIn:
case kHAT_pDefendRateIn:
case kHAT_pBlockRateIn:
case kHAT_pCritRateIn:
#if 0
case kHAT_vSpeedRateIn:
#endif
case kHAT_vHaste:
case kHAT_vDrain:
case kHAT_vTenacity:
case kHAT_vDamageTakenRateIn:
case kHAT_vDamageDealtRateIn:
case kHAT_vNormalDamageTakenRateIn: //受击方
case kHAT_vNormalDamageDealtRateIn: //攻击方
case kHAT_vSkillDamageTakenRateIn: //受击方
case kHAT_vSkillDamageDealtRateIn: //攻击方
case kHAT_vHealthGainRateIn:
case kHAT_vHealDealtRateIn:
{
return true;
}
break;
default:
{
return false;
}
break;
}
}
Ability::Ability(CreatureWeakPtr owner)
{
for (auto& tuple : attr_add_) {
std::get<0>(tuple) = 0.0f;
INIT_LIST_HEAD(&std::get<1>(tuple));
}
for (auto& tuple : attr_dec_) {
std::get<0>(tuple) = 0.0f;
INIT_LIST_HEAD(&std::get<1>(tuple));
}
for (auto& list : attr_list_) {
INIT_LIST_HEAD(&list);
}
for (auto& tuple : vattr_add_) {
std::get<0>(tuple) = 0.0f;
INIT_LIST_HEAD(&std::get<1>(tuple));
}
for (auto& tuple : vattr_dec_) {
std::get<0>(tuple) = 0.0f;
INIT_LIST_HEAD(&std::get<1>(tuple));
}
for (auto& list : vattr_list_) {
INIT_LIST_HEAD(&list);
}
owner_ = owner;
}
Ability::~Ability()
{
Clear();
}
void Ability::Clear()
{
for (auto& list : attr_list_) {
while (!list_empty(&list)) {
AttrAddition* e = list_first_entry(&list,
AttrAddition,
list_entry);
list_del_init(&e->entry);
list_del_init(&e->list_entry);
e->holder = nullptr;
}
}
for (auto& list : vattr_list_) {
while (!list_empty(&list)) {
AttrAddition* e = list_first_entry(&list,
AttrAddition,
list_entry);
list_del_init(&e->entry);
list_del_init(&e->list_entry);
e->holder = nullptr;
}
}
{
for (auto& tuple : attr_add_) {
std::get<0>(tuple) = 0.0f;
}
for (auto& tuple : attr_dec_) {
std::get<0>(tuple) = 0.0f;
}
for (auto& tuple : vattr_add_) {
std::get<0>(tuple) = 0.0f;
}
for (auto& tuple : vattr_dec_) {
std::get<0>(tuple) = 0.0f;
}
}
switch_times_ = {};
immune_tags_.clear();
}
void Ability::IncImmuneTimes(int tag)
{
auto itr = immune_tags_.find(tag);
if (itr != immune_tags_.end()) {
++itr->second;
} else {
immune_tags_[tag] = 1;
}
}
void Ability::DecImmuneTimes(int tag)
{
auto itr = immune_tags_.find(tag);
if (itr != immune_tags_.end()) {
--itr->second;
if (itr->second <= 0) {
immune_tags_.erase(itr);
}
}
}
bool Ability::CanImmune(int tag)
{
return immune_tags_.find(tag) != immune_tags_.end();
}
bool Ability::CanImmune(const std::set<int>& tags)
{
if (!immune_tags_.empty()) {
for (int tag : tags) {
if (CanImmune(tag)) {
return true;
}
}
}
return false;
}
AttrHandle Ability::AddAttr(int attr_id, float val)
{
float old_max_hp = owner_.Get()->GetMaxHP();
if (IsValidHumanAttr(attr_id) ||
IsValidHumanVirtualAttr(attr_id)) {
auto p = std::make_shared<AttrAddition>(attr_id, val);
p->holder = p;
if (p->IsAdd()) {
if (IsValidHumanAttr(attr_id)) {
list_add_tail(&p->entry, &std::get<1>(attr_add_[attr_id]));
list_add_tail(&p->list_entry, &attr_list_[attr_id]);
} else {
list_add_tail(&p->entry, &std::get<1>(vattr_add_[attr_id - kHVAT_Begin]));
list_add_tail(&p->list_entry, &vattr_list_[attr_id - kHVAT_Begin]);
}
RecalcAttrAddition(attr_id);
} else {
if (IsValidHumanAttr(attr_id)) {
list_add_tail(&p->entry, &std::get<1>(attr_dec_[attr_id]));
list_add_tail(&p->list_entry, &attr_list_[attr_id]);
} else {
list_add_tail(&p->entry, &std::get<1>(vattr_dec_[attr_id - kHVAT_Begin]));
list_add_tail(&p->list_entry, &vattr_list_[attr_id - kHVAT_Begin]);
}
RecalcAttrRuduce(attr_id);
}
if (std::fabs(owner_.Get()->GetMaxHP() - old_max_hp) > 0.000001f) {
owner_.Get()->SetMaxHP(owner_.Get()->GetMaxHP());
owner_.Get()->SetHP(owner_.Get()->GetHP() * (owner_.Get()->GetMaxHP() / old_max_hp));
owner_.Get()->room->frame_event.AddHpChg(owner_);
}
return p;
}
return AttrHandle();
}
void Ability::RemoveAttr(AttrHandle handle)
{
float old_max_hp = owner_.Get()->GetMaxHP();
if (!handle.expired()) {
auto p = handle.lock();
list_del_init(&p->entry);
list_del_init(&p->list_entry);
if (p->IsAdd()) {
RecalcAttrAddition(p->attr_id);
} else {
RecalcAttrRuduce(p->attr_id);
}
p->holder = nullptr;
if (std::fabs(owner_.Get()->GetMaxHP() - old_max_hp) > 0.000001f) {
owner_.Get()->SetMaxHP(owner_.Get()->GetMaxHP());
owner_.Get()->SetHP(owner_.Get()->GetHP() * (owner_.Get()->GetMaxHP() / old_max_hp));
owner_.Get()->room->frame_event.AddHpChg(owner_);
}
}
}
void Ability::RecalcAttrAddition(int attr_id)
{
list_head* head = nullptr;
if (IsValidHumanAttr(attr_id)) {
head = &std::get<1>(attr_add_[attr_id]);
} else if (IsValidHumanVirtualAttr(attr_id)) {
head = &std::get<1>(vattr_add_[attr_id - kHVAT_Begin]);
} else {
return;
}
list_head* pos = nullptr;
list_head* next = nullptr;
float new_val = 0.0f;
bool inited = false;
list_for_each_safe(pos, next, head) {
AttrAddition* e = list_entry(pos,
AttrAddition,
entry);
if (IsMulCalc(attr_id)) {
if (!inited) {
new_val = 1;
inited = true;
}
new_val *= 1 + e->value;
} else {
new_val += e->value;
}
}
if (IsValidHumanAttr(attr_id)) {
std::get<0>(attr_add_[attr_id]) = new_val;
} else if (IsValidHumanVirtualAttr(attr_id)) {
std::get<0>(vattr_add_[attr_id - kHVAT_Begin]) = new_val;
}
owner_.Get()->GetNetData()->RecalcMaxHP();
owner_.Get()->GetNetData()->RecalcAttack();
owner_.Get()->GetNetData()->RecalcDef();
owner_.Get()->GetNetData()->RecalcBlock();
owner_.Get()->GetNetData()->RecalcCrit();
}
void Ability::RecalcAttrRuduce(int attr_id)
{
list_head* head = nullptr;
if (IsValidHumanAttr(attr_id)) {
head = &std::get<1>(attr_dec_[attr_id]);
} else if (IsValidHumanVirtualAttr(attr_id)) {
head = &std::get<1>(vattr_dec_[attr_id - kHVAT_Begin]);
} else {
return;
}
list_head* pos = nullptr;
list_head* next = nullptr;
float new_val = 0.0f;
bool inited = false;
list_for_each_safe(pos, next, head) {
AttrAddition* e = list_entry(pos,
AttrAddition,
entry);
if (IsMulCalc(attr_id)) {
if (!inited) {
new_val = 1;
inited = true;
}
new_val *= 1 + e->value;
} else {
new_val += e->value;
}
}
if (IsValidHumanAttr(attr_id)) {
std::get<0>(attr_dec_[attr_id]) = new_val;
} else if (IsValidHumanVirtualAttr(attr_id)) {
std::get<0>(vattr_dec_[attr_id - kHVAT_Begin]) = new_val;
}
owner_.Get()->GetNetData()->RecalcMaxHP();
owner_.Get()->GetNetData()->RecalcAttack();
owner_.Get()->GetNetData()->RecalcDef();
owner_.Get()->GetNetData()->RecalcBlock();
owner_.Get()->GetNetData()->RecalcCrit();
}
float Ability::GetAttrAddition(int attr_id)
{
if (IsValidHumanAttr(attr_id)) {
return std::get<0>(attr_add_[attr_id]);
} else if (IsValidHumanVirtualAttr(attr_id)) {
return std::get<0>(vattr_add_[attr_id - kHVAT_Begin]);
} else {
return 0.0f;
}
}
float Ability::GetAttrRuduce(int attr_id)
{
if (IsValidHumanAttr(attr_id)) {
return std::get<0>(attr_dec_[attr_id]);
} else if (IsValidHumanVirtualAttr(attr_id)) {
return std::get<0>(vattr_dec_[attr_id - kHVAT_Begin]);
} else {
return 0.0f;
}
}
void Ability::GMDelAttr(int attr_id, int idx)
{
list_head* head = nullptr;
if (IsValidHumanAttr(attr_id)) {
head = &attr_list_[attr_id];
} else if (IsValidHumanVirtualAttr(attr_id)) {
head = &vattr_list_[attr_id];
}
if (head) {
list_head* pos = nullptr;
list_head* next = nullptr;
int i = 0;
list_for_each_safe(pos, next, head) {
AttrAddition* e = list_entry(pos,
AttrAddition,
list_entry);
if (i == idx) {
RemoveAttr(e->shared_from_this());
return;
}
++i;
}
}
}
void Ability::GMClearAttr()
{
Clear();
}
std::vector<std::string> Ability::GMShowAttrs()
{
std::vector<std::string> strings;
strings.push_back(a8::Format("curr_hp:%f max_hp:%f atk:%f def:%f block:%f crit:%f level:%d exp:%f",
{
owner_.Get()->GetHP(),
owner_.Get()->GetNetData()->GetMaxHP(),
owner_.Get()->GetNetData()->GetAttack(),
owner_.Get()->GetNetData()->GetDef(),
owner_.Get()->GetNetData()->GetBlock(),
owner_.Get()->GetNetData()->GetCrit(),
owner_.Get()->GetHeroLevel(),
owner_.Get()->GetHeroExp()
}));
{
std::vector<std::string> tmp_strings;
int attr_id = 0;
for (auto& list : attr_list_) {
list_head* head = &list;
list_head* pos = nullptr;
list_head* next = nullptr;
std::string data = a8::Format("attr_id:%d attr_name:%s value:%f [",
{attr_id,
AttrHelper::GetAttrName(attr_id),
GetAttr(attr_id)});
int i = 0;
list_for_each_safe(pos, next, head) {
AttrAddition* e = list_entry(pos,
AttrAddition,
list_entry);
if (e->get_source) {
data += "" + a8::XValue(e->value).GetString() + (*e->get_source)() + ",";
} else {
data += "" + a8::XValue(e->value).GetString() + "<-none,";
}
++i;
}
if (i > 0) {
data += "]";
tmp_strings.push_back(data);
}
++attr_id;
}
strings.push_back("属性:");
if (tmp_strings.empty()) {
strings.push_back("");
} else {
for (auto& str : tmp_strings) {
strings.push_back(str);
}
}
}
{
std::vector<std::string> tmp_strings;
int attr_id = 0;
for (auto& list : vattr_list_) {
list_head* head = &list;
list_head* pos = nullptr;
list_head* next = nullptr;
std::string data = a8::Format("attr_id:%d attr_name:%s value:%f [",
{attr_id,
AttrHelper::GetAttrName(attr_id),
GetAttr(attr_id)
});
int i = 0;
list_for_each_safe(pos, next, head) {
AttrAddition* e = list_entry(pos,
AttrAddition,
list_entry);
data += "" + a8::XValue(e->value).GetString() + ",";
++i;
}
if (i > 0) {
data += "]";
tmp_strings.push_back(data);
}
++attr_id;
}
strings.push_back("虚属性:");
if (tmp_strings.empty()) {
strings.push_back("");
} else {
for (auto& str : tmp_strings) {
strings.push_back(str);
}
}
}
return strings;
}
void Ability::IncSwitch(int type)
{
if (type >= kSwitchTimeBegin && type < kSwitchTimeEnd) {
++switch_times_[type];
} else {
abort();
}
}
void Ability::DecSwitch(int type)
{
if (type >= kSwitchTimeBegin && type < kSwitchTimeEnd) {
--switch_times_[type];
} else {
abort();
}
}
int Ability::GetSwitchTimes(int type)
{
if (type >= kSwitchTimeBegin && type < kSwitchTimeEnd) {
return switch_times_[type];
} else {
abort();
}
return 0;
}
float Ability::GetAttr(int attr_id)
{
float val = 0.0f;
if (!HasAttr(attr_id)) {
return 0.0f;
}
if (IsMulCalc(attr_id)) {
if (IsValidHumanAttr(attr_id)) {
val = (HasAddAttr(attr_id) ? std::get<0>(attr_add_[attr_id]) : 1) *
(HasDecAttr(attr_id) ? std::get<0>(attr_dec_[attr_id]) : 1);
} else if (IsValidHumanVirtualAttr(attr_id)) {
val = (HasAddAttr(attr_id) ? std::get<0>(vattr_add_[attr_id - kHVAT_Begin]) : 1) *
(HasDecAttr(attr_id) ? std::get<0>(vattr_dec_[attr_id - kHVAT_Begin]) : 1);
}
val = val - 1.0f;
} else {
if (IsValidHumanAttr(attr_id)) {
val = std::get<0>(attr_add_[attr_id]) +
std::get<0>(attr_dec_[attr_id]);
} else if (IsValidHumanVirtualAttr(attr_id)) {
val = std::get<0>(vattr_add_[attr_id - kHVAT_Begin]) +
std::get<0>(vattr_dec_[attr_id - kHVAT_Begin]);
}
}
return val;
}
bool Ability::HasAttr(int attr_id)
{
return HasAddAttr(attr_id) || HasDecAttr(attr_id);
}
bool Ability::HasAddAttr(int attr_id)
{
if (IsValidHumanAttr(attr_id)) {
return !list_empty(&std::get<1>(attr_add_[attr_id]));
} if (IsValidHumanVirtualAttr(attr_id)) {
return !list_empty(&std::get<1>(vattr_add_[attr_id - kHVAT_Begin]));
}
return false;
}
bool Ability::HasDecAttr(int attr_id)
{
if (IsValidHumanAttr(attr_id)) {
return !list_empty(&std::get<1>(attr_dec_[attr_id]));
} if (IsValidHumanVirtualAttr(attr_id)) {
return !list_empty(&std::get<1>(vattr_dec_[attr_id - kHVAT_Begin]));
}
return false;
}
void Ability::SetSource(AttrHandle handle, std::shared_ptr<std::function<std::string()>> cb)
{
auto p = handle.lock();
p->get_source = cb;
}