1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See https://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "modes/map/map_event_supervisor.h"
12
13 #include "modes/map/map_mode.h"
14 #include "modes/map/map_sprites/map_virtual_sprite.h"
15
16 #include "engine/system.h"
17
18 namespace vt_map
19 {
20
21 namespace private_map
22 {
23
~EventSupervisor()24 EventSupervisor::~EventSupervisor()
25 {
26 _active_events.clear();
27 _paused_events.clear();
28 _active_delayed_events.clear();
29 _paused_delayed_events.clear();
30
31 for(std::map<std::string, MapEvent *>::iterator it = _all_events.begin(); it != _all_events.end(); ++it) {
32 delete it->second;
33 }
34 _all_events.clear();
35 }
36
StartEvent(const std::string & event_id)37 void EventSupervisor::StartEvent(const std::string &event_id)
38 {
39 MapEvent *event = GetEvent(event_id);
40 if(event == nullptr) {
41 PRINT_WARNING << "No event with this ID existed: '" << event_id
42 << "' in map script: "
43 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
44 return;
45 }
46
47 StartEvent(event);
48 }
49
StartEvent(const std::string & event_id,uint32_t launch_time)50 void EventSupervisor::StartEvent(const std::string &event_id, uint32_t launch_time)
51 {
52 MapEvent *event = GetEvent(event_id);
53 if(event == nullptr) {
54 PRINT_WARNING << "No event with this ID existed: '" << event_id
55 << "' in map script: "
56 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
57 return;
58 }
59
60 if(launch_time == 0)
61 StartEvent(event);
62 else
63 _active_delayed_events.push_back(std::make_pair(static_cast<int32_t>(launch_time), event));
64 }
65
StartEvent(MapEvent * event,uint32_t launch_time)66 void EventSupervisor::StartEvent(MapEvent *event, uint32_t launch_time)
67 {
68 if(event == nullptr) {
69 IF_PRINT_WARNING(MAP_DEBUG) << "nullptr argument passed to function"
70 << std::endl;
71 return;
72 }
73
74 if(launch_time == 0)
75 StartEvent(event);
76 else
77 _active_delayed_events.push_back(std::make_pair(static_cast<int32_t>(launch_time), event));
78 }
79
StartEvent(MapEvent * event)80 void EventSupervisor::StartEvent(MapEvent *event)
81 {
82 if(!event) {
83 PRINT_WARNING << "nullptr argument passed to function" << std::endl;
84 return;
85 }
86
87 // Never ever do that when updating events.
88 if(_is_updating) {
89 PRINT_WARNING << "Tried to start the event: '" << event->GetEventID()
90 << "' within an update function. The StartEvent() call will be ignored. "
91 << std::endl << " You should fix the map script: "
92 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
93 return;
94 }
95
96 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end(); ++it) {
97 if((*it) == event) {
98 IF_PRINT_WARNING(MAP_DEBUG) << "The event: '" << event->GetEventID()
99 << "' is already active and can be active only once at a time. "
100 << "The StartEvent() call will be ignored."
101 << std::endl << " You should fix the map script: "
102 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
103 return;
104 }
105 }
106
107 _active_events.push_back(event);
108 event->_Start();
109 _ExamineEventLinks(event, true);
110 }
111
PauseEvent(const std::string & event_id)112 void EventSupervisor::PauseEvent(const std::string &event_id)
113 {
114 // Never ever do that when updating events.
115 if(_is_updating) {
116 PRINT_WARNING << "Tried to pause the event: '" << event_id
117 << "' within an update function. The PauseEvent() call will be ignored."
118 << std::endl << " You should fix the map script: "
119 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
120 return;
121 }
122
123 // Search for active ones
124 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end();) {
125 if((*it)->_event_id == event_id) {
126 _paused_events.push_back(*it);
127 it = _active_events.erase(it);
128 } else {
129 ++it;
130 }
131 }
132
133 // and for the delayed ones
134 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _active_delayed_events.begin();
135 it != _active_delayed_events.end();) {
136 if((*it).second->_event_id == event_id) {
137 _paused_delayed_events.push_back(*it);
138 it = _active_delayed_events.erase(it);
139 } else {
140 ++it;
141 }
142 }
143 }
144
PauseAllEvents(VirtualSprite * sprite)145 void EventSupervisor::PauseAllEvents(VirtualSprite *sprite)
146 {
147 if(!sprite)
148 return;
149 // Examine all potential active (now or later) events
150
151 // Never ever do that when updating events.
152 if(_is_updating) {
153 PRINT_WARNING << "Tried to pause all events for sprite: " << sprite->GetObjectID()
154 << " within an update function. The PauseAllEvents() call will be ignored."
155 << std::endl << " You should fix the map script: "
156 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
157 return;
158 }
159
160 // Starting by active ones.
161 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end();) {
162 SpriteEvent *event = dynamic_cast<SpriteEvent *>(*it);
163 if(event && event->GetSprite() == sprite) {
164 _paused_events.push_back(*it);
165 it = _active_events.erase(it);
166 } else {
167 ++it;
168 }
169 }
170
171 // Looking at incoming ones.
172 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _active_delayed_events.begin();
173 it != _active_delayed_events.end();) {
174 SpriteEvent *event = dynamic_cast<SpriteEvent *>((*it).second);
175 if(event && event->GetSprite() == sprite) {
176 _paused_delayed_events.push_back(*it);
177 it = _active_delayed_events.erase(it);
178 } else {
179 ++it;
180 }
181 }
182 }
183
ResumeEvent(const std::string & event_id)184 void EventSupervisor::ResumeEvent(const std::string &event_id)
185 {
186 // Never ever do that when updating events.
187 if(_is_updating) {
188 PRINT_WARNING << "Tried to resume event: '" << event_id
189 << "' within an update function. The ResumeEvent() call will be ignored."
190 << std::endl << " You should fix the map script: "
191 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
192 return;
193 }
194
195 for(std::vector<MapEvent *>::iterator it = _paused_events.begin();
196 it != _paused_events.end();) {
197 if((*it)->_event_id == event_id) {
198 _active_events.push_back(*it);
199 it = _paused_events.erase(it);
200 } else {
201 ++it;
202 }
203 }
204
205 // and the delayed ones
206 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _paused_delayed_events.begin();
207 it != _paused_delayed_events.end();) {
208 if((*it).second->_event_id == event_id) {
209 _active_delayed_events.push_back(*it);
210 it = _paused_delayed_events.erase(it);
211 } else {
212 ++it;
213 }
214 }
215 }
216
ResumeAllEvents(VirtualSprite * sprite)217 void EventSupervisor::ResumeAllEvents(VirtualSprite *sprite)
218 {
219 if(!sprite)
220 return;
221 // Examine all potential active (now or later) events
222
223 // Never ever do that when updating events.
224 if(_is_updating) {
225 PRINT_WARNING << "Tried to resume all events for sprite: " << sprite->GetObjectID()
226 << " within an update function. The EndAllEvents() call will be ignored."
227 << std::endl << " You should fix the map script: "
228 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
229 return;
230 }
231
232 // Starting by active ones.
233 for(std::vector<MapEvent *>::iterator it = _paused_events.begin(); it != _paused_events.end();) {
234 SpriteEvent *event = dynamic_cast<SpriteEvent *>(*it);
235 if(event && event->GetSprite() == sprite) {
236 _active_events.push_back(*it);
237 it = _paused_events.erase(it);
238 } else {
239 ++it;
240 }
241 }
242
243 // Looking at incoming ones.
244 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _paused_delayed_events.begin();
245 it != _paused_delayed_events.end();) {
246 SpriteEvent *event = dynamic_cast<SpriteEvent *>((*it).second);
247 if(event && event->GetSprite() == sprite) {
248 _active_delayed_events.push_back(*it);
249 it = _paused_delayed_events.erase(it);
250 } else {
251 ++it;
252 }
253 }
254 }
255
EndEvent(const std::string & event_id,bool trigger_event_links)256 void EventSupervisor::EndEvent(const std::string &event_id, bool trigger_event_links)
257 {
258 // Examine all potential active (now or later) events
259
260 // Never ever do that when updating events.
261 if(_is_updating) {
262 PRINT_WARNING << "Tried to terminate the event: '" << event_id
263 << "' within an update function. The EndEvent() call will be ignored."
264 << std::endl << " You should fix the map script: "
265 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
266 return;
267 }
268
269 // Starting by active ones.
270 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end();) {
271 if((*it)->_event_id == event_id) {
272 SpriteEvent *sprite_event = dynamic_cast<SpriteEvent *>(*it);
273 // Terminated sprite events need to release their owned sprite.
274 if(sprite_event)
275 sprite_event->Terminate();
276
277 MapEvent *terminated_event = *it;
278 it = _active_events.erase(it);
279 // We examine the event links only after the event has been removed from the active list
280 if(trigger_event_links)
281 _ExamineEventLinks(terminated_event, false);
282 } else {
283 ++it;
284 }
285 }
286
287 // Looking at incoming ones.
288 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _active_delayed_events.begin();
289 it != _active_delayed_events.end();) {
290 if((*it).second->_event_id == event_id) {
291 MapEvent *terminated_event = (*it).second;
292 it = _active_delayed_events.erase(it);
293
294 // We examine the event links only after the event has been removed from the active list
295 if(trigger_event_links)
296 _ExamineEventLinks(terminated_event, false);
297 } else {
298 ++it;
299 }
300 }
301
302 // And paused ones
303 for(std::vector<MapEvent *>::iterator it = _paused_events.begin(); it != _paused_events.end();) {
304 if((*it)->_event_id == event_id) {
305 SpriteEvent *sprite_event = dynamic_cast<SpriteEvent *>(*it);
306 // Paused sprite events need to release their owned sprite as they have been previously started.
307 if(sprite_event)
308 sprite_event->Terminate();
309
310 MapEvent *terminated_event = *it;
311 it = _paused_events.erase(it);
312 // We examine the event links only after the event has been removed from the list
313 if(trigger_event_links)
314 _ExamineEventLinks(terminated_event, false);
315 } else {
316 ++it;
317 }
318 }
319
320 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _paused_delayed_events.begin();
321 it != _paused_delayed_events.end();) {
322 if((*it).second->_event_id == event_id) {
323 MapEvent *terminated_event = (*it).second;
324 it = _paused_delayed_events.erase(it);
325
326 // We examine the event links only after the event has been removed from the list
327 if(trigger_event_links)
328 _ExamineEventLinks(terminated_event, false);
329 } else {
330 ++it;
331 }
332 }
333 }
334
EndEvent(MapEvent * event,bool trigger_event_links)335 void EventSupervisor::EndEvent(MapEvent *event, bool trigger_event_links)
336 {
337 if(!event) {
338 PRINT_ERROR << "Couldn't terminate nullptr event" << std::endl;
339 return;
340 }
341
342 // Never ever do that when updating events.
343 if(_is_updating) {
344 PRINT_WARNING << "Tried to terminate the event: '" << event->GetEventID()
345 << "' within an update function. The EndEvent() call will be ignored."
346 << std::endl << " You should fix the map script: "
347 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
348 return;
349 }
350
351 EndEvent(event->GetEventID(), trigger_event_links);
352 }
353
EndAllEvents(VirtualSprite * sprite)354 void EventSupervisor::EndAllEvents(VirtualSprite *sprite)
355 {
356 if(!sprite)
357 return;
358 // Examine all potential active (now or later) events
359
360 // Never ever do that when updating events.
361 if(_is_updating) {
362 PRINT_WARNING << "Tried to terminate all events for sprite: " << sprite->GetObjectID()
363 << " within an update function. The EndAllEvents() call will be ignored."
364 << std::endl << " You should fix the map script: "
365 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
366 return;
367 }
368
369 // Starting by active ones.
370 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end();) {
371 SpriteEvent *event = dynamic_cast<SpriteEvent *>(*it);
372 if(event && event->GetSprite() == sprite) {
373 // Active events need to release their owned sprite upon termination.
374 event->Terminate();
375
376 it = _active_events.erase(it);
377 } else {
378 ++it;
379 }
380 }
381
382 // Looking at incoming ones.
383 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _active_delayed_events.begin();
384 it != _active_delayed_events.end();) {
385 SpriteEvent *event = dynamic_cast<SpriteEvent *>((*it).second);
386 if(event && event->GetSprite() == sprite)
387 it = _active_delayed_events.erase(it);
388 else
389 ++it;
390 }
391
392 // And paused ones
393 for(std::vector<MapEvent *>::iterator it = _paused_events.begin(); it != _paused_events.end();) {
394 SpriteEvent *event = dynamic_cast<SpriteEvent *>(*it);
395 if(event && event->GetSprite() == sprite) {
396 // Paused events have been started, so they might need to release their owned sprite.
397 event->Terminate();
398
399 it = _paused_events.erase(it);
400 } else {
401 ++it;
402 }
403 }
404
405 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _paused_delayed_events.begin();
406 it != _paused_delayed_events.end();) {
407 SpriteEvent *event = dynamic_cast<SpriteEvent *>((*it).second);
408 if(event && event->GetSprite() == sprite)
409 it = _paused_delayed_events.erase(it);
410 else
411 ++it;
412 }
413 }
414
Update()415 void EventSupervisor::Update()
416 {
417 // Store the events that became active in the delayed event loop.
418 std::vector<MapEvent *> events_to_start;
419
420 // Update all launch event timers and start all events whose timers have finished
421 for(std::vector<std::pair<int32_t, MapEvent *> >::iterator it = _active_delayed_events.begin();
422 it != _active_delayed_events.end();) {
423 it->first -= vt_system::SystemManager->GetUpdateTime();
424
425 if(it->first <= 0) { // Timer has expired
426 MapEvent *start_event = it->second;
427 it = _active_delayed_events.erase(it);
428
429 // We add the event ready to start i a vector, waiting for the loop to end
430 // before starting it.
431 events_to_start.push_back(start_event);
432 } else {
433 ++it;
434 }
435 }
436
437 // Starts the events that became active.
438 for(std::vector<MapEvent *>::iterator it = events_to_start.begin(); it != events_to_start.end(); ++it)
439 StartEvent(*it);
440
441 // Store the events that ended within the update loop.
442 std::vector<MapEvent *> finished_events;
443
444 // Make the engine aware that the event supervisor is entering the event update loop
445 _is_updating = true;
446
447 // Check for active events which have finished
448 for(std::vector<MapEvent *>::iterator it = _active_events.begin(); it != _active_events.end();) {
449 if((*it)->_Update()) {
450 // Add it ot the finished events list
451 finished_events.push_back(*it);
452
453 // Remove the finished event from the active queue.
454 it = _active_events.erase(it);
455 } else {
456 ++it;
457 }
458 }
459
460 _is_updating = false;
461
462 // We examine the event links only after the events has been removed from the active list
463 // and the active list has finished parsing, to avoid a crash when adding a new event within the update loop.
464 for(std::vector<MapEvent *>::iterator it = finished_events.begin(); it != finished_events.end(); ++it) {
465 _ExamineEventLinks(*it, false);
466 }
467 }
468
IsEventActive(const std::string & event_id) const469 bool EventSupervisor::IsEventActive(const std::string &event_id) const
470 {
471 for(std::vector<MapEvent *>::const_iterator it = _active_events.begin(); it != _active_events.end(); ++it) {
472 if((*it)->_event_id == event_id) {
473 return true;
474 }
475 }
476 return false;
477 }
478
GetEvent(const std::string & event_id) const479 MapEvent *EventSupervisor::GetEvent(const std::string &event_id) const
480 {
481 std::map<std::string, MapEvent *>::const_iterator it = _all_events.find(event_id);
482
483 if(it == _all_events.end())
484 return nullptr;
485 else
486 return it->second;
487 }
488
_RegisterEvent(MapEvent * new_event)489 bool EventSupervisor::_RegisterEvent(MapEvent* new_event)
490 {
491 if(new_event == nullptr) {
492 IF_PRINT_WARNING(MAP_DEBUG) << "function argument was nullptr" << std::endl;
493 return false;
494 }
495
496 if(GetEvent(new_event->_event_id) != nullptr) {
497 PRINT_WARNING << "The event with this ID already existed: '"
498 << new_event->_event_id
499 << "' in map script: "
500 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
501 return false;
502 }
503
504 _all_events.insert(std::make_pair(new_event->_event_id, new_event));
505 return true;
506 }
507
_ExamineEventLinks(MapEvent * parent_event,bool event_start)508 void EventSupervisor::_ExamineEventLinks(MapEvent *parent_event, bool event_start)
509 {
510 for(uint32_t i = 0; i < parent_event->_event_links.size(); ++i) {
511 EventLink &link = parent_event->_event_links[i];
512
513 // Case 1: Start/finish launch member is not equal to the start/finish status of the parent event, so ignore this link
514 if(link.launch_at_start != event_start) {
515 continue;
516 }
517 // Case 2: The child event is to be launched immediately
518 else if(link.launch_timer == 0) {
519 StartEvent(link.child_event_id);
520 }
521 // Case 3: The child event has a timer associated with it and needs to be placed in the event launch container
522 else {
523 MapEvent *child = GetEvent(link.child_event_id);
524 if(child == nullptr) {
525 PRINT_WARNING << "Couldn't launch child event, no event with this ID existed: '"
526 << link.child_event_id << "' from parent event ID: '"
527 << parent_event->GetEventID()
528 << "' in map script: "
529 << MapMode::CurrentInstance()->GetMapScriptFilename() << std::endl;
530 continue;
531 } else {
532 _active_delayed_events.push_back(std::make_pair(static_cast<int32_t>(link.launch_timer), child));
533 }
534 }
535 }
536 }
537
538 } // namespace private_map
539
540 } // namespace vt_map
541