328 lines
11 KiB
C++
328 lines
11 KiB
C++
#include "precompile.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"
|
|
|
|
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->i->duration_time() * 1000;
|
|
}
|
|
|
|
void Buff::FillMFBuff(cs::MFBuff* buff_pb)
|
|
{
|
|
buff_pb->set_buff_id(meta->i->buff_id());
|
|
buff_pb->set_left_time(GetLeftTime());
|
|
buff_pb->set_lasting_time(GetLastingTime());
|
|
}
|
|
|
|
void Buff::ProcDelayAddBuff(Creature* caster)
|
|
{
|
|
InternalTimerAddBuff(caster);
|
|
}
|
|
|
|
void Buff::ProcIntervalAddBuff(Creature* caster)
|
|
{
|
|
InternalTimerAddBuff(caster);
|
|
}
|
|
|
|
void Buff::ProcBatchAddBuff(Creature* caster)
|
|
{
|
|
for (auto& tuple : meta->batch_add_list) {
|
|
int rand_space = std::get<0>(tuple);
|
|
const auto& items = std::get<1>(tuple);
|
|
if (items.empty()) {
|
|
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, buff_meta, 1, 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, buff_meta, 1, nullptr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Buff::InternalTimerAddBuff(Creature* caster)
|
|
{
|
|
if (!caster) {
|
|
return;
|
|
}
|
|
auto timer_func =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Creature* receiver = (Creature*)param.sender.GetUserData();
|
|
SkillCasterState* caster_state = (SkillCasterState*)param.param1.GetUserData();
|
|
if (caster_state->caster.Get()) {
|
|
int buff_id = param.param2;
|
|
MetaData::Skill* skill = (MetaData::Skill*)param.param3.GetUserData();
|
|
MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff(buff_id);
|
|
if (buff_meta) {
|
|
SkillCasterState old_caster_state;
|
|
caster_state->caster.Get()->FillSkillCasterState(&old_caster_state);
|
|
caster_state->caster.Get()->RecoverSkillCasterState(caster_state);
|
|
receiver->AddBuff(caster_state->caster.Get(), buff_meta, 1, skill);
|
|
caster_state->caster.Get()->RecoverSkillCasterState(&old_caster_state);
|
|
}
|
|
}
|
|
};
|
|
auto timer_after_func =
|
|
[] (const a8::XParams& param)
|
|
{
|
|
SkillCasterState* caster_state = (SkillCasterState*)param.param1.GetUserData();
|
|
delete caster_state;
|
|
};
|
|
|
|
SkillCasterState* caster_state = new SkillCasterState;
|
|
caster->FillSkillCasterState(caster_state);
|
|
|
|
a8::XParams param;
|
|
param.SetSender(owner);
|
|
param.SetParam1(caster_state);
|
|
param.SetParam2(meta->i->buff_param2());
|
|
param.SetParam3(caster->CurrentSkill() ? caster->CurrentSkill()->meta : nullptr);
|
|
|
|
switch (meta->i->buff_effect() ) {
|
|
case kBET_DelayAddBuff:
|
|
{
|
|
owner->room->xtimer.AddDeadLineTimerAndAttach
|
|
(
|
|
meta->param1 * SERVER_FRAME_RATE,
|
|
param,
|
|
timer_func,
|
|
&xtimer_attacher.timer_list_,
|
|
timer_after_func);
|
|
}
|
|
break;
|
|
case kBET_IntervalAddBuff:
|
|
{
|
|
owner->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
meta->param1 / FRAME_RATE_MS,
|
|
param,
|
|
timer_func,
|
|
&xtimer_attacher.timer_list_,
|
|
timer_after_func);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcSummonHero(Creature* caster)
|
|
{
|
|
if (!caster->IsHuman()) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Buff::ProcBeRecycle(Creature* caster)
|
|
{
|
|
owner->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
SERVER_FRAME_RATE * 2,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Buff* buff = (Buff*)param.sender.GetUserData();
|
|
if (buff->owner->IsHuman()) {
|
|
buff->owner->room->GetIncubator()->RecycleAndroid((Human*)buff->owner);
|
|
}
|
|
},
|
|
&xtimer_attacher.timer_list_
|
|
);
|
|
}
|
|
|
|
bool Buff::NeedSync(Human* hum)
|
|
{
|
|
return !meta->i->only_server() || !(meta->i->only_self() && owner == hum);
|
|
}
|
|
|
|
bool Buff::FreezeOperate()
|
|
{
|
|
return meta->i->buff_effect() == kBET_Become && !hold_weapons_.empty();
|
|
}
|
|
|
|
void Buff::ProcBecome(Creature* caster)
|
|
{
|
|
hold_curr_weapon_idx_ = caster->GetCurrWeapon()->weapon_idx;
|
|
if (caster->IsHuman() && meta->param2 > 0.01) {
|
|
std::vector<std::string> strings;
|
|
a8::Split(meta->i->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->weapons.size()) {
|
|
int weapon_idx = weapon_meta->GetWeaponIdx();
|
|
if (weapon_idx >= 0 && weapon_idx < caster->weapons.size()) {
|
|
Weapon* weapon = &caster->weapons[weapon_idx];
|
|
hold_weapons_.push_back(*weapon);
|
|
|
|
weapon->weapon_id = weapon_meta->i->id();
|
|
weapon->weapon_lv = 1;
|
|
weapon->meta = weapon_meta;
|
|
weapon->Recalc();
|
|
weapon->ammo = weapon->GetClipVolume();
|
|
if (i == 0) {
|
|
caster->SetCurrWeapon(weapon);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
caster->need_sync_active_player = true;
|
|
caster->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
}
|
|
|
|
void Buff::ProcRemoveBecome(Creature* caster)
|
|
{
|
|
RecoverHoldWeapons(caster);
|
|
}
|
|
|
|
void Buff::ProcDriver(Creature* caster)
|
|
{
|
|
hold_curr_weapon_idx_ = caster->GetCurrWeapon()->weapon_idx;
|
|
if (caster->IsHuman()) {
|
|
Human* hum = (Human*)caster;
|
|
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->need_sync_active_player = true;
|
|
caster->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcRemoveDriver(Creature* caster)
|
|
{
|
|
RecoverHoldWeapons(caster);
|
|
caster->shoot_offset = a8::Vec2();
|
|
}
|
|
|
|
void Buff::ProcPassenger(Creature* caster)
|
|
{
|
|
hold_curr_weapon_idx_ = caster->GetCurrWeapon()->weapon_idx;
|
|
if (caster->IsHuman()) {
|
|
Human* hum = (Human*)caster;
|
|
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->need_sync_active_player = true;
|
|
caster->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcRemovePassenger(Creature* caster)
|
|
{
|
|
RecoverHoldWeapons(caster);
|
|
caster->shoot_offset = a8::Vec2();
|
|
}
|
|
|
|
void Buff::RecoverHoldWeapons(Creature* caster)
|
|
{
|
|
for (auto& weapon : hold_weapons_) {
|
|
if (weapon.weapon_idx >= 0 &&
|
|
weapon.weapon_idx < caster->weapons.size()) {
|
|
caster->weapons[weapon.weapon_idx] = weapon;
|
|
}
|
|
}
|
|
if (hold_curr_weapon_idx_ >=0 &&
|
|
hold_curr_weapon_idx_ <= caster->weapons.size() &&
|
|
caster->weapons[hold_curr_weapon_idx_].weapon_id != 0) {
|
|
Weapon* next_weapon = &caster->weapons[hold_curr_weapon_idx_];
|
|
caster->SetCurrWeapon(next_weapon);
|
|
} else {
|
|
if (!hold_weapons_.empty()) {
|
|
Weapon* next_weapon = caster->AutoChgWeapon();
|
|
if (next_weapon) {
|
|
caster->SetCurrWeapon(next_weapon);
|
|
}
|
|
}
|
|
}
|
|
hold_weapons_.clear();
|
|
caster->need_sync_active_player = true;
|
|
caster->SyncAroundPlayers(__FILE__, __LINE__, __func__);
|
|
}
|
|
|
|
void Buff::ProcSprint(Creature* caster)
|
|
{
|
|
if (caster->IsPlayer()) {
|
|
Player* hum = (Player*)caster;
|
|
std::set<int>* hited_objects = new std::set<int>;
|
|
owner->room->xtimer.AddRepeatTimerAndAttach
|
|
(
|
|
1,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(hited_objects),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Buff* buff = (Buff*)param.sender.GetUserData();
|
|
std::set<int>* hited_objects = (std::set<int>*)param.param1.GetUserData();
|
|
std::set<Creature*> enemys;
|
|
buff->owner->GetHitEnemys(enemys);
|
|
for (auto& enemy : enemys) {
|
|
if (hited_objects->find(enemy->GetEntityUniId()) != hited_objects->end()) {
|
|
hited_objects->insert(enemy->GetEntityUniId());
|
|
for (int buff_id : buff->meta->param1_int_list) {
|
|
enemy->TryAddBuff(buff->owner, buff_id);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
&xtimer_attacher.timer_list_,
|
|
[] (const a8::XParams& param)
|
|
{
|
|
std::set<int>* hited_objects = (std::set<int>*)param.param1.GetUserData();
|
|
delete hited_objects;
|
|
});
|
|
}
|
|
}
|