diff --git a/server/gameserver/creature.cc b/server/gameserver/creature.cc index f9d0fca..eabce40 100644 --- a/server/gameserver/creature.cc +++ b/server/gameserver/creature.cc @@ -2400,6 +2400,7 @@ bool Creature::CheckCollision() { Global::last_collider = nullptr; if (room->OverBorder(GetPos(), GetRadius())){ + ++collision_times_; return true; } if (HasBuffEffect(kBET_ThroughWall) || @@ -2424,6 +2425,7 @@ bool Creature::CheckCollision() (collider->type == CT_Circle && self_collider_->Intersect(collider)) ) { if (obstacle->OnCollisionTrigger(this, collider) == 1) { + ++collision_times_; return true; } } @@ -2437,6 +2439,7 @@ bool Creature::CheckCollision() (collider->type == CT_Circle && self_collider_->Intersect(collider)) ) { Global::last_collider = collider; + ++collision_times_; return true; } } @@ -2448,6 +2451,7 @@ bool Creature::CheckCollision() (collider->type == CT_Circle && self_collider_->Intersect(collider)) ) { Global::last_collider = collider; + ++collision_times_; return true; } } diff --git a/server/gameserver/creature.h b/server/gameserver/creature.h index c6b1231..38b765b 100644 --- a/server/gameserver/creature.h +++ b/server/gameserver/creature.h @@ -210,6 +210,7 @@ class Creature : public MoveableEntity std::shared_ptr& GetAbility() { return ability_; }; void RefreshHP(); void TraverseBuff(std::function func); + long long GetCollisionTimes() { return collision_times_; }; protected: @@ -252,6 +253,7 @@ protected: private: CreatureWeakPtr weak_ptr_; Trigger* trigger_ = nullptr; + long long collision_times_ = 0; Team* team_ = nullptr; Weapon* curr_weapon_ = nullptr; CreatureWeakPtrChunk weak_ptr_chunk_; diff --git a/server/gameserver/hero.ai.cc b/server/gameserver/hero.ai.cc index 1d742a3..f1f454e 100644 --- a/server/gameserver/hero.ai.cc +++ b/server/gameserver/hero.ai.cc @@ -7,6 +7,7 @@ #include "room.h" #include "metamgr.h" #include "player.h" +#include "roomobstacle.h" HeroAI::HeroAI() { @@ -74,6 +75,11 @@ void HeroAI::UpdateAI() UpdateFollowMaster(); } break; + case HSE_SweepMine: + { + UpdateSweepMine(); + } + break; default: { abort(); @@ -112,6 +118,14 @@ void HeroAI::UpdateThinking() ChangeToStateAI(HSE_FollowMaster); return; } + if (ai_meta->i->ai_kind() == kAI_MineSweeper) { + RoomObstacle* target = FindObstacleTarget(); + if (target) { + node_->target_obstacle.Attach(target); + ChangeToStateAI(HSE_SweepMine); + return; + } + } Creature* target = GetTarget(); if (target) { node_->target.Attach(target); @@ -337,10 +351,24 @@ void HeroAI::ChangeToStateAI(HeroState_e to_state) } } break; + case HSE_SweepMine: + { + moving_ = true; + a8::Vec2 move_dir = node_->target_obstacle.Get()->GetPos() - hero->GetPos(); + move_dir.Normalize(); + hero->SetMoveDir(move_dir); + hero->SetAttackDir(hero->GetMoveDir()); + } + break; + default: + { + } + break; } node_->main_state = to_state; node_->frameno = hero->room->GetFrameNo(); node_->exec_frame_num = 0; + node_->last_collision_times = hero->GetCollisionTimes(); } Creature* HeroAI::GetTarget() @@ -438,3 +466,46 @@ int HeroAI::GetAttackTimes() return ai_meta->i->attack_times(); } } + +void HeroAI::UpdateSweepMine() +{ + Hero* myself = (Hero*)owner; + if (!node_->target_obstacle.Get() || node_->target_obstacle.Get()->IsDead(myself->room)) { + ChangeToStateAI(HSE_Thinking); + return; + } + if (node_->exec_frame_num > SERVER_FRAME_RATE * 8) { + ChangeToStateAI(HSE_Thinking); + return; + } + if (myself->HasBuffEffect(kBET_Vertigo)) { + return; + } + if (node_->exec_frame_num % SERVER_FRAME_RATE == 0) { + a8::Vec2 move_dir = node_->target_obstacle.Get()->GetPos() - myself->GetPos(); + move_dir.Normalize(); + myself->SetMoveDir(move_dir); + myself->SetAttackDir(myself->GetMoveDir()); + } + float distance = myself->GetPos().Distance(node_->target_obstacle.Get()->GetPos()); + if (distance < myself->GetSpeed() + 2) { + myself->_UpdateMove(distance); + distance = myself->GetPos().Distance(node_->target_obstacle.Get()->GetPos()); + } + if (!node_->target_obstacle.Get() || node_->target_obstacle.Get()->IsDead(myself->room)) { + ChangeToStateAI(HSE_Thinking); + } else { + if (myself->GetCollisionTimes() > node_->last_collision_times) { + ChangeToStateAI(HSE_Thinking); + } else { + if (distance < 3) { + ChangeToStateAI(HSE_Idle); + } + } + } +} + +RoomObstacle* HeroAI::FindObstacleTarget() +{ + return nullptr; +} diff --git a/server/gameserver/hero.ai.h b/server/gameserver/hero.ai.h index 9ea7954..ff0e818 100644 --- a/server/gameserver/hero.ai.h +++ b/server/gameserver/hero.ai.h @@ -7,12 +7,13 @@ enum HeroState_e : int { - HSE_Idle = 0, - HSE_Thinking = 1, - HSE_Attack = 2, - HSE_RandomWalk = 3, - HSE_Pursuit = 4, - HSE_FollowMaster = 5 + HSE_Idle, + HSE_Thinking, + HSE_Attack, + HSE_RandomWalk, + HSE_Pursuit, + HSE_FollowMaster, + HSE_SweepMine }; class HeroAINode @@ -33,6 +34,8 @@ public: long long last_check_nearest_human_frameno = 0; a8::Vec2 shot_dir; a8::Vec2 target_pos; + RoomObstacleWeakPtr target_obstacle; + long long last_collision_times = 0; }; class HeroAI : public AIComponent @@ -52,11 +55,13 @@ protected: void UpdateRandomWalk(); void UpdatePursuit(); void UpdateFollowMaster(); + void UpdateSweepMine(); void DoMoveAI(); void ChangeToStateAI(HeroState_e to_state); void DoShotAI(); Creature* GetTarget(); + RoomObstacle* FindObstacleTarget(); float GetAttackRange(); int GetAttackTimes();