293 lines
8.9 KiB
C++
293 lines
8.9 KiB
C++
#include "precompile.h"
|
|
|
|
#include <math.h>
|
|
#include <glm/glm.hpp>
|
|
|
|
#include "movement.h"
|
|
#include "moveableentity.h"
|
|
#include "room.h"
|
|
#include "mapinstance.h"
|
|
#include "creature.h"
|
|
#include "human.h"
|
|
#include "stats.h"
|
|
#include "car.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_->IsHuman() && owner_->room->BattleStarted()) {
|
|
owner_->AsHuman()->stats->IncMoveDistance(owner_->GetSpeed());
|
|
}
|
|
}
|
|
if (owner_->GetPos().Distance2D2(curr_point.src_pos) - curr_point.distance >= 0.0001f) {
|
|
#ifdef MYDEBUG1
|
|
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 MYDEBUG1
|
|
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 MYDEBUG1
|
|
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();
|
|
if (owner_->IsCar() && owner_->AsCar()->GetDriver()) {
|
|
owner_->AsCar()->GetDriver()->GetMovement()->ClearPath();
|
|
}
|
|
}
|
|
|
|
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;
|
|
#if 1
|
|
owner_->room->map_instance->Scale(start);
|
|
owner_->room->map_instance->Scale(end);
|
|
owner_->room->map_instance->FindStraightPath(start, end, paths_);
|
|
if (!paths_.empty()) {
|
|
is_find_path_ = true;
|
|
if (!paths_.empty()) {
|
|
owner_->SetMoveDir(paths_.at(0).dir);
|
|
owner_->SetAttackDir(paths_.at(0).dir);
|
|
}
|
|
}
|
|
#else
|
|
std::vector<glm::vec3> paths;
|
|
|
|
owner_->room->map_instance->Scale(start);
|
|
owner_->room->map_instance->Scale(end);
|
|
#if 0
|
|
owner_->room->map_instance->FindStraightPath(start, end, paths);
|
|
#endif
|
|
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 MYDEBUG1
|
|
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);
|
|
}
|
|
}
|
|
#endif
|
|
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);
|
|
}
|