diff --git a/server/gameserver/creature.cc b/server/gameserver/creature.cc index ef75712c..d9142d30 100644 --- a/server/gameserver/creature.cc +++ b/server/gameserver/creature.cc @@ -2186,52 +2186,38 @@ void Creature::SummonHero(Buff* buff, MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(hero_id); if (hero_meta) { for (int j = 0; j < num; ++j) { + bool can_create = false; + a8::Vec2 born_pos; Hero* hero = nullptr; for (int i = 0; i < 4; ++i) { a8::Vec2 born_dir = dir; a8::Vec2 born_offset(x, y); born_offset.Rotate(born_dir.CalcAngle(a8::Vec2::UP)); born_offset.Rotate(i * 0.5); - a8::Vec2 hero_pos = pos + born_offset; - hero = InternalSummonHero(hero_meta, - dir, - hero_pos, - through_wall); - if (hero) { + born_pos = pos + born_offset; + can_create = TrySummonHero(hero_meta, + dir, + born_pos, + through_wall); + if (can_create) { break; } }//end for i - if (!hero) { - hero = InternalSummonHero(hero_meta, - GetAttackDir(), - GetPos(), - through_wall); -#ifdef DEBUG - SendDebugMsg(a8::Format("second summon hero id:%d pos:%f,%f rad:%d ok:%d", - { - hero_meta->i->id(), - GetPos().x, - GetPos().y, - hero_meta->i->radius(), - hero ? 1 : 0 - })); -#endif + if (!can_create) { + born_pos = GetPos(); + can_create = TrySummonHero(hero_meta, + GetAttackDir(), + born_pos, + through_wall); } - if (hero) { - RemoveSurplusHero(buff->meta->i->buff_id(), hero_id, num); - slave_heros_.push_back(std::make_tuple(buff->meta->i->buff_id(), hero)); - hero->room->xtimer.AddDeadLineTimerAndAttach - ( - life_time / FRAME_RATE_MS, - a8::XParams(), - [] (const a8::XParams& param) - { - }, - &hero->xtimer_attacher.timer_list_, - [] (const a8::XParams& param) - { - - }); + if (can_create) { + InternalSummonHero(buff, + hero_meta, + GetAttackDir(), + born_pos, + through_wall, + num, + life_time); } }//end for j } @@ -2680,42 +2666,99 @@ void Creature::TraverseBuff(std::function func) } } -Hero* Creature::InternalSummonHero(MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, bool through_wall) +bool Creature::TrySummonHero(MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, bool through_wall) { - #if 1 AabbCollider collider; collider._min.x = -hero_meta->i->radius(); collider._min.y = -hero_meta->i->radius(); collider._max.x = hero_meta->i->radius(); collider._max.y = hero_meta->i->radius(); collider.MoveCenter(hero_meta->i->move_offset_x(), hero_meta->i->move_offset_y()); - #else - CircleCollider collider; - collider.rad = hero_meta->i->radius(); - #endif - if (!room->map_service->CollisionDetection + return !room->map_service->CollisionDetection ( room, through_wall, born_pos, &collider - )) { - Hero* hero = room->CreateHero - (this, - hero_meta, - born_pos, - dir, - team_id - ); - #ifdef DEBUG - SendDebugMsg(a8::Format("summon hero id:%d pos:%f,%f", - { - hero_meta->i->id(), - born_pos.x, - born_pos.y - })); - #endif - return hero; + ); +} + +Hero* Creature::InternalSummonHero(Buff* buff, MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, + bool through_wall, int num, int life_time) +{ + struct SummonHeroInfo + { + MetaData::Player* hero_meta = nullptr; + a8::Vec2 dir; + a8::Vec2 born_pos; + bool through_wall = false; + int num = 0; + int life_time = 0; + }; + if (TrySummonHero(hero_meta, dir, born_pos, through_wall)) { + int delay_time = 0; + for (auto& tuple : hero_meta->pre_appear_effect) { + delay_time += std::get<1>(tuple); + } + SummonHeroInfo* summon_info = new SummonHeroInfo; + summon_info->hero_meta = hero_meta; + summon_info->dir = dir; + summon_info->born_pos = born_pos; + summon_info->through_wall = through_wall; + summon_info->num = num; + summon_info->life_time = life_time; + room->xtimer.AddDeadLineTimerAndAttach + ( + delay_time / FRAME_RATE_MS, + a8::XParams() + .SetSender(buff) + .SetParam1(summon_info), + [] (const a8::XParams& param) + { + Buff* buff = (Buff*)param.sender.GetUserData(); + Creature* sender = buff->owner; + SummonHeroInfo* summon_info = (SummonHeroInfo*)param.param1.GetUserData(); + Hero* hero = sender->room->CreateHero + (sender, + summon_info->hero_meta, + summon_info->born_pos, + summon_info->dir, + sender->team_id + ); + if (!hero) { + return; + } + sender->RemoveSurplusHero(buff->meta->i->buff_id(), + summon_info->hero_meta->i->id(), + summon_info->num); + sender->slave_heros_.push_back(std::make_tuple(buff->meta->i->buff_id(), hero)); + hero->room->xtimer.AddDeadLineTimerAndAttach + ( + summon_info->life_time / FRAME_RATE_MS, + a8::XParams(), + [] (const a8::XParams& param) + { + }, + &hero->xtimer_attacher.timer_list_, + [] (const a8::XParams& param) + { + + }); +#ifdef DEBUG + sender->SendDebugMsg(a8::Format("summon hero id:%d pos:%f,%f", + { + summon_info->hero_meta->i->id(), + summon_info->born_pos.x, + summon_info->born_pos.y + })); +#endif + }, + &buff->xtimer_attacher.timer_list_, + [] (const a8::XParams& param) + { + SummonHeroInfo* summon_info = (SummonHeroInfo*)param.param1.GetUserData(); + delete summon_info; + }); } return nullptr; } diff --git a/server/gameserver/creature.h b/server/gameserver/creature.h index e1f17802..2928ce9f 100644 --- a/server/gameserver/creature.h +++ b/server/gameserver/creature.h @@ -272,7 +272,9 @@ private: void RemoveSurplusObstacle(int buff_id, int id, int num); void CheckAbilityUsed(); void ProcOnceChgAttrBuff(MetaData::Buff* buff_meta); - Hero* InternalSummonHero(MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, bool through_wall ); + bool TrySummonHero(MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, bool through_wall); + Hero* InternalSummonHero(Buff* buff, MetaData::Player* hero_meta, a8::Vec2 dir, a8::Vec2 born_pos, + bool through_wall, int num, int life_time); void AutoSwitchWeapon(); void CheckLoadingBullet(); diff --git a/server/gameserver/metadata.cc b/server/gameserver/metadata.cc index 7d5b545e..7adaf946 100644 --- a/server/gameserver/metadata.cc +++ b/server/gameserver/metadata.cc @@ -626,6 +626,20 @@ namespace MetaData init_buffs.push_back(a8::XValue(str)); } } + { + std::vector strings; + a8::Split(i->pre_appear_effect(), strings, '|'); + for (auto& str : strings) { + std::vector strings2; + a8::Split(str, strings2, ':'); + assert(strings2.size() == 2); + if (strings2.size() >= 2) { + int thing_id = a8::XValue(strings2[0]); + int time = a8::XValue(strings2[1]); + pre_appear_effect.push_back(std::make_tuple(thing_id, time)); + } + } + } } int Player::RandDrop() diff --git a/server/gameserver/metadata.h b/server/gameserver/metadata.h index cd5c70fd..d86a4a87 100644 --- a/server/gameserver/metadata.h +++ b/server/gameserver/metadata.h @@ -134,6 +134,7 @@ namespace MetaData std::array volume = {}; std::vector init_buffs; std::vector> dead_drop; + std::vector> pre_appear_effect; bool HasDrop() { return !dead_drop.empty();}; void Init(); diff --git a/server/tools/protobuild/metatable.proto b/server/tools/protobuild/metatable.proto index 0c2841b0..ba99472c 100755 --- a/server/tools/protobuild/metatable.proto +++ b/server/tools/protobuild/metatable.proto @@ -235,6 +235,7 @@ message Player optional int32 ai = 46; optional int32 delay_remove = 47; optional int32 skinlist = 48; + optional string pre_appear_effect = 50; } message Robot