#include "precompile.h" #include #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 { list_head entry; list_head list_entry; int attr_id; float value; std::shared_ptr holder; std::shared_ptr> 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 kNHAT_pHealthRateIn: case kNHAT_vHealthRateIn: case kNHAT_pAttackRateIn: case kNHAT_vAttackRateIn: case kNHAT_pDefendRateIn: case kNHAT_pBlockRateIn: case kNHAT_pCritRateIn: case kNHAT_vSpeedRateIn: case kNHAT_vHaste: case kNHAT_vDrain: case kNHAT_vTenacity: case kNHAT_vDamageTakenRateIn: case kNHAT_vDamageDealtRateIn: case kNHAT_vNormalDamageTakenRateIn: //受击方 case kNHAT_vNormalDamageDealtRateIn: //攻击方 case kNHAT_vSkillDamageTakenRateIn: //受击方 case kNHAT_vSkillDamageDealtRateIn: //攻击方 case kNHAT_vHealthGainRateIn: case kNHAT_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& 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(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 Ability::GMShowAttrs() { std::vector strings; strings.push_back(a8::Format("curr_hp:%f max_hp:%f atk:%f def:%f block:%f crit:%f", { owner_.Get()->GetHP(), owner_.Get()->GetNetData()->GetMaxHP(), owner_.Get()->GetNetData()->GetAttack(), owner_.Get()->GetNetData()->GetDef(), owner_.Get()->GetNetData()->GetBlock(), owner_.Get()->GetNetData()->GetCrit(), })); { std::vector 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 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> cb) { }