Skip to content

Commit 53f3bd1

Browse files
authored
Add support for paths for the WillOWisp in the editor (#3265)
* Add support for paths for `WillOWisps` in the editor * Code style * DRY
1 parent 0a84620 commit 53f3bd1

File tree

2 files changed

+151
-45
lines changed

2 files changed

+151
-45
lines changed

src/badguy/willowisp.cpp

Lines changed: 149 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,13 @@ WillOWisp::WillOWisp(const ReaderMapping& reader) :
4949
m_color(0, 1, 0),
5050
m_starting_node(0)
5151
{
52-
if (Editor::is_active()) {
52+
if (Editor::is_active())
53+
{
5354
reader.get("sector", m_target_sector);
5455
reader.get("spawnpoint", m_target_spawnpoint);
55-
} else {
56+
}
57+
else
58+
{
5659
reader.get("sector", m_target_sector, DEFAULT_SECTOR_NAME.c_str());
5760
reader.get("spawnpoint", m_target_spawnpoint, DEFAULT_SPAWNPOINT_NAME.c_str());
5861
}
@@ -62,16 +65,16 @@ WillOWisp::WillOWisp(const ReaderMapping& reader) :
6265
reader.get("vanish-range", m_vanish_range, VANISH_RANGE);
6366
reader.get("hit-script", m_hit_script, "");
6467

65-
bool running;
66-
if ( !reader.get("running", running)) running = false;
68+
bool running = false;
69+
reader.get("running", running);
6770

6871
std::vector<float> color;
6972
if (reader.get("color", color))
7073
{
7174
m_color = Color(color);
7275
}
7376

74-
reader.get("starting-node", m_starting_node, 0.f);
77+
reader.get("starting-node", m_starting_node, 0);
7578

7679
init_path(reader, running);
7780

@@ -88,14 +91,60 @@ WillOWisp::WillOWisp(const ReaderMapping& reader) :
8891
set_action("idle");
8992
}
9093

94+
void
95+
WillOWisp::synchronize_position_from_path()
96+
{
97+
if (!has_valid_path())
98+
return;
99+
100+
const auto& nodes = get_path()->get_nodes();
101+
if (nodes.empty())
102+
return;
103+
104+
const int size = static_cast<int>(nodes.size());
105+
106+
if (m_starting_node < 0)
107+
{
108+
m_starting_node = 0;
109+
}
110+
if (m_starting_node >= size)
111+
{
112+
m_starting_node = size - 1;
113+
}
114+
115+
set_pos(m_path_handle.get_pos(m_col.m_bbox.get_size(), nodes[m_starting_node].position));
116+
}
117+
91118
void
92119
WillOWisp::finish_construction()
93120
{
94-
if (get_walker() && get_walker()->is_running()) {
95-
m_mystate = STATE_PATHMOVING_TRACK;
121+
if (!get_path())
122+
init_path_pos(m_col.m_bbox.p1());
123+
124+
synchronize_position_from_path();
125+
126+
if (has_valid_path())
127+
{
128+
const auto& nodes = get_path()->get_nodes();
129+
if (!nodes.empty())
130+
{
131+
get_walker()->jump_to_node(m_starting_node);
132+
133+
if (get_walker()->is_running())
134+
{
135+
m_mystate = STATE_PATHMOVING_TRACK;
136+
get_walker()->start_moving();
137+
}
138+
}
96139
}
97140
}
98141

142+
void
143+
WillOWisp::editor_update()
144+
{
145+
synchronize_position_from_path();
146+
}
147+
99148
void
100149
WillOWisp::after_editor_set()
101150
{
@@ -105,72 +154,91 @@ WillOWisp::after_editor_set()
105154
m_color.green * 0.2f,
106155
m_color.blue * 0.2f));
107156
m_sprite->set_color(m_color);
157+
158+
if (Editor::is_active())
159+
{
160+
synchronize_position_from_path();
161+
}
108162
}
109163

110164
void
111165
WillOWisp::active_update(float dt_sec)
112166
{
113-
if (Editor::is_active() && get_path() && get_path()->is_valid()) {
167+
if (Editor::is_active() && get_path() && get_path()->is_valid())
168+
{
114169
get_walker()->update(dt_sec);
115170
set_pos(get_walker()->get_pos(m_col.m_bbox.get_size(), m_path_handle));
116171
return;
117172
}
118173

119174
auto player = get_nearest_player();
120175
if (!player) return;
121-
Vector p1 = m_col.m_bbox.get_middle();
122-
Vector p2 = player->get_bbox().get_middle();
176+
const Vector p1 = m_col.m_bbox.get_middle();
177+
const Vector p2 = player->get_bbox().get_middle();
123178
Vector dist = (p2 - p1);
124179

125-
switch (m_mystate) {
180+
switch (m_mystate)
181+
{
126182
case STATE_STOPPED:
127183
break;
128-
129184
case STATE_IDLE:
130-
if (glm::length(dist) <= m_track_range) {
185+
if (glm::length(dist) <= m_track_range)
186+
{
131187
m_mystate = STATE_TRACKING;
132188
}
133189
break;
134-
135190
case STATE_TRACKING:
136-
if (glm::length(dist) > m_vanish_range) {
191+
if (glm::length(dist) > m_vanish_range)
192+
{
137193
vanish();
138-
} else if (glm::length(dist) >= 1) {
194+
}
195+
else if (glm::length(dist) >= 1)
196+
{
139197
Vector dir_ = glm::normalize(dist);
140198
m_col.set_movement(dir_ * dt_sec * m_flyspeed);
141-
} else {
199+
}
200+
else
201+
{
142202
/* We somehow landed right on top of the player without colliding.
143203
* Sit tight and avoid a division by zero. */
144204
}
145205
m_sound_source->set_position(get_pos());
146206
break;
147-
148207
case STATE_WARPING:
149-
if (m_sprite->animation_done()) {
208+
m_col.set_movement(Vector(0.0f, 0.0f));
209+
if (m_sprite->animation_done())
210+
{
150211
remove_me();
151212
}
152213
break;
153-
154-
case STATE_VANISHING: {
214+
case STATE_VANISHING:
215+
{
155216
Vector dir_ = glm::normalize(dist);
156217
m_col.set_movement(dir_ * dt_sec * m_flyspeed);
157-
if (m_sprite->animation_done()) {
218+
if (m_sprite->animation_done())
219+
{
158220
remove_me();
159221
}
160222
break;
161223
}
162224

163225
case STATE_PATHMOVING:
164226
case STATE_PATHMOVING_TRACK:
165-
if (get_walker() == nullptr)
227+
if (!PathObject::has_valid_path())
228+
{
229+
m_mystate = STATE_IDLE;
166230
return;
231+
}
232+
167233
get_walker()->update(dt_sec);
234+
168235
m_col.set_movement(get_walker()->get_pos(m_col.m_bbox.get_size(), m_path_handle) - get_pos());
169-
if (m_mystate == STATE_PATHMOVING_TRACK && glm::length(dist) <= m_track_range) {
236+
if (m_mystate == STATE_PATHMOVING_TRACK && glm::length(dist) <= m_track_range)
237+
{
170238
m_mystate = STATE_TRACKING;
171239
}
172-
break;
173240

241+
break;
174242
default:
175243
assert(false);
176244
}
@@ -195,7 +263,8 @@ WillOWisp::deactivate()
195263
{
196264
m_sound_source.reset(nullptr);
197265

198-
switch (m_mystate) {
266+
switch (m_mystate)
267+
{
199268
case STATE_STOPPED:
200269
case STATE_IDLE:
201270
case STATE_PATHMOVING:
@@ -225,7 +294,8 @@ WillOWisp::vanish()
225294
}
226295

227296
bool
228-
WillOWisp::collides(MovingObject& other, const CollisionHit& ) const {
297+
WillOWisp::collides(MovingObject& other, const CollisionHit&) const
298+
{
229299
auto lantern = dynamic_cast<Lantern*>(&other);
230300

231301
// vv 'xor'
@@ -239,7 +309,8 @@ WillOWisp::collides(MovingObject& other, const CollisionHit& ) const {
239309
}
240310

241311
HitResponse
242-
WillOWisp::collision_player(Player& player, const CollisionHit& ) {
312+
WillOWisp::collision_player(Player& player, const CollisionHit&)
313+
{
243314
if (player.is_invincible())
244315
return ABORT_MOVE;
245316

@@ -249,9 +320,12 @@ WillOWisp::collision_player(Player& player, const CollisionHit& ) {
249320
m_mystate = STATE_WARPING;
250321
set_action("warping", 1);
251322

252-
if (!m_hit_script.empty()) {
323+
if (!m_hit_script.empty())
324+
{
253325
Sector::get().run_script(m_hit_script, "hit-script");
254-
} else {
326+
}
327+
else
328+
{
255329
GameSession::current()->respawn(m_target_sector, m_target_spawnpoint);
256330
}
257331
SoundManager::current()->play("sounds/warp.wav", get_pos());
@@ -262,6 +336,15 @@ WillOWisp::collision_player(Player& player, const CollisionHit& ) {
262336
void
263337
WillOWisp::goto_node(int node_idx)
264338
{
339+
// If the wisp is following a player refuse to "snap back" to the path it was supposed to follow.
340+
if (m_mystate == STATE_TRACKING)
341+
return;
342+
343+
if (!has_valid_path())
344+
{
345+
return;
346+
}
347+
265348
PathObject::goto_node(node_idx);
266349

267350
if (m_mystate != STATE_PATHMOVING && m_mystate != STATE_PATHMOVING_TRACK)
@@ -277,22 +360,35 @@ WillOWisp::set_state(const std::string& new_state)
277360
m_mystate = STATE_IDLE;
278361
else if (new_state == "move_path")
279362
{
280-
m_mystate = STATE_PATHMOVING;
281-
if (get_walker())
282-
get_walker()->start_moving();
363+
if (has_valid_path())
364+
{
365+
m_mystate = STATE_PATHMOVING;
366+
if (get_walker())
367+
get_walker()->start_moving();
368+
}
369+
else
370+
{
371+
m_mystate = STATE_IDLE;
372+
}
283373
}
284374
else if (new_state == "move_path_track")
285375
{
286-
m_mystate = STATE_PATHMOVING_TRACK;
287-
if (get_walker())
288-
get_walker()->start_moving();
376+
if (has_valid_path())
377+
{
378+
m_mystate = STATE_PATHMOVING_TRACK;
379+
if (get_walker()) get_walker()->start_moving();
380+
}
381+
else
382+
{
383+
m_mystate = STATE_IDLE;
384+
}
289385
}
290386
else if (new_state == "normal")
291387
m_mystate = STATE_IDLE;
292388
else if (new_state == "vanish")
293389
vanish();
294390
else
295-
log_warning << "Cannot set unknown Will-O-Wisp state: '" << new_state << "'." << std::endl;
391+
log_warning << "Cannot set an unknown WillOWisp state: '" << new_state << "'." << std::endl;
296392
}
297393

298394
ObjectSettings
@@ -309,27 +405,34 @@ WillOWisp::get_settings()
309405
result.add_path_ref(_("Path"), *this, get_path_ref(), "path-ref");
310406
result.add_int(_("Starting Node"), &m_starting_node, "starting-node", 0, 0U);
311407
result.add_color(_("Color"), &m_color, "color");
312-
if (get_path())
408+
409+
if (get_path_gameobject() && get_path())
313410
{
314-
result.add_bool(_("Adapt Speed"), &get_path()->m_adapt_speed, {}, {});
411+
result.add_walk_mode(_("Path Mode"), &get_path()->m_mode, {}, {});
412+
result.add_bool(_("Adapt Speed"), &get_path()->m_adapt_speed, "adapt-speed", {});
315413
result.add_path_handle(_("Handle"), m_path_handle, "handle");
414+
result.add_bool(_("Running"), &get_walker()->m_running, "running", false, 0);
316415
}
317416

318-
result.reorder({"sector", "spawnpoint", "flyspeed", "track-range", "hit-script", "vanish-range", "name", "path-ref", "width", "height", "x", "y"});
417+
result.reorder({ "name", "x", "y", "width", "height", "path-ref", "starting-node", "running", "path-walk-mode", "adapt-speed", "handle", "flyspeed", "track-range", "vanish-range", "sector", "spawnpoint", "hit-script", "color" });
319418

320419
return result;
321420
}
322421

323-
void WillOWisp::stop_looping_sounds()
422+
void
423+
WillOWisp::stop_looping_sounds()
324424
{
325-
if (m_sound_source) {
425+
if (m_sound_source)
426+
{
326427
m_sound_source->stop();
327428
}
328429
}
329430

330-
void WillOWisp::play_looping_sounds()
431+
void
432+
WillOWisp::play_looping_sounds()
331433
{
332-
if (m_sound_source) {
434+
if (m_sound_source)
435+
{
333436
m_sound_source->play();
334437
}
335438
}
@@ -338,7 +441,8 @@ void
338441
WillOWisp::move_to(const Vector& pos)
339442
{
340443
Vector shift = pos - m_col.m_bbox.p1();
341-
if (get_path()) {
444+
if (get_path())
445+
{
342446
get_path()->move_by(shift);
343447
}
344448
set_pos(pos);

src/badguy/willowisp.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class WillOWisp final : public BadGuy,
6969
static std::string display_name() { return _("Will o' Wisp"); }
7070
virtual std::string get_display_name() const override { return display_name(); }
7171
virtual GameObjectClasses get_class_types() const override { return BadGuy::get_class_types().add(typeid(PathObject)).add(typeid(WillOWisp)); }
72+
virtual void editor_update() override;
7273

7374
virtual ObjectSettings get_settings() override;
7475
virtual void move_to(const Vector& pos) override;
@@ -86,6 +87,7 @@ class WillOWisp final : public BadGuy,
8687
private:
8788
virtual bool collides(MovingObject& other, const CollisionHit& hit) const override;
8889
virtual HitResponse collision_player(Player& player, const CollisionHit& hit) override;
90+
void synchronize_position_from_path();
8991

9092
private:
9193
enum MyState {

0 commit comments

Comments
 (0)