468 lines
13 KiB
C++
468 lines
13 KiB
C++
#include "precompile.h"
|
|
|
|
#include "creature.h"
|
|
#include "metamgr.h"
|
|
#include "room.h"
|
|
#include "skill.h"
|
|
|
|
bool Creature::HasBuffEffect(int buff_effect_id)
|
|
{
|
|
return GetBuffByEffectId(buff_effect_id) != nullptr;
|
|
}
|
|
|
|
Buff* Creature::GetBuffByEffectId(int effect_id)
|
|
{
|
|
return IsValidBuffEffect(effect_id) ? buff_effect_[effect_id] : nullptr;
|
|
}
|
|
|
|
Buff* Creature::GetBuffById(int buff_id)
|
|
{
|
|
for (Buff& buff : buff_list_) {
|
|
if (buff.meta->i->buff_id() == buff_id) {
|
|
return &buff;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void Creature::AddBuff(Creature* caster,
|
|
MetaData::Buff* buff_meta,
|
|
int skill_lv,
|
|
MetaData::Skill* buff_skill_meta)
|
|
{
|
|
if (GetBuffById(buff_meta->i->buff_id())) {
|
|
return;
|
|
}
|
|
if (IsImmuneBuffEffect(buff_meta->i->buff_effect())) {
|
|
return;
|
|
}
|
|
if (!buff_meta->EffectCanStack()) {
|
|
Buff* buff = GetBuffByEffectId(buff_meta->i->buff_effect());
|
|
if (buff) {
|
|
RemoveBuffById(buff->meta->i->buff_id());
|
|
}
|
|
}
|
|
if (buff_meta->i->buff_effect() == kBET_OnceChgAttr) {
|
|
if ((int)buff_meta->param1== kHAT_Hp) {
|
|
if ((int)buff_meta->param2 == 1) {
|
|
//绝对值
|
|
ability.hp += buff_meta->param3;
|
|
ability.hp = std::min(ability.max_hp, ability.hp);
|
|
} else if ((int)buff_meta->param2 == 2) {
|
|
//百分比
|
|
ability.hp *= 1 + buff_meta->param3;
|
|
ability.hp = std::min(ability.max_hp, ability.hp);
|
|
}
|
|
SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
}
|
|
Buff* buff = &a8::FastAppend(buff_list_);
|
|
buff->skill_lv = skill_lv;
|
|
buff->owner = this;
|
|
buff->meta = buff_meta;
|
|
buff->skill_meta = buff_skill_meta;
|
|
buff->add_frameno = room->GetFrameNo();
|
|
buff->xtimer_attacher.xtimer = &room->xtimer;
|
|
buff_effect_[buff->meta->i->buff_effect()] = buff;
|
|
{
|
|
room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
buff_meta->i->duration_time() * SERVER_FRAME_RATE,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(buff_meta->i->buff_id()),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Creature* c = (Creature*)param.sender.GetUserData();
|
|
c->RemoveBuffById(param.param1);
|
|
},
|
|
&buff->xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
AddBuffPostProc(caster, buff);
|
|
#ifdef DEBUG
|
|
SendDebugMsg(a8::Format("添加buff_id:%d buff_effect:%d",
|
|
{
|
|
buff_meta->i->buff_id(),
|
|
buff_meta->i->buff_effect()
|
|
}));
|
|
#endif
|
|
}
|
|
|
|
bool Creature::IsImmuneBuffEffect(int buff_effect)
|
|
{
|
|
for (auto itr = buff_list_.begin(); itr != buff_list_.end(); ++itr) {
|
|
if (itr->meta->IsImmuneBuffEffect(buff_effect)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Creature::MustBeAddBuff(Creature* caster, int buff_id)
|
|
{
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (!buff_meta) {
|
|
abort();
|
|
}
|
|
AddBuff(caster, buff_meta, 1);
|
|
}
|
|
|
|
void Creature::RemoveBuffById(int buff_id)
|
|
{
|
|
for (auto itr = buff_list_.begin(); itr != buff_list_.end(); ++itr) {
|
|
const Buff& buff = *itr;
|
|
if (buff.meta->i->buff_id() == buff_id) {
|
|
if (buff_effect_[buff.meta->i->buff_effect()] == &(*itr)) {
|
|
buff_effect_[buff.meta->i->buff_effect()] = nullptr;
|
|
}
|
|
OnBuffRemove(buff);
|
|
buff_list_.erase(itr);
|
|
break;
|
|
}
|
|
}
|
|
RecalcBuffAttr();
|
|
#ifdef DEBUG
|
|
SendDebugMsg(a8::Format("移除buff_id:%d",
|
|
{
|
|
buff_id
|
|
}));
|
|
#endif
|
|
}
|
|
|
|
void Creature::SendDebugMsg(const std::string& debug_msg)
|
|
{
|
|
|
|
}
|
|
|
|
void Creature::AddBuffPostProc(Creature* caster, Buff* buff)
|
|
{
|
|
|
|
}
|
|
|
|
void Creature::RecalcBuffAttr()
|
|
{
|
|
buff_attr_abs_ = {};
|
|
buff_attr_rate_ = {};
|
|
for (auto& buff : buff_list_) {
|
|
if (buff.meta->i->buff_effect() == kBET_ChgAttr ||
|
|
buff.meta->i->buff_effect() == kBET_Car) {
|
|
int attr_type = (int)buff.meta->param1;
|
|
int calc_type = (int)buff.meta->param2;
|
|
if (IsValidHumanAttr(attr_type)) {
|
|
if (calc_type == 1) {
|
|
buff_attr_abs_[attr_type] += buff.meta->param3;
|
|
} else if (calc_type == 2) {
|
|
buff_attr_rate_[attr_type] += buff.meta->param3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Creature::OnBuffRemove(const Buff& buff)
|
|
{
|
|
|
|
}
|
|
|
|
void Creature::RemoveBuffByEffectId(int buff_effect_id)
|
|
{
|
|
Buff* buff = GetBuffByEffectId(buff_effect_id);
|
|
if (buff) {
|
|
RemoveBuffById(buff->meta->i->buff_id());
|
|
}
|
|
}
|
|
|
|
void Creature::ClearBuffList()
|
|
{
|
|
for (auto itr = buff_list_.begin(); itr != buff_list_.end(); ++itr) {
|
|
if (buff_effect_[itr->meta->i->buff_effect()] == &(*itr)) {
|
|
buff_effect_[itr->meta->i->buff_effect()] = nullptr;
|
|
}
|
|
OnBuffRemove(*itr);
|
|
}
|
|
buff_list_.clear();
|
|
buff_effect_ = {};
|
|
buff_attr_abs_ = {};
|
|
buff_attr_rate_ = {};
|
|
RecalcBuffAttr();
|
|
}
|
|
|
|
float Creature::GetBuffAttrAbs(int attr_type)
|
|
{
|
|
if (IsValidHumanAttr(attr_type)) {
|
|
return buff_attr_abs_[attr_type];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float Creature::GetBuffAttrRate(int attr_type)
|
|
{
|
|
if (IsValidHumanAttr(attr_type)) {
|
|
return buff_attr_rate_[attr_type];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Creature::FillBuffList(::google::protobuf::RepeatedPtrField<::cs::MFBuff>* pb_buff_list)
|
|
{
|
|
for (auto& itr : buff_list_) {
|
|
auto buff = pb_buff_list->Add();
|
|
itr.FillMFBuff(buff);
|
|
}
|
|
}
|
|
|
|
void Creature::AddPassiveSkill(MetaData::Skill* skill_meta)
|
|
{
|
|
if (!HasPassiveSkill(skill_meta)) {
|
|
xtimer_list* tmp_timer = room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * skill_meta->i->skill_cd(),
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(skill_meta),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Creature* c = (Creature*)param.sender.GetUserData();
|
|
MetaData::Skill* skill_meta = (MetaData::Skill*)param.param1.GetUserData();
|
|
c->ClearPassiveSkillBuff(skill_meta);
|
|
c->AddPassiveSkillBuff(skill_meta);
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
passive_skill_metas_[skill_meta] = tmp_timer;
|
|
AddPassiveSkillBuff(skill_meta);
|
|
if (skill_meta->i->skill_cd() > 10000) {
|
|
//永久被动被动技能
|
|
AddPassiveSkillBuff(skill_meta);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Creature::RemovePassiveSkill(MetaData::Skill* skill_meta)
|
|
{
|
|
auto itr = passive_skill_metas_.find(skill_meta);
|
|
if (itr != passive_skill_metas_.end()) {
|
|
ClearPassiveSkillBuff(skill_meta);
|
|
room->xtimer.DeleteTimer(itr->second);
|
|
passive_skill_metas_.erase(itr);
|
|
}
|
|
}
|
|
|
|
void Creature::ClearPassiveSkill()
|
|
{
|
|
std::vector<MetaData::Skill*> del_skills;
|
|
del_skills.reserve(passive_skill_metas_.size());
|
|
for (auto& pair : passive_skill_metas_) {
|
|
del_skills.push_back(pair.first);
|
|
}
|
|
for (MetaData::Skill* skill_meta : del_skills) {
|
|
RemovePassiveSkill(skill_meta);
|
|
}
|
|
}
|
|
|
|
bool Creature::HasPassiveSkill(MetaData::Skill* skill_meta)
|
|
{
|
|
return passive_skill_metas_.find(skill_meta) != passive_skill_metas_.end();
|
|
}
|
|
|
|
void Creature::ClearPassiveSkillBuff(MetaData::Skill* skill_meta)
|
|
{
|
|
for (int buff_id : skill_meta->buff_list) {
|
|
Buff* buff = GetBuffById(buff_id);
|
|
if (buff &&
|
|
(buff->meta->i->buff_target() == kBuffTargetSelf ||
|
|
buff->meta->i->buff_target() == kBuffTargetFriendly)) {
|
|
RemoveBuffById(buff_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Creature::AddPassiveSkillBuff(MetaData::Skill* skill_meta)
|
|
{
|
|
if (!skill_meta) {
|
|
return;
|
|
}
|
|
MetaData::Skill* old_curr_skill = skill_meta_;
|
|
int old_skill_target_id_ = skill_target_id_;
|
|
a8::Vec2 old_skill_target_pos_ = skill_target_pos_;
|
|
|
|
skill_meta_ = skill_meta;
|
|
skill_target_id_ = GetEntityUniId();
|
|
skill_target_pos_ = GetPos();
|
|
|
|
std::set<Entity*> target_list;
|
|
SelectSkillTargets(GetPos(), target_list);
|
|
TriggerBuff(target_list, kBTT_UseSkill);
|
|
|
|
skill_meta_= old_curr_skill;
|
|
skill_target_id_ = old_skill_target_id_;
|
|
skill_target_pos_ = old_skill_target_pos_;
|
|
}
|
|
|
|
void Creature::SelectSkillTargets(const a8::Vec2& target_pos, std::set<Entity*>& target_list)
|
|
{
|
|
|
|
}
|
|
|
|
void Creature::TriggerBuff(std::set<Entity*>& target_list, BuffTriggerType_e trigger_type)
|
|
{
|
|
for (Entity* entity : target_list) {
|
|
TriggerOneObjectBuff(entity, trigger_type);
|
|
}
|
|
}
|
|
|
|
void Creature::TriggerOneObjectBuff(Entity* target, BuffTriggerType_e trigger_type)
|
|
{
|
|
|
|
}
|
|
|
|
Skill* Creature::GetSkill(int skill_id)
|
|
{
|
|
auto itr = skill_hash_.find(skill_id);
|
|
return itr != skill_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
bool Creature::CanUseSkill(int skill_id)
|
|
{
|
|
Skill* skill = GetSkill(skill_id);
|
|
if (!skill) {
|
|
return false;
|
|
}
|
|
return skill->GetLeftTime() <= 0;
|
|
}
|
|
|
|
void Creature::DoSkill(int skill_id, int target_id, const a8::Vec2& target_pos)
|
|
{
|
|
DoSkillPreProc(skill_id, target_id, target_pos);
|
|
skill_target_id_ = target_id;
|
|
skill_target_pos_ = target_pos;
|
|
if (CanUseSkill(skill_id)) {
|
|
ResetSkill();
|
|
playing_skill = true;
|
|
CurrentSkill()->last_use_frameno = room->GetFrameNo();
|
|
if (skill_meta_->i->skill_target() == kST_Self
|
|
) {
|
|
skill_target_id_ = GetEntityUniId();
|
|
}
|
|
Entity* entity = room->GetEntityByUniId(skill_target_id_);
|
|
if (entity && entity->IsEntityType(ET_Player)) {
|
|
Creature* c = (Creature*)entity;
|
|
std::set<Entity*> target_list;
|
|
skill_target_pos_ = c->GetPos();
|
|
SelectSkillTargets(c->GetPos(), target_list);
|
|
TriggerBuff(target_list, kBTT_UseSkill);
|
|
if (!skill_meta_->phases.empty() && skill_meta_->phases[0].time_offset <= 0) {
|
|
UpdateSkill();
|
|
}
|
|
} else {
|
|
playing_skill = false;
|
|
}
|
|
if (HasBuffEffect(kBET_Camouflage)) {
|
|
RemoveBuffByEffectId(kBET_Camouflage);
|
|
}
|
|
DoSkillPostProc(true, skill_id, target_id, target_pos);
|
|
} else {
|
|
DoSkillPostProc(false, skill_id, target_id, target_pos);
|
|
}
|
|
}
|
|
|
|
void Creature::DoSkillPreProc(int skill_id, int target_id, const a8::Vec2& target_pos)
|
|
{
|
|
}
|
|
|
|
void Creature::DoSkillPostProc(bool used, int skill_id, int target_id, const a8::Vec2& target_pos)
|
|
{
|
|
}
|
|
|
|
void Creature::ResetSkill()
|
|
{
|
|
#if 0
|
|
use_skill = false;
|
|
#endif
|
|
curr_skill_phase = 0;
|
|
skill_dir = a8::Vec2();
|
|
skill_target_pos_ = a8::Vec2();
|
|
skill_param1 = 0.0f;
|
|
playing_skill = false;
|
|
}
|
|
|
|
void Creature::UpdateSkill()
|
|
{
|
|
if (skill_meta_) {
|
|
if (curr_skill_phase < skill_meta_->phases.size()) {
|
|
MetaData::SkillPhase* phase = &skill_meta_->phases[curr_skill_phase];
|
|
if (phase->time_offset >= CurrentSkill()->GetLeftTime()) {
|
|
ProcSkillPhase(phase);
|
|
++curr_skill_phase;
|
|
}
|
|
} else {
|
|
playing_skill = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Creature::ProcSkillPhase(MetaData::SkillPhase* phase)
|
|
{
|
|
switch (phase->func_id) {
|
|
case kSkill_TurnOver:
|
|
{
|
|
}
|
|
break;
|
|
case kSkill_JumpTo:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case kSkill_Shot:
|
|
{
|
|
Entity* entity = room->GetEntityByUniId(skill_target_id_);
|
|
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(phase->param1.GetInt());
|
|
if (weapon_meta && entity) {
|
|
float target_distance = entity->GetPos().Distance(GetPos());
|
|
MetaData::EquipUpgrade* weapon_upgrade_meta =
|
|
MetaMgr::Instance()->GetEquipUpgrade(weapon_meta->i->id());
|
|
MetaData::Equip* bullet_meta =
|
|
MetaMgr::Instance()->GetEquip(weapon_meta->i->use_bullet());
|
|
if (bullet_meta && target_distance > 0.00001f) {
|
|
a8::Vec2 old_attack_dir = attack_dir;
|
|
attack_dir = entity->GetPos() - GetPos();
|
|
attack_dir.Normalize();
|
|
#if 0
|
|
InternalShot
|
|
(
|
|
this,
|
|
weapon_meta,
|
|
weapon_upgrade_meta,
|
|
bullet_meta,
|
|
1,
|
|
skill_meta_->i->skill_id(),
|
|
target_distance,
|
|
false);
|
|
#endif
|
|
attack_dir = old_attack_dir;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case kSkill_Pull:
|
|
{
|
|
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
MetaData::SkillPhase* Creature::GetCurrSkillPhase()
|
|
{
|
|
return curr_skill_phase < skill_meta_->phases.size() ? &skill_meta_->phases[curr_skill_phase] : nullptr;
|
|
}
|
|
|
|
Skill* Creature::CurrentSkill()
|
|
{
|
|
return nullptr;
|
|
}
|