1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#include "critter-script.hpp"
//#include "raycast.hpp"
#include "compat/failwith.hpp"
#include "point.hpp"
#include "nanosecond.hpp"
#include "critter.hpp"
#include "search-result.hpp"
#include "search-astar.hpp"
#include "entity/name-of.hpp"
namespace floormat {
namespace {
struct walk_script;
constexpr StringView script_name = name_of<walk_script>;
using ScriptPtr = Pointer<critter_script>;
using psr = path_search_result;
struct walk_script final : critter_script
{
enum class walk_mode : uint8_t { none, line, path, };
StringView name() const override;
const void* id() const override;
void on_init(const std::shared_ptr<critter>& c) override;
void on_update(const std::shared_ptr<critter>& c, size_t& i, const Ns& dt) override;
void on_destroy(const std::shared_ptr<critter>& c, script_destroy_reason reason) override;
void delete_self() noexcept override;
walk_script(point dest);
walk_script(psr path);
bool walk_line(const std::shared_ptr<critter>& c, size_t& i, const Ns& dt);
bool walk_path(const std::shared_ptr<critter>& c, size_t& i, const Ns& dt);
private:
point dest;
psr path;
uint32_t path_index = -1u;
walk_mode mode = failwith<walk_mode>("walk_mode not set");
};
StringView walk_script::name() const { return "walk"_s; }
const void* walk_script::id() const { return &script_name; }
void walk_script::on_destroy(const std::shared_ptr<critter>& c, script_destroy_reason) { c->clear_auto_movement(); }
void walk_script::delete_self() noexcept { delete this; }
void walk_script::on_init(const std::shared_ptr<critter>& c)
{
Debug{} << "| start walking from" << c->position() << "to" << dest;
c->moves.AUTO = true;
switch (mode)
{
case walk_mode::line:
break;
case walk_mode::path:
fm_assert(!path.empty());
dest = path.path().back();
break;
default:
std::unreachable();
fm_assert(false);
}
}
void walk_script::on_update(const std::shared_ptr<critter>& c, size_t& i, const Ns& dt)
{
if (c->maybe_stop_auto_movement())
goto done;
switch (mode)
{
case walk_mode::line:
fm_assert(!path);
if (walk_line(c, i, dt))
goto done;
return;
case walk_mode::path:
if (walk_path(c, i, dt))
goto done;
return;
case walk_mode::none:
break;
}
fm_assert(false);
done:
//path = {};
Debug{} << " finished walking";
c->clear_auto_movement();
c->script.do_clear(c);
}
walk_script::walk_script(point dest) : dest{dest}, mode{walk_mode::line} {}
walk_script::walk_script(psr path) : dest{path.path().back()}, path{move(path)}, mode{walk_mode::path} { fm_assert(!path.empty()); }
bool walk_script::walk_line(const std::shared_ptr<critter>& c, size_t& i, const Ns& dtʹ)
{
auto dt = dtʹ;
auto res = c->move_toward(i, dt, dest);
return res.blocked || c->position() == dest;
}
bool walk_script::walk_path(const std::shared_ptr<critter>& c, size_t& i, const Ns& dtʹ)
{
point cur;
for (cur = path.path()[path_index]; c->position() == cur; path_index++) [[unlikely]]
if (path_index == path.size()) [[unlikely]]
return true;
auto dt = dtʹ;
auto ret = c->move_toward(i, dt, cur);
Debug{} << "move toward" << cur << dt;
return ret.blocked;
// todo allow move_toward() to return portion of dt
}
} // namespace
ScriptPtr critter_script::make_walk_script(point dest) { return ScriptPtr(new walk_script{dest}); }
ScriptPtr critter_script::make_walk_script(psr path) { return ScriptPtr(new walk_script{move(path)}); }
} // namespace floormat
|