1501 lines
49 KiB
C++
1501 lines
49 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#include "buff.h"
|
|
#include "metamgr.h"
|
|
#include "human.h"
|
|
#include "room.h"
|
|
#include "collider.h"
|
|
#include "skill.h"
|
|
#include "incubator.h"
|
|
#include "car.h"
|
|
#include "frameevent.h"
|
|
#include "skillhelper.h"
|
|
#include "trigger.h"
|
|
#include "virtualbullet.h"
|
|
#include "bullet.h"
|
|
#include "config.h"
|
|
|
|
Buff::Buff()
|
|
{
|
|
|
|
}
|
|
|
|
void Buff::Init()
|
|
{
|
|
INIT_LIST_HEAD(&effect_entry);
|
|
INIT_LIST_HEAD(&depend_entry);
|
|
INIT_LIST_HEAD(&cond_entry);
|
|
INIT_LIST_HEAD(&on_remove_contexts);
|
|
}
|
|
|
|
void Buff::UnInit()
|
|
{
|
|
list_del_init(&effect_entry);
|
|
if (!list_empty(&depend_entry)) {
|
|
list_del_init(&depend_entry);
|
|
}
|
|
if (!list_empty(&cond_entry)) {
|
|
list_del_init(&cond_entry);
|
|
}
|
|
while (!list_empty(&on_remove_contexts)) {
|
|
RemoveBuffCbConext* cb = list_last_entry(&on_remove_contexts,
|
|
RemoveBuffCbConext,
|
|
entry);
|
|
*cb->next = (*cb->next)->next;
|
|
list_del_init(&cb->entry);
|
|
}
|
|
ClearEventHandlers();
|
|
}
|
|
|
|
int Buff::GetLeftTime()
|
|
{
|
|
int passed_ms = (owner->room->GetFrameNo() - add_frameno) * FRAME_RATE_MS;
|
|
return std::max(GetLastingTime() - passed_ms, 0);
|
|
}
|
|
|
|
int Buff::GetLastingTime()
|
|
{
|
|
return meta->pb->duration_time() * 1000;
|
|
}
|
|
|
|
void Buff::FillMFBuff(cs::MFBuff* buff_pb)
|
|
{
|
|
buff_pb->set_buff_id(meta->pb->buff_id());
|
|
buff_pb->set_left_time(GetLeftTime());
|
|
buff_pb->set_lasting_time(GetLastingTime());
|
|
buff_pb->set_buff_uniid(buff_uniid);
|
|
if (owner->IsHuman() &&
|
|
(meta->pb->buff_effect() == kBET_Driver ||
|
|
meta->pb->buff_effect() == kBET_Passenger)) {
|
|
}
|
|
}
|
|
|
|
void Buff::ProcDelayAddBuff()
|
|
{
|
|
InternalTimerAddBuff();
|
|
}
|
|
|
|
void Buff::ProcIntervalAddBuff()
|
|
{
|
|
InternalTimerAddBuff();
|
|
}
|
|
|
|
void Buff::ProcBatchAddBuff()
|
|
{
|
|
std::shared_ptr<Ability> old_context_ability = owner->context_ability;
|
|
a8::Vec2 old_context_dir = owner->context_dir;
|
|
Position old_context_pos = owner->context_pos;
|
|
owner->context_dir = owner->GetAttackDir();
|
|
owner->context_pos = owner->GetPos();
|
|
|
|
for (auto& tuple : meta->batch_add_list) {
|
|
int rand_space = std::get<0>(tuple);
|
|
const auto& items = std::get<1>(tuple);
|
|
if (items.empty()) {
|
|
A8_ABORT();
|
|
}
|
|
int rnd = rand();
|
|
if (rand_space == -1) {
|
|
//概率
|
|
rnd = rnd % 10000;
|
|
if (rnd < std::get<1>(items[0])){
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(std::get<0>(items[0]));
|
|
if (buff_meta) {
|
|
owner->AddBuff(caster_.Get(), buff_meta, nullptr);
|
|
}
|
|
}
|
|
} else {
|
|
//权重
|
|
rnd = rnd % rand_space;
|
|
for (const auto& item : items) {
|
|
if (rnd <= std::get<1>(item)) {
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(std::get<0>(item));
|
|
if (buff_meta) {
|
|
owner->AddBuff(caster_.Get(), buff_meta, nullptr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
owner->context_dir = old_context_dir;
|
|
owner->context_pos = old_context_pos;
|
|
owner->context_ability = old_context_ability;
|
|
}
|
|
|
|
void Buff::InternalTimerAddBuff()
|
|
{
|
|
if (!caster_.Get()) {
|
|
return;
|
|
}
|
|
|
|
std::shared_ptr<SkillCasterState> caster_state = std::make_shared<SkillCasterState>();
|
|
caster_.Get()->FillSkillCasterState(caster_state.get());
|
|
|
|
MetaData::Skill* skill = caster_.Get()->CurrentSkill() ? caster_.Get()->CurrentSkill()->meta : nullptr;
|
|
auto timer_func =
|
|
[this, caster_state, skill] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Creature* receiver = owner;
|
|
if (caster_state->caster.Get()) {
|
|
CreatureWeakPtr caster = caster_state->caster;
|
|
std::shared_ptr<Ability> old_context_ability = receiver->context_ability;
|
|
a8::Vec2 old_context_dir = receiver->context_dir;
|
|
Position old_context_pos = receiver->context_pos;
|
|
receiver->context_dir = receiver->GetAttackDir();
|
|
receiver->context_pos = receiver->GetPos();
|
|
|
|
int buff_id = meta->int_param2;
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
SkillCasterState old_caster_state;
|
|
caster.Get()->FillSkillCasterState(&old_caster_state);
|
|
caster.Get()->RecoverSkillCasterState(caster_state.get());
|
|
//!!!在AddBuff的过程可能删除buff导致caster_state野指针
|
|
receiver->AddBuff(caster.Get(), buff_meta, skill);
|
|
caster.Get()->RecoverSkillCasterState(&old_caster_state);
|
|
}
|
|
|
|
receiver->context_dir = old_context_dir;
|
|
receiver->context_pos = old_context_pos;
|
|
receiver->context_ability = old_context_ability;
|
|
}
|
|
}
|
|
};
|
|
|
|
switch (meta->pb->buff_effect() ) {
|
|
case kBET_DelayAddBuff:
|
|
{
|
|
owner->room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->param1 * SERVER_FRAME_RATE,
|
|
timer_func,
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
break;
|
|
case kBET_IntervalAddBuff:
|
|
{
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
meta->param1 / FRAME_RATE_MS,
|
|
timer_func,
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcSummonHero()
|
|
{
|
|
if (!caster_.Get()->IsHuman()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcBeRecycle()
|
|
{
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE * 2,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (owner->IsHuman()) {
|
|
owner->room->GetIncubator()->RecycleAndroid(owner->AsHuman());
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
|
|
bool Buff::NeedSync(Human* hum)
|
|
{
|
|
return !meta->pb->only_server() || !(meta->pb->only_self() && owner == hum);
|
|
}
|
|
|
|
bool Buff::FreezeOperate()
|
|
{
|
|
return meta->pb->buff_effect() == kBET_Become && !hold_weapons_.empty();
|
|
}
|
|
|
|
void Buff::ProcBecome()
|
|
{
|
|
hold_curr_weapon_idx_ = caster_.Get()->GetCurrWeapon()->weapon_idx;
|
|
if (caster_.Get()->IsHuman() && meta->param2 > 0.01) {
|
|
std::vector<std::string> strings;
|
|
a8::Split(meta->pb->buff_param2(), strings, ':');
|
|
for (size_t i = 0; i < strings.size(); ++i) {
|
|
int weapon_id = a8::XValue(strings[i]);
|
|
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(weapon_id);
|
|
if (weapon_meta && i < caster_.Get()->weapons.size()) {
|
|
int weapon_idx = weapon_meta->GetWeaponIdx();
|
|
if (weapon_idx >= 0 && weapon_idx < caster_.Get()->weapons.size()) {
|
|
Weapon* weapon = &caster_.Get()->weapons[weapon_idx];
|
|
hold_weapons_.push_back(*weapon);
|
|
|
|
weapon->weapon_id = weapon_meta->pb->id();
|
|
weapon->meta = weapon_meta;
|
|
weapon->skill_meta = skill_meta;
|
|
weapon->Recalc();
|
|
weapon->ammo = weapon->GetClipVolume(owner);
|
|
if (i == 0) {
|
|
caster_.Get()->SetCurrWeapon(weapon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
caster_.Get()->MarkSyncActivePlayer(__FILE__, __LINE__, __func__);
|
|
caster_.Get()->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
#ifdef DEBUG1
|
|
caster_.Get()->SendDebugMsg(a8::Format("ProcBecome buff:%d hold_curr_weapon_idx:%d",
|
|
{
|
|
meta->pb->buff_id(),
|
|
hold_curr_weapon_idx_
|
|
}));
|
|
#endif
|
|
}
|
|
|
|
void Buff::ProcRemoveBecome()
|
|
{
|
|
RecoverHoldWeapons();
|
|
}
|
|
|
|
void Buff::ProcDriver()
|
|
{
|
|
hold_curr_weapon_idx_ = caster_.Get()->GetCurrWeapon()->weapon_idx;
|
|
if (caster_.Get()->IsHuman()) {
|
|
Human* hum = (Human*)caster_.Get();
|
|
if (hum->GetCar() && hum->GetCar()->GetCurrWeapon()) {
|
|
hold_weapons_.push_back(hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx]);
|
|
hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx] = *hum->GetCar()->GetCurrWeapon();
|
|
hum->SetCurrWeapon(&hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx]);
|
|
if (hum->GetCar()->meta &&
|
|
hum->GetSeat() < hum->GetCar()->meta->shoot_offsets.size() &&
|
|
std::get<0>(hum->GetCar()->meta->shoot_offsets[hum->GetSeat()])
|
|
) {
|
|
hum->shoot_offset = std::get<1>(hum->GetCar()->meta->shoot_offsets[hum->GetSeat()]);
|
|
}
|
|
}
|
|
}
|
|
caster_.Get()->MarkSyncActivePlayer(__FILE__, __LINE__, __func__);
|
|
caster_.Get()->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcRemoveDriver()
|
|
{
|
|
RecoverHoldWeapons();
|
|
caster_.Get()->shoot_offset = a8::Vec2();
|
|
}
|
|
|
|
void Buff::ProcPassenger()
|
|
{
|
|
hold_curr_weapon_idx_ = caster_.Get()->GetCurrWeapon()->weapon_idx;
|
|
CalcPassengerShotOffset();
|
|
caster_.Get()->MarkSyncActivePlayer(__FILE__, __LINE__, __func__);
|
|
caster_.Get()->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcRemovePassenger()
|
|
{
|
|
RecoverHoldWeapons();
|
|
caster_.Get()->shoot_offset = a8::Vec2();
|
|
}
|
|
|
|
void Buff::RecoverHoldWeapons()
|
|
{
|
|
#ifdef DEBUG1
|
|
caster_.Get()->SendDebugMsg(a8::Format("RecoverHoldWeapons buff:%d hold_curr_weapon_idx:%d",
|
|
{
|
|
meta->pb->buff_id(),
|
|
hold_curr_weapon_idx_
|
|
}));
|
|
#endif
|
|
for (auto& weapon : hold_weapons_) {
|
|
if (weapon.weapon_idx >= 0 &&
|
|
weapon.weapon_idx < caster_.Get()->weapons.size()) {
|
|
caster_.Get()->weapons[weapon.weapon_idx] = weapon;
|
|
}
|
|
}
|
|
if (hold_curr_weapon_idx_ >=0 &&
|
|
hold_curr_weapon_idx_ <= caster_.Get()->weapons.size() &&
|
|
caster_.Get()->weapons[hold_curr_weapon_idx_].weapon_id != 0) {
|
|
Weapon* next_weapon = &caster_.Get()->weapons[hold_curr_weapon_idx_];
|
|
caster_.Get()->SetCurrWeapon(next_weapon);
|
|
} else {
|
|
if (!hold_weapons_.empty()) {
|
|
Weapon* next_weapon = caster_.Get()->AutoChgWeapon();
|
|
if (next_weapon) {
|
|
caster_.Get()->SetCurrWeapon(next_weapon);
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUG1
|
|
for (auto& w : caster_.Get()->weapons) {
|
|
caster_.Get()->SendDebugMsg(a8::Format("weapon_idx:%d weapon_id:%d",
|
|
{
|
|
w.weapon_idx,
|
|
w.weapon_id
|
|
}));
|
|
}
|
|
#endif
|
|
hold_weapons_.clear();
|
|
caster_.Get()->MarkSyncActivePlayer(__FILE__, __LINE__, __func__);
|
|
caster_.Get()->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcSprint()
|
|
{
|
|
if (caster_.Get()->IsPlayer()) {
|
|
if (meta->int_param5) {
|
|
owner->IncDisableMoveDirTimes();
|
|
}
|
|
{
|
|
int old_times = owner->GetDisableMoveDirTimes();
|
|
owner->SetDisableMoveDirTimes(0);
|
|
owner->SetMoveDir(owner->context_dir);
|
|
owner->SetAttackDir(owner->context_dir);
|
|
owner->SetDisableMoveDirTimes(old_times);
|
|
#ifdef DEBUG
|
|
{
|
|
owner->SendDebugMsg(a8::Format("xxxxxxxx move_dir:%d,%d attack_dir:%d,%d speed:%d",
|
|
{
|
|
owner->GetMoveDir().x,
|
|
owner->GetMoveDir().y,
|
|
owner->GetAttackDir().x,
|
|
owner->GetAttackDir().y,
|
|
owner->GetSpeed()
|
|
}));
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
2,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
Human* hum = owner->AsHuman();
|
|
hum->SendDebugMsg(a8::Format("xxxxxxxx move_dir:%d,%d attack_dir:%d,%d speed:%d",
|
|
{
|
|
hum->GetMoveDir().x,
|
|
hum->GetMoveDir().y,
|
|
hum->GetAttackDir().x,
|
|
hum->GetAttackDir().y,
|
|
hum->GetSpeed()
|
|
}));
|
|
}
|
|
},
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
#endif
|
|
}
|
|
Player* hum = (Player*)caster_.Get();
|
|
std::map<int, long long> hited_objects = std::map<int, long long>();
|
|
Position pre_pos;
|
|
pre_pos = owner->GetPos();
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
1,
|
|
[this, hited_objects, pre_pos]
|
|
(int event, const a8::Args* args) mutable
|
|
{
|
|
Buff* buff = this;
|
|
if (!buff->meta->param3_int_list.empty() || buff->skill_meta) {
|
|
std::set<Creature*> enemys;
|
|
Position old_pos = buff->owner->GetPos();
|
|
|
|
if (pre_pos.ManhattanDistance2D(buff->owner->GetPos()) > 2) {
|
|
a8::Vec2 dir = buff->owner->GetPos().CalcDir2D(pre_pos);
|
|
dir.Normalize();
|
|
float distance = buff->owner->GetPos().Distance2D2(pre_pos);
|
|
for (int i = 0; i < (distance + 6); i += 5) {
|
|
// 999
|
|
#if 1
|
|
#else
|
|
buff->owner->MutablePos.FromVec2((pre_pos) + (dir * i));
|
|
#endif
|
|
buff->owner->GetHitEnemys(enemys, buff->meta->param4);
|
|
for (auto& enemy : enemys) {
|
|
if (enemy->IsEntityType(ET_Car)) {
|
|
continue;
|
|
}
|
|
auto itr = hited_objects.find(enemy->GetUniId());
|
|
if (itr != hited_objects.end()) {
|
|
if ((buff->owner->room->GetFrameNo() - itr->second) * FRAME_RATE_MS <
|
|
buff->meta->int_param5) {
|
|
continue;
|
|
}
|
|
}
|
|
hited_objects[enemy->GetUniId()] = buff->owner->room->GetFrameNo();
|
|
for (int buff_id : buff->meta->param3_int_list) {
|
|
enemy->TryAddBuff(buff->owner, buff_id);
|
|
}
|
|
if (buff->skill_meta) {
|
|
switch (buff->skill_meta->GetMagicId()) {
|
|
case MAGIC_YMCZ:
|
|
{
|
|
float dmg = SkillHelper::GetYmczDmg(buff->owner,
|
|
enemy,
|
|
buff->skill_meta);
|
|
if (dmg > 0.0001f) {
|
|
enemy->DecHP(
|
|
dmg,
|
|
buff->owner->GetUniId(),
|
|
buff->owner->GetName(),
|
|
0,
|
|
buff->owner->GetUniId(),
|
|
buff->owner->GetName()
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
buff->owner->SetPos(old_pos);
|
|
pre_pos = buff->owner->GetPos();
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
if (skill_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_YMCZ:
|
|
{
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
SkillHelper::GetYmczBuffTime(skill_meta) / FRAME_RATE_MS);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcSeletTargetWithSelfPos()
|
|
{
|
|
std::vector<Creature*> targets;
|
|
owner->TraverseCreatures
|
|
(
|
|
[this, &targets] (Creature* c, bool& stop)
|
|
{
|
|
if (owner->GetPos().Distance2D2(c->GetPos()) < meta->int_param3) {
|
|
switch (meta->int_param1) {
|
|
case kBST_All:
|
|
{
|
|
targets.push_back(c);
|
|
}
|
|
break;
|
|
case kBST_Self:
|
|
{
|
|
if (c == owner) {
|
|
targets.push_back(c);
|
|
}
|
|
}
|
|
break;
|
|
case kBST_FriendlyIncludeSelf:
|
|
{
|
|
if (c->team_id == owner->team_id) {
|
|
targets.push_back(c);
|
|
}
|
|
}
|
|
break;
|
|
case kBST_FriendlyExcludeSelf:
|
|
{
|
|
if (c->team_id == owner->team_id && c != owner) {
|
|
targets.push_back(c);
|
|
}
|
|
}
|
|
break;
|
|
case kBST_Enemy:
|
|
{
|
|
if (c->team_id != owner->team_id) {
|
|
targets.push_back(c);
|
|
}
|
|
}
|
|
break;
|
|
case kBST_EnemyAndSelf:
|
|
{
|
|
if (c->team_id != owner->team_id || c == owner) {
|
|
targets.push_back(c);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
for (auto& target : targets) {
|
|
for (int buff_id : meta->param2_int_list) {
|
|
target->TryAddBuff(caster_.Get(), buff_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcTurnOver()
|
|
{
|
|
Skill* skill = owner->CurrentSkill();
|
|
if (!skill) {
|
|
return;
|
|
}
|
|
MetaData::SkillPhase* phase = owner->GetCurrSkillPhase();
|
|
if (!phase) {
|
|
return;
|
|
}
|
|
#if 0
|
|
if (phase->time_offset < skill->GetPassedTime()) {
|
|
return;
|
|
}
|
|
#endif
|
|
a8::Vec2 old_dir = owner->GetMoveDir();
|
|
Position old_pos = owner->GetPos();
|
|
float distance =
|
|
owner->HasBuffEffect(kBET_Car) ? phase->param1.GetDouble() * 1.5 : phase->param1.GetDouble();
|
|
#ifdef DEBUG
|
|
caster_.Get()->SendDebugMsg(a8::Format("ProcBecome currTimes:%d last_pos:%d,%d curr_pos:%d,%d",
|
|
{
|
|
skill->GetCurrTimes(),
|
|
owner->last_turn_over_pos.x,
|
|
owner->last_turn_over_pos.y,
|
|
owner->GetPos().x,
|
|
owner->GetPos().y
|
|
}));
|
|
#endif
|
|
#if 0
|
|
if (phase->param2.GetInt() == 1) {
|
|
if (owner->turn_over_times % 2 == 1) {
|
|
distance = old_pos.Distance(owner->last_turn_over_pos);
|
|
if (distance > 0.01f) {
|
|
a8::Vec2 new_dir = owner->last_turn_over_pos - old_pos;
|
|
new_dir.Normalize();
|
|
owner->SetMoveDir(new_dir);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
Global::Instance()->verify_set_pos = 1;
|
|
owner->_UpdateMove(distance);
|
|
Global::Instance()->verify_set_pos = 0;
|
|
owner->SetMoveDir(old_dir);
|
|
if (phase->param2.GetInt() == 1) {
|
|
++owner->turn_over_times;
|
|
owner->last_turn_over_pos = old_pos;
|
|
}
|
|
int moved_distance = (int)owner->GetPos().Distance2D2(old_pos);
|
|
moved_distance = std::min(moved_distance, 200);
|
|
if (!meta->param1_int_list.empty() && moved_distance > 2) {
|
|
std::set<Creature*> target_list;
|
|
owner->TraverseCreatures
|
|
(
|
|
[this, &target_list] (Creature* c, bool& stop)
|
|
{
|
|
if (owner->IsProperTarget(c) && owner->GetPos().Distance2D2(c->GetPos()) < 300) {
|
|
target_list.insert(c);
|
|
}
|
|
});
|
|
|
|
Position curr_pos = owner->GetPos();
|
|
a8::Vec2 dir = old_pos.Distance2D2(owner->GetPos());
|
|
dir.Normalize();
|
|
for (int i = 5; i < moved_distance; i += 5) {
|
|
// 999
|
|
#if 1
|
|
#else
|
|
owner->SetPos(old_pos + dir * i);
|
|
#endif
|
|
std::list<Creature*> hit_objects;
|
|
for (auto& target : target_list) {
|
|
if (owner->TestCollision(owner->room, target)) {
|
|
hit_objects.push_back(target);
|
|
}
|
|
}
|
|
for (auto& target : hit_objects) {
|
|
target_list.erase(target);
|
|
target->room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->int_param4 / FRAME_RATE_MS * (i / moved_distance),
|
|
[this, target] (int event, const a8::Args* args) mutable
|
|
{
|
|
Creature* c = target;
|
|
MetaData::Buff* buff_meta = meta;
|
|
Entity* caster = c->room->GetEntityByUniId(owner->GetUniId());
|
|
if (caster && caster->IsCreature(c->room)) {
|
|
for (int buff_id : buff_meta->param1_int_list) {
|
|
c->TryAddBuff((Creature*)caster, buff_id);
|
|
}
|
|
}
|
|
},
|
|
&target->xtimer_attacher);
|
|
}
|
|
}
|
|
owner->SetPos(curr_pos);
|
|
}
|
|
if (!meta->param2_int_list.empty()) {
|
|
owner->room->xtimer.SetTimeoutEx
|
|
(
|
|
meta->int_param4 / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args) mutable
|
|
{
|
|
Creature* c = owner;
|
|
MetaData::Buff* buff_meta = meta;
|
|
c->TraverseCreatures
|
|
(
|
|
[c, buff_meta] (Creature* target, bool& stop)
|
|
{
|
|
if (c->GetPos().Distance2D2(target->GetPos()) < buff_meta->int_param3) {
|
|
for (int buff_id : buff_meta->param2_int_list) {
|
|
target->TryAddBuffWithTarget(c, buff_id);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
&owner->xtimer_attacher
|
|
);
|
|
}
|
|
}
|
|
|
|
CreatureWeakPtr& Buff::GetCaster()
|
|
{
|
|
return caster_;
|
|
}
|
|
|
|
void Buff::SetCaster(Creature* caster)
|
|
{
|
|
if (caster) {
|
|
caster_.Attach(caster);
|
|
} else {
|
|
caster_.Reset();
|
|
}
|
|
}
|
|
|
|
void Buff::ProcPullToWalkable()
|
|
{
|
|
if (!owner->CollisonDetection()) {
|
|
return;
|
|
}
|
|
a8::Vec2 move_dir = owner->GetMoveDir();
|
|
if (std::abs(move_dir.x) > FLT_EPSILON ||
|
|
std::abs(move_dir.y) > FLT_EPSILON
|
|
) {
|
|
Position old_pos = owner->GetPos();
|
|
for (int i = 1; i < 2000; i += 5) {
|
|
// 999
|
|
#if 1
|
|
#else
|
|
owner->SetPos(old_pos + move_dir * i);
|
|
#endif
|
|
if (!owner->CollisonDetection()) {
|
|
owner->room->grid_service->MoveCreature(owner);
|
|
return;
|
|
}
|
|
}
|
|
owner->FindLocation();
|
|
} else {
|
|
owner->FindLocation();
|
|
}
|
|
}
|
|
|
|
void Buff::ProcAutoShot()
|
|
{
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
1,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (owner->IsHuman()) {
|
|
#if 0
|
|
>owner->AsHuman()->shot_start = true;
|
|
#endif
|
|
owner->AsHuman()->shot_hold = true;
|
|
owner->AsHuman()->series_shot_frames = 0;
|
|
}
|
|
} else if (a8::TIMER_DELETE_EVENT == event) {
|
|
if (owner->IsHuman()) {
|
|
owner->AsHuman()->shot_hold = false;
|
|
owner->AsHuman()->series_shot_frames = 0;
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher);
|
|
}
|
|
|
|
void Buff::ProcBeatBack()
|
|
{
|
|
if (caster_.Get()) {
|
|
if (std::abs(caster_.Get()->context_dir.x) > FLT_EPSILON ||
|
|
std::abs(caster_.Get()->context_dir.x) > FLT_EPSILON) {
|
|
if (std::abs(meta->int_param1) > 0) {
|
|
a8::Vec2 old_move_dir = owner->GetMoveDir();
|
|
owner->SetMoveDir(caster_.Get()->context_dir);
|
|
owner->_UpdateMove(meta->param1);
|
|
owner->SetMoveDir(old_move_dir);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcDisperse()
|
|
{
|
|
std::vector<int> del_buffs;
|
|
owner->TraverseBuff
|
|
(
|
|
[this, &del_buffs] (Buff* buff, bool& stop)
|
|
{
|
|
for (int tag : meta->param1_int_set) {
|
|
if (buff->meta->tags.find(tag) != buff->meta->tags.end()) {
|
|
del_buffs.push_back(buff->buff_uniid);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
for (int buff_uniid : del_buffs) {
|
|
owner->RemoveBuffByUniId(buff_uniid);
|
|
}
|
|
if (!del_buffs.empty()) {
|
|
owner->TryAddBuff(owner, meta->int_param2);
|
|
}
|
|
}
|
|
|
|
void Buff::CalcPassengerShotOffset()
|
|
{
|
|
if (meta->pb->buff_effect() == kBET_Passenger && caster_.Get()->IsHuman()) {
|
|
Human* hum = (Human*)caster_.Get();
|
|
if (hum->GetCar() && hum->GetCar()->GetCurrWeapon()) {
|
|
{
|
|
//换座位时清除之前的状态
|
|
RecoverHoldWeapons();
|
|
}
|
|
hold_weapons_.push_back(hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx]);
|
|
hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx] = *hum->GetCar()->GetCurrWeapon();
|
|
hum->SetCurrWeapon(&hum->weapons[hum->GetCar()->GetCurrWeapon()->weapon_idx]);
|
|
if (hum->GetCar()->meta &&
|
|
hum->GetSeat() < hum->GetCar()->meta->shoot_offsets.size() &&
|
|
std::get<0>(hum->GetCar()->meta->shoot_offsets[hum->GetSeat()])
|
|
) {
|
|
hum->shoot_offset = std::get<1>(hum->GetCar()->meta->shoot_offsets[hum->GetSeat()]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcDive()
|
|
{
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (owner->dead || !owner->IsHuman()) {
|
|
owner->RemoveBuffByUniId(buff_uniid);
|
|
return;
|
|
}
|
|
Human* hum = owner->AsHuman();
|
|
if (hum->GetOxygen() > 0) {
|
|
hum->DecOxygen(Config::Instance()->dive_oxygen_consume);
|
|
hum->room->frame_event.AddPropChg(hum->GetWeakPtrRef(),
|
|
kPropDive,
|
|
Config::Instance()->dive_oxygen_total,
|
|
hum->GetOxygen(),
|
|
true);
|
|
return;
|
|
}
|
|
hum->DecHP(Config::Instance()->dive_hp_consume,
|
|
VP_Water,
|
|
"water",
|
|
0,
|
|
0,
|
|
"water");
|
|
}
|
|
},
|
|
&xtimer_attacher
|
|
);
|
|
if (owner->IsHuman()) {
|
|
++owner->AsHuman()->stats.diving_times;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveDive()
|
|
{
|
|
if (owner->IsHuman()) {
|
|
#if 0
|
|
owner->AsHuman()->SetOxygen(0);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void Buff::ProcInWater()
|
|
{
|
|
if (owner->IsHuman()) {
|
|
owner->AsHuman()->room->frame_event.AddPropChg
|
|
(owner->AsHuman()->GetWeakPtrRef(),
|
|
kPropDive,
|
|
Config::Instance()->dive_oxygen_total,
|
|
owner->AsHuman()->GetOxygen(),
|
|
true);
|
|
|
|
if (owner->IsPlayer()) {
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
if (owner->dead || !owner->IsHuman()) {
|
|
return;
|
|
}
|
|
Human* hum = owner->AsHuman();
|
|
if (!hum->HasBuffEffect(kBET_Dive) &&
|
|
hum->GetOxygen() < Config::Instance()->dive_oxygen_total) {
|
|
hum->AddOxygen(Config::Instance()->inwater_oxygen_recover);
|
|
hum->room->frame_event.AddPropChg
|
|
(hum->GetWeakPtrRef(),
|
|
kPropDive,
|
|
Config::Instance()->dive_oxygen_total,
|
|
hum->GetOxygen(),
|
|
true);
|
|
return;
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveInWater()
|
|
{
|
|
if (owner->IsHuman()) {
|
|
if (owner->IsPlayer()) {
|
|
Human* hum = owner->AsHuman();
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
SERVER_FRAME_RATE,
|
|
[hum] (int event, const a8::Args* args)
|
|
{
|
|
if (hum->HasBuffEffect(kBET_InWater) || hum->dead) {
|
|
hum->room->xtimer.DeleteCurrentTimer();
|
|
return;
|
|
}
|
|
if (hum->GetOxygen() >= Config::Instance()->dive_oxygen_total) {
|
|
hum->room->xtimer.DeleteCurrentTimer();
|
|
return;
|
|
}
|
|
hum->AddOxygen(Config::Instance()->inwater_oxygen_recover);
|
|
},
|
|
&hum->xtimer_attacher
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcReserve()
|
|
{
|
|
if (caster_.Get()) {
|
|
a8::Vec2 dir = caster_.Get()->GetPos().CalcDir2D(owner->GetPos());
|
|
if ((std::isfinite(dir.x) &&
|
|
std::isfinite(dir.y))) {
|
|
dir = dir * 1.0f;
|
|
dir.Normalize();
|
|
owner->SetMoveDir(dir);
|
|
owner->SetAttackDir(dir);
|
|
if (skill_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_YMCZ:
|
|
{
|
|
owner->_UpdateMove(SkillHelper::GetYmczReserveDistance(skill_meta));
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
if (meta->param1 > 0.001) {
|
|
owner->_UpdateMove(meta->param1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcMachineGun()
|
|
{
|
|
hold_curr_weapon_idx_ = caster_.Get()->GetCurrWeapon()->weapon_idx;
|
|
{
|
|
std::vector<std::string> strings;
|
|
a8::Split(meta->pb->buff_param1(), strings, ':');
|
|
for (size_t i = 0; i < strings.size(); ++i) {
|
|
int weapon_id = a8::XValue(strings[i]);
|
|
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(weapon_id);
|
|
if (weapon_meta && i < caster_.Get()->weapons.size()) {
|
|
int weapon_idx = weapon_meta->GetWeaponIdx();
|
|
if (weapon_idx >= 0 && weapon_idx < caster_.Get()->weapons.size()) {
|
|
Weapon* weapon = &caster_.Get()->weapons[weapon_idx];
|
|
hold_weapons_.push_back(*weapon);
|
|
|
|
weapon->weapon_id = weapon_meta->pb->id();
|
|
weapon->meta = weapon_meta;
|
|
weapon->skill_meta = skill_meta;
|
|
weapon->Recalc();
|
|
weapon->ammo = weapon->GetClipVolume(owner);
|
|
if (i == 0) {
|
|
caster_.Get()->SetCurrWeapon(weapon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
caster_.Get()->MarkSyncActivePlayer(__FILE__, __LINE__, __func__);
|
|
caster_.Get()->UpdateCharImage(__FILE__, __LINE__, __func__);
|
|
}
|
|
if (skill_meta && skill_meta->number_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_HLYZ:
|
|
{
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
skill_meta->number_meta->float_time * 1000/ FRAME_RATE_MS);
|
|
}
|
|
break;
|
|
case MAGIC_HJHX:
|
|
{
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS);
|
|
owner->GetTrigger()->DispatchEvent(kStartSwitchWeaponBuffEvent, {this});
|
|
}
|
|
break;
|
|
case MAGIC_FG:
|
|
{
|
|
bool shot_ok = false;
|
|
a8::Vec2 target_dir;
|
|
float fly_distance = 0;
|
|
int trace_target_uniid = 0;
|
|
owner->Shot(owner->context_dir, shot_ok, fly_distance, trace_target_uniid);
|
|
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS);
|
|
event_handlers_.push_back
|
|
(
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kSkillBulletPreCreateEvent,
|
|
[this] (const a8::Args& args)
|
|
{
|
|
int delay_time = args.Get<int>(0);
|
|
MetaData::Skill* bullet_skill_meta = args.Get<MetaData::Skill*>(1);
|
|
int passed_frames = (owner->room->GetFrameNo() - add_frameno);
|
|
int raw_frames = skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS;
|
|
if (skill_meta == bullet_skill_meta &&
|
|
delay_time >= (passed_frames - raw_frames - 2) * FRAME_RATE_MS) {
|
|
int remain_time = owner->room->xtimer.GetRemainTime(remover_timer);
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer, delay_time / FRAME_RATE_MS + 2);
|
|
}
|
|
#ifdef DEBUG
|
|
a8::XPrintf("event1 %d %d %d\n", {passed_frames, raw_frames, delay_time});
|
|
#endif
|
|
}
|
|
)
|
|
);
|
|
event_handlers_.push_back
|
|
(
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kFlyHookCreateEvent,
|
|
[this] (const a8::Args& args)
|
|
{
|
|
Bullet* bullet = args.Get<Bullet*>(0);
|
|
int passed_frames = (owner->room->GetFrameNo() - add_frameno);
|
|
int raw_frames = skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS;
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS);
|
|
#ifdef DEBUG
|
|
a8::XPrintf("event2 %d %d\n", {passed_frames, raw_frames});
|
|
#endif
|
|
})
|
|
);
|
|
event_handlers_.push_back
|
|
(
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kFlyHookDestoryEvent,
|
|
[this] (const a8::Args& args)
|
|
{
|
|
int passed_frames = (owner->room->GetFrameNo() - add_frameno);
|
|
int raw_frames = skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS;
|
|
if (passed_frames >= raw_frames) {
|
|
owner->RemoveBuffByUniId(buff_uniid);
|
|
}
|
|
#ifdef DEBUG
|
|
a8::XPrintf("event3 %d %d\n", {passed_frames, raw_frames});
|
|
#endif
|
|
}
|
|
)
|
|
);
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_msg = a8::Format
|
|
(
|
|
"skill_id:%d 飞钩 距离:%f 钩子持续时间:%f",
|
|
{
|
|
skill_meta->pb->skill_id(),
|
|
skill_meta->number_meta->float_range,
|
|
skill_meta->number_meta->float_time,
|
|
});
|
|
owner->SendDebugMsg(dbg_msg);
|
|
a8::XPrintf("%s\n", {dbg_msg});
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveMachineGun()
|
|
{
|
|
owner->GetTrigger()->DispatchEvent(kEndSwitchWeaponBuffEvent, {this});
|
|
RecoverHoldWeapons();
|
|
}
|
|
|
|
void Buff::ProcReserveMove()
|
|
{
|
|
|
|
}
|
|
|
|
void Buff::ProcHoldShield()
|
|
{
|
|
owner->IncDisableAttackDirTimes();
|
|
owner->shield_max_hp_ = SkillHelper::GetLdfyHp(owner, skill_meta);
|
|
owner->shield_hp_ = owner->shield_max_hp_;
|
|
owner->room->frame_event.AddPropChg(owner->GetWeakPtrRef(),
|
|
kPropShieldHp,
|
|
owner->shield_max_hp_,
|
|
owner->shield_hp_);
|
|
if (skill_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_LDFY:
|
|
{
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
SkillHelper::GetLdfyBuffTime(owner, skill_meta) * 1000 / FRAME_RATE_MS);
|
|
if (owner->CurrentSkill() && owner->CurrentSkill()->meta == skill_meta) {
|
|
Creature* c = owner;
|
|
owner->CurrentSkill()->AddMinorMode
|
|
(
|
|
SMT_BLINK,
|
|
SkillHelper::GetLdfyBuffTime(owner, skill_meta) * 1000,
|
|
[c]
|
|
{
|
|
c->RemoveBuffByEffectId(kBET_HoldShield);
|
|
}
|
|
);
|
|
}
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_msg = a8::Format
|
|
(
|
|
"skill_id:%d 立盾防御 hp:%f ratio:%f ratio:%f human.max_hp:%f time:%f",
|
|
{
|
|
skill_meta->pb->skill_id(),
|
|
owner->shield_max_hp_,
|
|
skill_meta->number_meta->float_ratio,
|
|
skill_meta->number_meta->float_ratio2,
|
|
owner->GetMaxHP(),
|
|
skill_meta->number_meta->float_time,
|
|
});
|
|
owner->SendDebugMsg(dbg_msg);
|
|
a8::XPrintf("%s\n", {dbg_msg});
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveHoldShield()
|
|
{
|
|
owner->DecDisableAttackDirTimes();
|
|
}
|
|
|
|
void Buff::ProcHide()
|
|
{
|
|
if (skill_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_YS:
|
|
{
|
|
owner->room->xtimer.ModifyTime
|
|
(remover_timer,
|
|
skill_meta->number_meta->float_time * 1000 / FRAME_RATE_MS);
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_msg = a8::Format
|
|
(
|
|
"skill_id:%d 兔子隐身 time:%f 警告提示距离:%f 暴击率:%f",
|
|
{
|
|
skill_meta->pb->skill_id(),
|
|
skill_meta->number_meta->float_time,
|
|
skill_meta->number_meta->float_range2,
|
|
skill_meta->number_meta->float_ratio2,
|
|
});
|
|
owner->SendDebugMsg(dbg_msg);
|
|
a8::XPrintf("%s\n", {dbg_msg});
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveHide()
|
|
{
|
|
if (skill_meta) {
|
|
switch (skill_meta->GetMagicId()) {
|
|
case MAGIC_YS:
|
|
{
|
|
owner->GetTrigger()->YsBuffRemove(this);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::ClearEventHandlers()
|
|
{
|
|
for (auto& handler : event_handlers_) {
|
|
if (!handler.expired()) {
|
|
owner->GetTrigger()->RemoveEventHandler(handler);
|
|
}
|
|
}
|
|
event_handlers_.clear();
|
|
}
|
|
|
|
void Buff::ProcRescuer()
|
|
{
|
|
Human* target = owner->room->GetHumanByUniId(owner->AsHuman()->GetActionTargetId());
|
|
if (target) {
|
|
owner->GetTrigger()->StartRescue(target);
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveRescuer()
|
|
{
|
|
Human* target = owner->room->GetHumanByUniId(owner->AsHuman()->GetActionTargetId());
|
|
if (target) {
|
|
owner->GetTrigger()->EndRescue(target);
|
|
}
|
|
}
|
|
|
|
void Buff::ProcImmune()
|
|
{
|
|
for (int tag : meta->param1_int_list) {
|
|
owner->GetAbility()->IncImmuneTimes(tag);
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveImmune()
|
|
{
|
|
for (int tag : meta->param1_int_list) {
|
|
owner->GetAbility()->DecImmuneTimes(tag);
|
|
}
|
|
}
|
|
|
|
void Buff::ProcCallFunc()
|
|
{
|
|
switch (meta->int_param1) {
|
|
case 1:
|
|
{
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
owner->GetAbility()->AddSpeedRuduce(meta->param2);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
ProcIntervalRangeAddBuffFunc();
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveCallFunc()
|
|
{
|
|
switch (meta->int_param1) {
|
|
case 1:
|
|
{
|
|
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
owner->GetAbility()->DelSpeedRuduce(meta->param2);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Buff::PreProcess()
|
|
{
|
|
switch (meta->pb->buff_effect()) {
|
|
case kBET_CallFunc:
|
|
{
|
|
switch (meta->int_param1) {
|
|
case 1:
|
|
{
|
|
event_handlers_.push_back
|
|
(
|
|
owner->GetTrigger()->AddListener
|
|
(
|
|
kTriggerBulletHitBuffEvent,
|
|
[this] (const a8::Args& args)
|
|
{
|
|
Bullet* bullet = args.Get<Bullet*>(0);
|
|
ProcSputteringFunc(bullet);
|
|
}));
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Buff::ProcSputteringFunc(Bullet* bullet)
|
|
{
|
|
MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(meta->int_param2);
|
|
if (!weapon_meta) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < meta->param4_int_list.size(); ++i) {
|
|
a8::Vec2 bullet_dir = a8::Vec2::UP;
|
|
bullet_dir.Rotate(meta->param4_int_list[i] / 180.f);
|
|
// 999
|
|
#if 1
|
|
Position bullet_born_pos;
|
|
#else
|
|
a8::Vec2 bullet_born_pos = owner->GetPos() + bullet_dir * meta->param3;
|
|
#endif
|
|
int bullet_uniid = owner->room->AllocUniid();
|
|
owner->room->frame_event.AddBullet
|
|
(bullet_uniid,
|
|
owner->GetWeakPtrRef(),
|
|
weapon_meta,
|
|
1,
|
|
bullet_born_pos,
|
|
bullet_dir,
|
|
0,
|
|
0,
|
|
0);
|
|
VirtualBullet* p = new VirtualBullet();
|
|
p->bullet_uniid = bullet_uniid;
|
|
p->weapon_uniid = bullet->weapon_uniid;
|
|
p->skill_meta = bullet->skill_meta;
|
|
p->gun_meta = bullet->gun_meta;
|
|
p->bullet_meta = bullet->meta;
|
|
p->sender = bullet->sender;
|
|
p->passenger = bullet->passenger;
|
|
p->room = bullet->room;
|
|
p->is_pre_battle_bullet = bullet->IsPreBattleBullet();
|
|
p->dir = bullet_dir;
|
|
p->born_pos = bullet_born_pos;
|
|
p->born_dir = bullet_dir;
|
|
p->Init();
|
|
owner->room->AddTask(bullet_uniid, p);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void Buff::ProcIntervalRangeAddBuffFunc()
|
|
{
|
|
owner->room->xtimer.SetIntervalEx
|
|
(
|
|
meta->param4 / FRAME_RATE_MS,
|
|
[this] (int event, const a8::Args* args)
|
|
{
|
|
if (a8::TIMER_EXEC_EVENT == event) {
|
|
owner->TraverseCreatures
|
|
(
|
|
[this] (Creature* c, bool& stop)
|
|
{
|
|
if (c->dead) {
|
|
return;
|
|
}
|
|
if (owner->GetUniId() == c->GetUniId()) {
|
|
return;
|
|
}
|
|
if (!GetCaster().Get()) {
|
|
return;
|
|
}
|
|
if (GetCaster().Get()->team_id != c->team_id) {
|
|
if (owner->GetPos().Distance2D2(c->GetPos()) < meta->param2) {
|
|
c->TryAddBuff(GetCaster().Get(), meta->int_param3, skill_meta);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
&xtimer_attacher
|
|
);
|
|
}
|
|
|
|
void Buff::ProcOnceChgAttr()
|
|
{
|
|
InternalProcOnceChgAttr();
|
|
}
|
|
|
|
void Buff::ProcRemoveOnceChgAttr()
|
|
{
|
|
|
|
}
|
|
|
|
void Buff::InternalProcOnceChgAttr()
|
|
{
|
|
if (owner->dead) {
|
|
return;
|
|
}
|
|
switch (meta->int_param1) {
|
|
case kHAT_Hp:
|
|
{
|
|
int real_killer_id = 0;
|
|
std::string real_killer_name;
|
|
if (caster_.Get()) {
|
|
real_killer_id = caster_.Get()->GetUniId();
|
|
real_killer_name = caster_.Get()->GetName();
|
|
}
|
|
if (meta->int_param2 == 1) {
|
|
//绝对值
|
|
if (meta->param3 > 0) {
|
|
owner->AddHp(meta->param3);
|
|
} else if (meta->param3 < 0) {
|
|
owner->over_delay_time = 100;
|
|
owner->DecHP(std::abs(meta->param3),
|
|
VP_Buff,
|
|
"",
|
|
meta->pb->buff_id(),
|
|
real_killer_id,
|
|
real_killer_name);
|
|
owner->over_delay_time = 0;
|
|
}
|
|
} else if (meta->int_param2 == 2) {
|
|
//百分比
|
|
float chg_hp = owner->GetHP() * meta->param3;
|
|
if (chg_hp > 0.0001f) {
|
|
owner->AddHp(chg_hp);
|
|
} else if (chg_hp < 0.0001f) {
|
|
owner->over_delay_time = 100;
|
|
owner->DecHP(std::abs(chg_hp),
|
|
VP_Buff,
|
|
"",
|
|
meta->pb->buff_id(),
|
|
real_killer_id,
|
|
real_killer_name);
|
|
owner->over_delay_time = 0;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
{
|
|
std::string dbg_msg = a8::Format
|
|
("buff扣血 type:%s val:%f",
|
|
{
|
|
meta->int_param2,
|
|
meta->int_param3,
|
|
});
|
|
owner->room->BroadcastDebugMsg(dbg_msg);
|
|
}
|
|
#endif
|
|
owner->room->frame_event.AddHpChg(owner->GetWeakPtrRef());
|
|
}
|
|
break;
|
|
case kHAT_SkillTime:
|
|
{
|
|
#if 0
|
|
if (meta->int_param2 == 1) {
|
|
for (auto& pair : skill_hash_) {
|
|
pair.second->Accelerate(meta->int_param3);
|
|
}
|
|
} else if (meta->int_param2 == 2) {
|
|
for (auto& pair : skill_hash_) {
|
|
int time = pair.second->GetCd() * meta->param3;
|
|
pair.second->Accelerate(time);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|