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