#include "precompile.h" #include #include #include "movement.h" #include "moveableentity.h" #include "room.h" #include "mapinstance.h" #include "creature.h" #include "mt/Map.h" Movement::Movement(Creature* owner) { owner_ = owner; } bool Movement::UpdatePosition() { if (path_index_ >= paths_.size()) { ClearPath(); is_find_path_ = false; return false; } MovePathPoint& curr_point = paths_[path_index_]; { curr_point.curr_pos.AddGlmVec3(curr_point.dir * owner_->GetSpeed()); owner_->SetPos(curr_point.curr_pos); owner_->room->map_instance->CheckTerrain(owner_, curr_point.same_polys_flags, curr_point.spec_polys); } if (owner_->GetPos().Distance2D2(curr_point.src_pos) - curr_point.distance >= 0.0001f) { #ifdef DEBUG1 if (owner_->IsPlayer()) { a8::XPrintf("UpdatePosition curr_pos:%f %f %f tar_pos:%f %f %f\n", { curr_point.curr_pos.GetX(), curr_point.curr_pos.GetY(), curr_point.curr_pos.GetZ(), curr_point.tar_pos.GetX(), curr_point.tar_pos.GetY(), curr_point.tar_pos.GetZ() }); } #endif #if 0 curr_point.tar_pos.SetY(curr_point.curr_pos.GetY()); #endif owner_->SetPos(curr_point.tar_pos); ++path_index_; if (path_index_ < paths_.size()) { MovePathPoint& next_point = paths_[path_index_]; if (IsFindPath()) { owner_->SetMoveDir(next_point.dir); owner_->SetAttackDir(next_point.dir); } #if 0 glm::vec3 dir = next_point.tar_pos.ToGlmVec3() - owner_->GetPos().ToGlmVec3(); GlmHelper::Normalize(dir); next_point.dir.x = dir.x; next_point.dir.y = dir.y; next_point.dir.z = dir.z; #endif } } owner_->AdjustPos(); #if 0 if (owner_->GetPos().GetX() < 0 || owner_->GetPos().GetZ() < 0) { abort(); } #endif return true; } void Movement::CalcTargetPos(float distance) { ClearPath(); #ifdef DEBUG1 if (owner_->IsPlayer()) { a8::XPrintf("CalcTaretPos old_size:%d distance:%f\n", {paths_.size(), distance}); } #endif Position pos = owner_->GetPos(); glm::vec3 start = owner_->GetPos().ToGlmVec3(); glm::vec3 end = pos.AddGlmVec3(owner_->GetMoveDir() * distance).ToGlmVec3(); if (end.x < 0.0f) { end.x = 0.0f; } if (end.z < 0.0f) { end.z = 0.0f; } bool hit_result = false; MovePathPoint point; if (owner_->HasBuffEffect(kBET_ThroughWall) || owner_->HasBuffEffect(kBET_Fly) || owner_->HasBuffEffect(kBET_Jump)) { point.tar_pos.FromGlmVec3(end); if (point.tar_pos.GetX() > owner_->room->GetMapMeta()->map_width() + 10) { point.tar_pos.SetX(owner_->room->GetMapMeta()->map_width() - 10); } if (point.tar_pos.GetZ() > owner_->room->GetMapMeta()->map_height() + 10) { point.tar_pos.SetZ(owner_->room->GetMapMeta()->map_height() - 10); } if (point.tar_pos.GetX() < 10) { point.tar_pos.SetX(10); } if (point.tar_pos.GetZ() < 10) { point.tar_pos.SetZ(10); } } else { unsigned short exclude_flags = 0; if (owner_->HasBuffEffect(kBET_Driver)) { exclude_flags = SAMPLE_POLYFLAGS_DOOR; } glm::vec3 hit_point; owner_->room->map_instance->Scale(start); owner_->room->map_instance->Scale(end); bool ret = owner_->room->map_instance->RaycastEx(start, end, hit_point, hit_result, point.same_polys_flags, point.spec_polys, exclude_flags); if (ret) { owner_->room->map_instance->UnScale(hit_point); point.tar_pos.FromGlmVec3(hit_point); } else { return; } if (point.tar_pos.GetX() < 0 || point.tar_pos.GetZ() < 0) { return; #if 0 abort(); #endif } } point.distance = owner_->GetPos().Distance2D2(point.tar_pos); point.src_pos = owner_->GetPos(); point.curr_pos = owner_->GetPos(); if (point.tar_pos.GetX() < 0 || point.tar_pos.GetZ() < 0) { abort(); } #ifdef DEBUG1 if (owner_->IsPlayer()) { a8::XPrintf("CalcTargetPos src_pos:%f,%f,%f tar_pos:%f,%f,%f is_hit:%d start:%f,%f,%f end:%f,%f,%f distance:%f src_distance:%f\n", { point.src_pos.GetX(), point.src_pos.GetY(), point.src_pos.GetZ(), point.tar_pos.GetX(), point.tar_pos.GetY(), point.tar_pos.GetZ(), hit_result ? 1 : 0, start.x, start.y, start.z, end.x, end.y, end.z, point.distance, distance }); } #endif const float safe_distance = 2.0f; if (point.distance < safe_distance + 1.0f / owner_->room->GetMapMeta()->scale()) { return; } glm::vec3 dir = point.tar_pos.ToGlmVec3() - owner_->GetPos().ToGlmVec3(); GlmHelper::Normalize(dir); point.dir.x = dir.x; point.dir.y = dir.y; point.dir.z = dir.z; point.distance -= safe_distance; point.tar_pos.FromGlmVec3(owner_->GetPos().ToGlmVec3() + point.dir * point.distance); paths_.push_back(point); } void Movement::ClearPath() { is_find_path_ = false; path_index_ = 0; paths_.clear(); } size_t Movement::GetPathSize() { return paths_.size(); } bool Movement::FindPath(const glm::vec3& target_pos, float distance) { ClearPath(); glm::vec3 start = owner_->GetPos().ToGlmVec3(); glm::vec3 end = target_pos; std::vector paths; owner_->room->map_instance->Scale(start); owner_->room->map_instance->Scale(end); owner_->room->map_instance->FindStraightPath(start, end, paths); if (paths.size() > 0) { glm::vec3 last_pos = owner_->GetPos().ToGlmVec3(); for (const glm::vec3& pos1 : paths) { glm::vec3 pos = pos1; owner_->room->map_instance->UnScale(pos); if (!GlmHelper::IsEqual2D(pos, last_pos)) { glm::vec3 dir = pos - last_pos; GlmHelper::Normalize(dir); MovePathPoint point; point.src_pos.FromGlmVec3(last_pos); point.curr_pos.FromGlmVec3(last_pos); point.dir.x = dir.x; point.dir.y = dir.y; point.dir.z = dir.z; point.distance = GlmHelper::Norm2D(pos - last_pos); point.tar_pos.FromGlmVec3(pos); paths_.push_back(point); last_pos = pos; #ifdef DEBUG1 a8::XPrintf("src_pos:%f %f %f tar_pos:%f %f %f distance:%f\n", { last_pos.x, last_pos.y, last_pos.z, pos.x, pos.y, pos.z, point.distance }); #endif } } is_find_path_ = true; if (!paths_.empty()) { owner_->SetMoveDir(paths_.at(0).dir); owner_->SetAttackDir(paths_.at(0).dir); } } AdjustLastPath(distance); return !paths_.empty(); } void Movement::AdjustLastPath(float distance) { if (paths_.empty()) { return; } if (distance < 0.01f) { return; } MovePathPoint& point = paths_.at(paths_.size() - 1); if (point.distance + 3 < distance) { return; } point.distance -= distance; point.tar_pos.FromGlmVec3(point.src_pos.ToGlmVec3() + point.dir * point.distance); }