diff --git a/server/gameserver/creature.cc b/server/gameserver/creature.cc index b9b29f48..145e103a 100644 --- a/server/gameserver/creature.cc +++ b/server/gameserver/creature.cc @@ -2366,7 +2366,19 @@ void Creature::UpdateMove() } } room->grid_service->MoveCreature(this); - if (room->IsPveRoom() && IsEntityType(ET_Hero) && IsNearGas()) { + if (a8::HasBitFlag(status, CS_CrazeMode) && IsNearGas(100)) { + GetMutablePos() = old_pos; + GetMovement()->ClearPath(); + glm::vec2 dir2 = room->GetGasData().pos_new - room->GetGasData().pos_old; + glm::vec3 dir = glm::vec3(dir2.x, 0.0f, dir2.y); + if (std::abs(dir.x) > FLT_EPSILON || + std::abs(dir.y) > FLT_EPSILON || + std::abs(dir.z) > FLT_EPSILON + ) { + GlmHelper::Normalize(dir); + SetMoveDir(dir); + } + } else if (room->IsPveRoom() && IsEntityType(ET_Hero) && IsNearGas(20)) { GetMutablePos() = old_pos; GetMovement()->ClearPath(); glm::vec3 dir = GetPos().ToGlmVec3() - old_pos.ToGlmVec3(); @@ -2377,7 +2389,7 @@ void Creature::UpdateMove() GlmHelper::Normalize(dir); SetMoveDir(dir); } - } else if (room->IsNewBieRoom() && IsNearGas()) { + } else if (room->IsNewBieRoom() && IsNearGas(20)) { GetMutablePos() = old_pos; GetMovement()->ClearPath(); } @@ -2979,12 +2991,12 @@ void Creature::NetInitOk() { } -bool Creature::IsNearGas() +bool Creature::IsNearGas(float distance) { Position p; p.FromGlmVec3(glm::vec3(room->GetGasData().pos_new.x, 0, room->GetGasData().pos_new.y)); - float distance = GetPos().Distance2D2(p); - return distance + GetRadius() * 2 + 20 > room->GetGasData().rad_new; + float gas_distance = GetPos().Distance2D2(p); + return gas_distance + GetRadius() * 2 + distance > room->GetGasData().rad_new; } float Creature::GetSpeed() diff --git a/server/gameserver/creature.h b/server/gameserver/creature.h index 60f3d55d..ac4814b0 100644 --- a/server/gameserver/creature.h +++ b/server/gameserver/creature.h @@ -16,6 +16,8 @@ enum CreatureStatus CS_PreDieSuspended, CS_DeadNoDrop, CS_Reviving, + CS_CrazeMode, + CS_DisableAttackAndroid, CS_End }; @@ -122,6 +124,8 @@ class Creature : public MoveableEntity bool shot_start = false; bool shot_hold = false; + a8::XTimerWp craze_mode_timer; + Creature(); virtual ~Creature() override; virtual void Initialize() override; @@ -351,7 +355,7 @@ class Creature : public MoveableEntity void ShortFindPath(); float GetSkillRaycastDistance(); virtual void NetInitOk(); - bool IsNearGas(); + bool IsNearGas(float distance); std::shared_ptr> CalcReporterList(bool is_trace_bullet, const mt::Equip* weapon_meta, const mt::Equip* bullet_meta); diff --git a/server/gameserver/incubator.cc b/server/gameserver/incubator.cc index 9159d480..9b16ee97 100644 --- a/server/gameserver/incubator.cc +++ b/server/gameserver/incubator.cc @@ -17,6 +17,7 @@ #include "mt/PveGeminiMode.h" #include "mt/PveGeminiContent.h" #include "mt/Text.h" +#include "mt/SafeArea.h" void Incubator::Init() { @@ -151,6 +152,9 @@ void Incubator::AllocAndroid(Human* target, int num, std::vector* androi room->BroadcastDebugMsg(a8::Format("投放机器人 分配失败 %d", {hold_humans_.size()})); } #endif + if (hold_humans_.size() <= 6 && room->GetGasData().new_area_meta->GetSmallRingCount() < 3) { + ShowHand(); + } } void Incubator::RecycleAndroid(Human* hum) @@ -244,7 +248,7 @@ void Incubator::AutoAllocAndroid() killer->GetCurrWeapon()->weapon_id, killer->GetUniId(), killer->name); - } else if (room->GetGasData().gas_count > 1) { + } else if (room->GetGasData().gas_count > 2) { hum->BeKill(VP_Gas, TEXT("battle_server_killer_gas", "毒圈"), VW_Gas, @@ -471,3 +475,35 @@ void Incubator::NextWave() #endif } } + +void Incubator::ShowHand() +{ + #ifdef DEBUG + a8::XPrintf("ShowHand\n", {}); + #endif + for (auto& hum : hold_humans_) { + glm::vec3 point = glm::vec3(room->GetGasData().new_area_meta->GetLastArea()->x1(), + 6.0f, + room->GetGasData().new_area_meta->GetLastArea()->y1()); + Global::Instance()->verify_set_pos = 1; + hum->GetMutablePos().FromGlmVec3(point); + Global::Instance()->verify_set_pos = 0; + + a8::SetBitFlag(hum->status, CS_CrazeMode); + a8::SetBitFlag(hum->status, CS_DisableAttackAndroid); + room->xtimer.SetTimeoutEx + ( + SERVER_FRAME_RATE * 20, + [hum] (int event, const a8::Args* args) + { + if (a8::TIMER_EXEC_EVENT == event) { + a8::UnSetBitFlag(hum->status, CS_DisableAttackAndroid); + } + }, + &hum->xtimer_attacher); + + room->EnableHuman(hum); + hum->MustBeAddBuff(hum, kTraceBuffId); + } + hold_humans_.clear(); +} diff --git a/server/gameserver/incubator.h b/server/gameserver/incubator.h index 391a8a40..7f9aab65 100644 --- a/server/gameserver/incubator.h +++ b/server/gameserver/incubator.h @@ -24,6 +24,7 @@ private: void AutoAllocAndroid(); void OnEnterNewWave(int wave); void SpawnWaveMon(int wave); + void ShowHand(); private: int wait_alloc_time_ = 0; diff --git a/server/gameserver/mt/SafeArea.cc b/server/gameserver/mt/SafeArea.cc index 37083921..e9ad0646 100644 --- a/server/gameserver/mt/SafeArea.cc +++ b/server/gameserver/mt/SafeArea.cc @@ -4,15 +4,26 @@ IMPL_TABLE(mt::SafeArea) -std::map mt::SafeArea::type_hash_; +std::map> mt::SafeArea::type_hash_; namespace mt { void SafeArea::Init1() { - if (!GetByType(type())) { - type_hash_[type()] = this; + { + auto itr = type_hash_.find(type()); + if (itr == type_hash_.end()) { + type_hash_[type()] = std::vector({this}); + } else { + if (itr->second.empty()) { + abort(); + } + if (itr->second.at(itr->second.size() - 1)->id() + 1 != id()) { + abort(); + } + itr->second.push_back(this); + } } if (!boss().empty()) { std::vector strings; @@ -32,10 +43,25 @@ namespace mt } } + void SafeArea::StaticPostInit() + { + for (auto& pair : type_hash_) { + if (pair.second.size() < 1) { + abort(); + } + int ring_count = pair.second.size() - 1; + auto last_area = pair.second.at(pair.second.size() - 1); + for (auto& meta : pair.second) { + meta->small_ring_count_ = ring_count--; + meta->last_area_ = last_area; + } + } + } + const SafeArea* SafeArea::GetByType(int type) { auto itr = type_hash_.find(type); - return itr != type_hash_.end() ? itr->second : nullptr; + return itr != type_hash_.end() ? itr->second.at(0) : nullptr; } } diff --git a/server/gameserver/mt/SafeArea.h b/server/gameserver/mt/SafeArea.h index 2c38878d..8550a1ce 100644 --- a/server/gameserver/mt/SafeArea.h +++ b/server/gameserver/mt/SafeArea.h @@ -12,13 +12,18 @@ namespace mt public: void Init1(); + static void StaticPostInit(); std::shared_ptr> GetBoss() const { return _boss; } + int GetSmallRingCount() const { return small_ring_count_; } + const mt::SafeArea* GetLastArea() const { return last_area_; } static const SafeArea* GetByType(int type); private: - static std::map type_hash_; + static std::map> type_hash_; + int small_ring_count_ = 0; + const mt::SafeArea* last_area_ = nullptr; std::shared_ptr> _boss; }; diff --git a/server/gameserver/room.cc b/server/gameserver/room.cc index d8e1c158..043ca216 100644 --- a/server/gameserver/room.cc +++ b/server/gameserver/room.cc @@ -455,11 +455,15 @@ Human* Room::FindEnemy(Human* hum, float range) if (!hum->dead && !a8::HasBitFlag(hum->status, CS_Disable) && hum->team_id != myself->team_id) { - float distance = hum->GetPos().Distance2D2(myself->GetPos()); - if (distance <= range) { - if (distance < last_distance) { - target = hum; - last_distance = distance; + if (a8::HasBitFlag(hum->status, CS_DisableAttackAndroid) && + target->IsAndroid()) { + } else { + float distance = hum->GetPos().Distance2D2(myself->GetPos()); + if (distance <= range) { + if (distance < last_distance) { + target = hum; + last_distance = distance; + } } } }