1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #include "System/EventHandler.h"
4 #include "System/EventBatchHandler.h"
5 
6 #include "Lua/LuaCallInCheck.h"
7 #include "Lua/LuaOpenGL.h"  // FIXME -- should be moved
8 
9 #include "System/Config/ConfigHandler.h"
10 #include "System/Platform/Threading.h"
11 #include "System/GlobalConfig.h"
12 
13 using std::string;
14 using std::vector;
15 using std::map;
16 
17 
18 CEventHandler eventHandler;
19 
20 
21 /******************************************************************************/
22 /******************************************************************************/
23 
SetupEvent(const string & eName,EventClientList * list,int props)24 void CEventHandler::SetupEvent(const string& eName,
25                                EventClientList* list, int props)
26 {
27 	eventMap[eName] = EventInfo(eName, list, props);
28 }
29 
30 /******************************************************************************/
31 /******************************************************************************/
32 
CEventHandler()33 CEventHandler::CEventHandler()
34 {
35 	mouseOwner = NULL;
36 
37 	// Setup all events
38 	#define SETUP_EVENT(name, props) SetupEvent(#name, &list ## name, props);
39 	#define SETUP_UNMANAGED_EVENT(name, props) SetupEvent(#name, NULL, props);
40 		#include "Events.def"
41 	#undef SETUP_EVENT
42 	#undef SETUP_UNMANAGED_EVENT
43 
44 	// helper event client (alwayss create)
45 	EventBatchHandler::CreateInstance();
46 }
47 
48 
~CEventHandler()49 CEventHandler::~CEventHandler()
50 {
51 	EventBatchHandler::DeleteInstance();
52 }
53 
54 
55 /******************************************************************************/
56 /******************************************************************************/
57 
AddClient(CEventClient * ec)58 void CEventHandler::AddClient(CEventClient* ec)
59 {
60 	ListInsert(handles, ec);
61 
62 	EventMap::const_iterator it;
63 	for (it = eventMap.begin(); it != eventMap.end(); ++it) {
64 		const EventInfo& ei = it->second;
65 		if (ei.HasPropBit(MANAGED_BIT)) {
66 			if (ec->WantsEvent(it->first)) {
67 				InsertEvent(ec, it->first);
68 			}
69 		}
70 	}
71 }
72 
73 
RemoveClient(CEventClient * ec)74 void CEventHandler::RemoveClient(CEventClient* ec)
75 {
76 	if (mouseOwner == ec) {
77 		mouseOwner = NULL;
78 	}
79 
80 	ListRemove(handles, ec);
81 
82 	EventMap::const_iterator it;
83 	for (it = eventMap.begin(); it != eventMap.end(); ++it) {
84 		const EventInfo& ei = it->second;
85 		if (ei.HasPropBit(MANAGED_BIT)) {
86 			RemoveEvent(ec, it->first);
87 		}
88 	}
89 }
90 
91 
92 /******************************************************************************/
93 /******************************************************************************/
94 
GetEventList(vector<string> & list) const95 void CEventHandler::GetEventList(vector<string>& list) const
96 {
97 	list.clear();
98 	EventMap::const_iterator it;
99 	for (it = eventMap.begin(); it != eventMap.end(); ++it) {
100 		list.push_back(it->first);
101 	}
102 }
103 
104 
IsKnown(const string & eName) const105 bool CEventHandler::IsKnown(const string& eName) const
106 {
107 	return (eventMap.find(eName) != eventMap.end());
108 }
109 
110 
IsManaged(const string & eName) const111 bool CEventHandler::IsManaged(const string& eName) const
112 {
113 	EventMap::const_iterator it = eventMap.find(eName);
114 	return ((it != eventMap.end()) && (it->second.HasPropBit(MANAGED_BIT)));
115 }
116 
117 
IsUnsynced(const string & eName) const118 bool CEventHandler::IsUnsynced(const string& eName) const
119 {
120 	EventMap::const_iterator it = eventMap.find(eName);
121 	return ((it != eventMap.end()) && (it->second.HasPropBit(UNSYNCED_BIT)));
122 }
123 
124 
IsController(const string & eName) const125 bool CEventHandler::IsController(const string& eName) const
126 {
127 	EventMap::const_iterator it = eventMap.find(eName);
128 	return ((it != eventMap.end()) && (it->second.HasPropBit(CONTROL_BIT)));
129 }
130 
131 
132 /******************************************************************************/
133 
InsertEvent(CEventClient * ec,const string & ciName)134 bool CEventHandler::InsertEvent(CEventClient* ec, const string& ciName)
135 {
136 	EventMap::iterator it = eventMap.find(ciName);
137 	if ((it == eventMap.end()) || (it->second.GetList() == NULL)) {
138 		return false;
139 	}
140 	if (ec->GetSynced() && it->second.HasPropBit(UNSYNCED_BIT)) {
141 		return false;
142 	}
143 	ListInsert(*it->second.GetList(), ec);
144 	return true;
145 }
146 
147 
RemoveEvent(CEventClient * ec,const string & ciName)148 bool CEventHandler::RemoveEvent(CEventClient* ec, const string& ciName)
149 {
150 	EventMap::iterator it = eventMap.find(ciName);
151 	if ((it == eventMap.end()) || (it->second.GetList() == NULL)) {
152 		return false;
153 	}
154 	ListRemove(*it->second.GetList(), ec);
155 	return true;
156 }
157 
158 
159 /******************************************************************************/
160 
ListInsert(EventClientList & ecList,CEventClient * ec)161 void CEventHandler::ListInsert(EventClientList& ecList, CEventClient* ec)
162 {
163 	EventClientList::iterator it;
164 	for (it = ecList.begin(); it != ecList.end(); ++it) {
165 		const CEventClient* ecIt = *it;
166 		if (ec == ecIt) {
167 			return; // already in the list
168 		}
169 		else if ((ec->GetOrder()  <  ecIt->GetOrder()) ||
170 		         ((ec->GetOrder() == ecIt->GetOrder()) &&
171 		          (ec->GetName()  <  ecIt->GetName()))) { // should not happen
172 			ecList.insert(it, ec);
173 			return;
174 		}
175 	}
176 	ecList.push_back(ec);
177 }
178 
179 
ListRemove(EventClientList & ecList,CEventClient * ec)180 void CEventHandler::ListRemove(EventClientList& ecList, CEventClient* ec)
181 {
182 	// FIXME: efficient, hardly
183 	EventClientList newList;
184 	newList.reserve(ecList.size());
185 	for (size_t i = 0; i < ecList.size(); i++) {
186 		if (ec != ecList[i]) {
187 			newList.push_back(ecList[i]);
188 		}
189 	}
190 	ecList.swap(newList);
191 }
192 
193 
194 /******************************************************************************/
195 /******************************************************************************/
196 
197 #define CONTROL_ITERATE_DEF_TRUE(name, ...) \
198 	bool result = true;                        \
199 	for (int i = 0; i < list##name.size(); ) { \
200 		CEventClient* ec = list##name[i];  \
201 		result &= ec->name(__VA_ARGS__);   \
202 		if (i < list##name.size() && ec == list##name[i]) \
203 			++i; /* the call-in may remove itself from the list */ \
204 	} \
205 	return result;
206 
207 #define CONTROL_ITERATE_DEF_FALSE(name, ...) \
208 	bool result = false;                        \
209 	for (int i = 0; i < list##name.size(); ) { \
210 		CEventClient* ec = list##name[i];  \
211 		result |= ec->name(__VA_ARGS__);   \
212 		if (i < list##name.size() && ec == list##name[i]) \
213 			++i; /* the call-in may remove itself from the list */ \
214 	} \
215 	return result;
216 
217 
CommandFallback(const CUnit * unit,const Command & cmd)218 bool CEventHandler::CommandFallback(const CUnit* unit, const Command& cmd)
219 {
220 	CONTROL_ITERATE_DEF_TRUE(CommandFallback, unit, cmd)
221 }
222 
223 
AllowCommand(const CUnit * unit,const Command & cmd,bool fromSynced)224 bool CEventHandler::AllowCommand(const CUnit* unit, const Command& cmd, bool fromSynced)
225 {
226 	CONTROL_ITERATE_DEF_TRUE(AllowCommand, unit, cmd, fromSynced)
227 }
228 
229 
AllowUnitCreation(const UnitDef * unitDef,const CUnit * builder,const BuildInfo * buildInfo)230 bool CEventHandler::AllowUnitCreation(const UnitDef* unitDef, const CUnit* builder, const BuildInfo* buildInfo)
231 {
232 	CONTROL_ITERATE_DEF_TRUE(AllowUnitCreation, unitDef, builder, buildInfo)
233 }
234 
235 
AllowUnitTransfer(const CUnit * unit,int newTeam,bool capture)236 bool CEventHandler::AllowUnitTransfer(const CUnit* unit, int newTeam, bool capture)
237 {
238 	CONTROL_ITERATE_DEF_TRUE(AllowUnitTransfer, unit, newTeam, capture)
239 }
240 
241 
AllowUnitBuildStep(const CUnit * builder,const CUnit * unit,float part)242 bool CEventHandler::AllowUnitBuildStep(const CUnit* builder, const CUnit* unit, float part)
243 {
244 	CONTROL_ITERATE_DEF_TRUE(AllowUnitBuildStep, builder, unit, part)
245 }
246 
247 
AllowFeatureCreation(const FeatureDef * featureDef,int allyTeamID,const float3 & pos)248 bool CEventHandler::AllowFeatureCreation(const FeatureDef* featureDef, int allyTeamID, const float3& pos)
249 {
250 	CONTROL_ITERATE_DEF_TRUE(AllowFeatureCreation, featureDef, allyTeamID, pos)
251 }
252 
253 
AllowFeatureBuildStep(const CUnit * builder,const CFeature * feature,float part)254 bool CEventHandler::AllowFeatureBuildStep(const CUnit* builder, const CFeature* feature, float part)
255 {
256 	CONTROL_ITERATE_DEF_TRUE(AllowFeatureBuildStep, builder, feature, part)
257 }
258 
259 
AllowResourceLevel(int teamID,const string & type,float level)260 bool CEventHandler::AllowResourceLevel(int teamID, const string& type, float level)
261 {
262 	CONTROL_ITERATE_DEF_TRUE(AllowResourceLevel, teamID, type, level)
263 }
264 
265 
AllowResourceTransfer(int oldTeam,int newTeam,const string & type,float amount)266 bool CEventHandler::AllowResourceTransfer(int oldTeam, int newTeam, const string& type, float amount)
267 {
268 	CONTROL_ITERATE_DEF_TRUE(AllowResourceTransfer, oldTeam, newTeam, type, amount)
269 }
270 
271 
AllowDirectUnitControl(int playerID,const CUnit * unit)272 bool CEventHandler::AllowDirectUnitControl(int playerID, const CUnit* unit)
273 {
274 	CONTROL_ITERATE_DEF_TRUE(AllowDirectUnitControl, playerID, unit)
275 }
276 
277 
AllowBuilderHoldFire(const CUnit * unit,int action)278 bool CEventHandler::AllowBuilderHoldFire(const CUnit* unit, int action)
279 {
280 	CONTROL_ITERATE_DEF_TRUE(AllowBuilderHoldFire, unit, action)
281 }
282 
283 
AllowStartPosition(int playerID,unsigned char readyState,const float3 & clampedPos,const float3 & rawPickPos)284 bool CEventHandler::AllowStartPosition(int playerID, unsigned char readyState, const float3& clampedPos, const float3& rawPickPos)
285 {
286 	CONTROL_ITERATE_DEF_TRUE(AllowStartPosition, playerID, readyState, clampedPos, rawPickPos)
287 }
288 
289 
290 
TerraformComplete(const CUnit * unit,const CUnit * build)291 bool CEventHandler::TerraformComplete(const CUnit* unit, const CUnit* build)
292 {
293 	CONTROL_ITERATE_DEF_FALSE(TerraformComplete, unit, build)
294 }
295 
296 
MoveCtrlNotify(const CUnit * unit,int data)297 bool CEventHandler::MoveCtrlNotify(const CUnit* unit, int data)
298 {
299 	CONTROL_ITERATE_DEF_FALSE(MoveCtrlNotify, unit, data)
300 }
301 
302 
AllowWeaponTargetCheck(unsigned int attackerID,unsigned int attackerWeaponNum,unsigned int attackerWeaponDefID)303 int CEventHandler::AllowWeaponTargetCheck(unsigned int attackerID, unsigned int attackerWeaponNum, unsigned int attackerWeaponDefID)
304 {
305 	int result = -1;
306 	for (int i = 0; i < listAllowWeaponTargetCheck.size(); ) {
307 		CEventClient* ec = listAllowWeaponTargetCheck[i];
308 		int result2 = ec->AllowWeaponTargetCheck(attackerID, attackerWeaponNum, attackerWeaponDefID);
309 		if (result2 > result) result = result2;
310 		if (i < listAllowWeaponTargetCheck.size() && ec == listAllowWeaponTargetCheck[i])
311 			++i; /* the call-in may remove itself from the list */
312 	}
313 	return result;
314 }
315 
316 
AllowWeaponTarget(unsigned int attackerID,unsigned int targetID,unsigned int attackerWeaponNum,unsigned int attackerWeaponDefID,float * targetPriority)317 bool CEventHandler::AllowWeaponTarget(
318 	unsigned int attackerID,
319 	unsigned int targetID,
320 	unsigned int attackerWeaponNum,
321 	unsigned int attackerWeaponDefID,
322 	float* targetPriority
323 ) {
324 	CONTROL_ITERATE_DEF_TRUE(AllowWeaponTarget, attackerID, targetID, attackerWeaponNum, attackerWeaponDefID, targetPriority)
325 }
326 
327 
AllowWeaponInterceptTarget(const CUnit * interceptorUnit,const CWeapon * interceptorWeapon,const CProjectile * interceptorTarget)328 bool CEventHandler::AllowWeaponInterceptTarget(const CUnit* interceptorUnit, const CWeapon* interceptorWeapon, const CProjectile* interceptorTarget)
329 {
330 	CONTROL_ITERATE_DEF_TRUE(AllowWeaponInterceptTarget, interceptorUnit, interceptorWeapon, interceptorTarget)
331 }
332 
333 
UnitPreDamaged(const CUnit * unit,const CUnit * attacker,float damage,int weaponDefID,int projectileID,bool paralyzer,float * newDamage,float * impulseMult)334 bool CEventHandler::UnitPreDamaged(
335 	const CUnit* unit,
336 	const CUnit* attacker,
337 	float damage,
338 	int weaponDefID,
339 	int projectileID,
340 	bool paralyzer,
341 	float* newDamage,
342 	float* impulseMult
343 ) {
344 	CONTROL_ITERATE_DEF_FALSE(UnitPreDamaged, unit, attacker, damage, weaponDefID, projectileID, paralyzer, newDamage, impulseMult)
345 }
346 
347 
FeaturePreDamaged(const CFeature * feature,const CUnit * attacker,float damage,int weaponDefID,int projectileID,float * newDamage,float * impulseMult)348 bool CEventHandler::FeaturePreDamaged(
349 	const CFeature* feature,
350 	const CUnit* attacker,
351 	float damage,
352 	int weaponDefID,
353 	int projectileID,
354 	float* newDamage,
355 	float* impulseMult
356 ) {
357 	CONTROL_ITERATE_DEF_FALSE(FeaturePreDamaged, feature, attacker, damage, weaponDefID, projectileID, newDamage, impulseMult)
358 }
359 
360 
ShieldPreDamaged(const CProjectile * proj,const CWeapon * w,const CUnit * u,bool repulsor)361 bool CEventHandler::ShieldPreDamaged(const CProjectile* proj, const CWeapon* w, const CUnit* u, bool repulsor)
362 {
363 	CONTROL_ITERATE_DEF_FALSE(ShieldPreDamaged, proj, w, u, repulsor)
364 }
365 
366 
SyncedActionFallback(const string & line,int playerID)367 bool CEventHandler::SyncedActionFallback(const string& line, int playerID)
368 {
369 	for (int i = 0; i < listSyncedActionFallback.size(); ) {
370 		CEventClient* ec = listSyncedActionFallback[i];
371 		if (ec->SyncedActionFallback(line, playerID))
372 			return true;
373 		if (i < listSyncedActionFallback.size() && ec == listSyncedActionFallback[i])
374 			++i; /* the call-in may remove itself from the list */
375 	}
376 	return false;
377 }
378 
379 
380 /******************************************************************************/
381 /******************************************************************************/
382 
383 #define ITERATE_EVENTCLIENTLIST(name, ...) \
384 	for (int i = 0; i < list##name.size(); ) { \
385 		CEventClient* ec = list##name[i]; \
386 		ec->name(__VA_ARGS__); \
387 		if (i < list##name.size() && ec == list##name[i]) \
388 			++i; /* the call-in may remove itself from the list */ \
389 	}
390 
391 
Save(zipFile archive)392 void CEventHandler::Save(zipFile archive)
393 {
394 	ITERATE_EVENTCLIENTLIST(Save, archive);
395 }
396 
397 
GamePreload()398 void CEventHandler::GamePreload()
399 {
400 	ITERATE_EVENTCLIENTLIST(GamePreload);
401 }
402 
403 
GameStart()404 void CEventHandler::GameStart()
405 {
406 	ITERATE_EVENTCLIENTLIST(GameStart);
407 }
408 
409 
GameOver(const std::vector<unsigned char> & winningAllyTeams)410 void CEventHandler::GameOver(const std::vector<unsigned char>& winningAllyTeams)
411 {
412 	ITERATE_EVENTCLIENTLIST(GameOver, winningAllyTeams);
413 }
414 
415 
GamePaused(int playerID,bool paused)416 void CEventHandler::GamePaused(int playerID, bool paused)
417 {
418 	ITERATE_EVENTCLIENTLIST(GamePaused, playerID, paused);
419 }
420 
421 
GameFrame(int gameFrame)422 void CEventHandler::GameFrame(int gameFrame)
423 {
424 	ITERATE_EVENTCLIENTLIST(GameFrame, gameFrame);
425 }
426 
427 
GameID(const unsigned char * gameID,unsigned int numBytes)428 void CEventHandler::GameID(const unsigned char* gameID, unsigned int numBytes)
429 {
430 	ITERATE_EVENTCLIENTLIST(GameID, gameID, numBytes);
431 }
432 
433 
TeamDied(int teamID)434 void CEventHandler::TeamDied(int teamID)
435 {
436 	ITERATE_EVENTCLIENTLIST(TeamDied, teamID);
437 }
438 
439 
TeamChanged(int teamID)440 void CEventHandler::TeamChanged(int teamID)
441 {
442 	ITERATE_EVENTCLIENTLIST(TeamChanged, teamID);
443 }
444 
445 
PlayerChanged(int playerID)446 void CEventHandler::PlayerChanged(int playerID)
447 {
448 	ITERATE_EVENTCLIENTLIST(PlayerChanged, playerID);
449 }
450 
451 
PlayerAdded(int playerID)452 void CEventHandler::PlayerAdded(int playerID)
453 {
454 	ITERATE_EVENTCLIENTLIST(PlayerAdded, playerID);
455 }
456 
457 
PlayerRemoved(int playerID,int reason)458 void CEventHandler::PlayerRemoved(int playerID, int reason)
459 {
460 	ITERATE_EVENTCLIENTLIST(PlayerRemoved, playerID, reason);
461 }
462 
463 
464 /******************************************************************************/
465 /******************************************************************************/
466 
UnitHarvestStorageFull(const CUnit * unit)467 void CEventHandler::UnitHarvestStorageFull(const CUnit* unit)
468 {
469 	const int unitAllyTeam = unit->allyteam;
470 	const int count = listUnitHarvestStorageFull.size();
471 	for (int i = 0; i < count; i++) {
472 		CEventClient* ec = listUnitHarvestStorageFull[i];
473 		if (ec->CanReadAllyTeam(unitAllyTeam)) {
474 			ec->UnitHarvestStorageFull(unit);
475 		}
476 	}
477 }
478 
479 /******************************************************************************/
480 /******************************************************************************/
481 
CollectGarbage()482 void CEventHandler::CollectGarbage()
483 {
484 	ITERATE_EVENTCLIENTLIST(CollectGarbage);
485 }
486 
487 
DbgTimingInfo(DbgTimingInfoType type,const spring_time start,const spring_time end)488 void CEventHandler::DbgTimingInfo(DbgTimingInfoType type, const spring_time start, const spring_time end)
489 {
490 	ITERATE_EVENTCLIENTLIST(DbgTimingInfo, type, start, end);
491 }
492 
493 
Load(IArchive * archive)494 void CEventHandler::Load(IArchive* archive)
495 {
496 	ITERATE_EVENTCLIENTLIST(Load, archive);
497 }
498 
499 
Update()500 void CEventHandler::Update()
501 {
502 	ITERATE_EVENTCLIENTLIST(Update);
503 }
504 
505 
506 
UpdateUnits()507 void CEventHandler::UpdateUnits() { eventBatchHandler->UpdateUnits(); }
UpdateDrawUnits()508 void CEventHandler::UpdateDrawUnits() { eventBatchHandler->UpdateDrawUnits(); }
DeleteSyncedUnits()509 void CEventHandler::DeleteSyncedUnits() { eventBatchHandler->DeleteSyncedUnits(); }
510 
UpdateFeatures()511 void CEventHandler::UpdateFeatures() { eventBatchHandler->UpdateFeatures(); }
UpdateDrawFeatures()512 void CEventHandler::UpdateDrawFeatures() { eventBatchHandler->UpdateDrawFeatures(); }
DeleteSyncedFeatures()513 void CEventHandler::DeleteSyncedFeatures() { eventBatchHandler->DeleteSyncedFeatures(); }
514 
UpdateProjectiles()515 void CEventHandler::UpdateProjectiles() { eventBatchHandler->UpdateProjectiles(); }
UpdateDrawProjectiles()516 void CEventHandler::UpdateDrawProjectiles() { eventBatchHandler->UpdateDrawProjectiles(); }
517 
ExecuteAllCallsFromSynced()518 inline void ExecuteAllCallsFromSynced() { } //FIXME delete
519 
DeleteSyncedProjectiles()520 void CEventHandler::DeleteSyncedProjectiles() {
521 	ExecuteAllCallsFromSynced();
522 	eventBatchHandler->DeleteSyncedProjectiles();
523 }
524 
UpdateObjects()525 void CEventHandler::UpdateObjects() {
526 	eventBatchHandler->UpdateObjects();
527 }
DeleteSyncedObjects()528 void CEventHandler::DeleteSyncedObjects() {
529 	ExecuteAllCallsFromSynced();
530 }
531 
532 
533 
SunChanged(const float3 & sunDir)534 void CEventHandler::SunChanged(const float3& sunDir)
535 {
536 	ITERATE_EVENTCLIENTLIST(SunChanged, sunDir);
537 }
538 
ViewResize()539 void CEventHandler::ViewResize()
540 {
541 	ITERATE_EVENTCLIENTLIST(ViewResize);
542 }
543 
544 
GameProgress(int gameFrame)545 void CEventHandler::GameProgress(int gameFrame)
546 {
547 	ITERATE_EVENTCLIENTLIST(GameProgress, gameFrame);
548 }
549 
550 
551 #define DRAW_CALLIN(name)                         \
552   void CEventHandler:: Draw ## name ()            \
553   {                                               \
554     if (listDraw ## name.empty())                 \
555       return;                                     \
556     LuaOpenGL::EnableDraw ## name ();             \
557     listDraw ## name [0]->Draw ## name ();        \
558                                                   \
559     for (int i = 1; i < listDraw ## name.size(); ) { \
560       LuaOpenGL::ResetDraw ## name ();            \
561       CEventClient* ec = listDraw ## name [i];    \
562       ec-> Draw ## name ();                       \
563       if (i < listDraw ## name.size() && ec == listDraw ## name [i]) \
564 	    ++i;                                      \
565     }                                             \
566                                                   \
567     LuaOpenGL::DisableDraw ## name ();            \
568   }
569 
570 DRAW_CALLIN(Genesis)
DRAW_CALLIN(World)571 DRAW_CALLIN(World)
572 DRAW_CALLIN(WorldPreUnit)
573 DRAW_CALLIN(WorldShadow)
574 DRAW_CALLIN(WorldReflection)
575 DRAW_CALLIN(WorldRefraction)
576 DRAW_CALLIN(ScreenEffects)
577 DRAW_CALLIN(Screen)
578 DRAW_CALLIN(InMiniMap)
579 DRAW_CALLIN(InMiniMapBackground)
580 
581 
582 #define DRAW_ENTITY_CALLIN(name, args, args2)     \
583   bool CEventHandler:: Draw ## name args        \
584   {                                               \
585     bool skipEngineDrawing = false;               \
586     for (int i = 0; i < listDraw ## name.size(); ) { \
587       CEventClient* ec = listDraw ## name [i];    \
588       skipEngineDrawing |= ec-> Draw ## name args2 ; \
589       if (i < listDraw ## name.size() && ec == listDraw ## name [i]) \
590 	    ++i;                                      \
591     } \
592     return skipEngineDrawing; \
593   }
594 
595 DRAW_ENTITY_CALLIN(Unit, (const CUnit* unit), (unit))
596 DRAW_ENTITY_CALLIN(Feature, (const CFeature* feature), (feature))
597 DRAW_ENTITY_CALLIN(Shield, (const CUnit* unit, const CWeapon* weapon), (unit, weapon))
598 DRAW_ENTITY_CALLIN(Projectile, (const CProjectile* projectile), (projectile))
599 
600 /******************************************************************************/
601 /******************************************************************************/
602 
603 #define CONTROL_REVERSE_ITERATE_DEF_TRUE(name, ...) \
604 	for (int i = list##name.size() - 1; i >= 0; --i) { \
605 		CEventClient* ec = list##name[i]; \
606 		if (ec->name(__VA_ARGS__)) \
607 			return true; \
608 	}
609 
610 #define CONTROL_REVERSE_ITERATE_STRING(name, ...) \
611 	for (int i = list##name.size() - 1; i >= 0; --i) { \
612 		CEventClient* ec = list##name[i]; \
613 		const std::string& str = ec->name(__VA_ARGS__); \
614 		if (!str.empty()) \
615 			return str; \
616 	}
617 
618 bool CEventHandler::CommandNotify(const Command& cmd)
619 {
620 	CONTROL_REVERSE_ITERATE_DEF_TRUE(CommandNotify, cmd)
621 	return false;
622 }
623 
624 
KeyPress(int key,bool isRepeat)625 bool CEventHandler::KeyPress(int key, bool isRepeat)
626 {
627 	CONTROL_REVERSE_ITERATE_DEF_TRUE(KeyPress, key, isRepeat)
628 	return false;
629 }
630 
631 
KeyRelease(int key)632 bool CEventHandler::KeyRelease(int key)
633 {
634 	CONTROL_REVERSE_ITERATE_DEF_TRUE(KeyRelease, key)
635 	return false;
636 }
637 
638 
TextInput(const std::string & utf8)639 bool CEventHandler::TextInput(const std::string& utf8)
640 {
641 	CONTROL_REVERSE_ITERATE_DEF_TRUE(TextInput, utf8)
642 	return false;
643 }
644 
645 
MousePress(int x,int y,int button)646 bool CEventHandler::MousePress(int x, int y, int button)
647 {
648 	for (int i = listMousePress.size() - 1; i >= 0; --i) {
649 		CEventClient* ec = listMousePress[i];
650 		if (ec->MousePress(x,y,button)) {
651 			if (!mouseOwner)
652 				mouseOwner = ec;
653 			return true;
654 		}
655 	}
656 	return false;
657 }
658 
659 
MouseRelease(int x,int y,int button)660 void CEventHandler::MouseRelease(int x, int y, int button)
661 {
662 	if (mouseOwner) {
663 		mouseOwner->MouseRelease(x, y, button);
664 		mouseOwner = NULL;
665 	}
666 }
667 
668 
MouseMove(int x,int y,int dx,int dy,int button)669 bool CEventHandler::MouseMove(int x, int y, int dx, int dy, int button)
670 {
671 	if (mouseOwner == NULL) {
672 		return false;
673 	}
674 
675 	return mouseOwner->MouseMove(x, y, dx, dy, button);
676 }
677 
678 
MouseWheel(bool up,float value)679 bool CEventHandler::MouseWheel(bool up, float value)
680 {
681 	CONTROL_REVERSE_ITERATE_DEF_TRUE(MouseWheel, up, value)
682 	return false;
683 }
684 
JoystickEvent(const std::string & event,int val1,int val2)685 bool CEventHandler::JoystickEvent(const std::string& event, int val1, int val2)
686 {
687 	CONTROL_REVERSE_ITERATE_DEF_TRUE(JoystickEvent, event, val1, val2)
688 	return false;
689 }
690 
IsAbove(int x,int y)691 bool CEventHandler::IsAbove(int x, int y)
692 {
693 	CONTROL_REVERSE_ITERATE_DEF_TRUE(IsAbove, x, y)
694 	return false;
695 }
696 
GetTooltip(int x,int y)697 string CEventHandler::GetTooltip(int x, int y)
698 {
699 	CONTROL_REVERSE_ITERATE_STRING(GetTooltip, x, y)
700 	return "";
701 }
702 
703 
AddConsoleLine(const std::string & msg,const std::string & section,int level)704 bool CEventHandler::AddConsoleLine(const std::string& msg, const std::string& section, int level)
705 {
706 	if (listAddConsoleLine.empty())
707 		return false;
708 
709 	ITERATE_EVENTCLIENTLIST(AddConsoleLine, msg, section, level);
710 	return true;
711 }
712 
713 
LastMessagePosition(const float3 & pos)714 void CEventHandler::LastMessagePosition(const float3& pos)
715 {
716 	ITERATE_EVENTCLIENTLIST(LastMessagePosition, pos);
717 }
718 
719 
GroupChanged(int groupID)720 bool CEventHandler::GroupChanged(int groupID)
721 {
722 	ITERATE_EVENTCLIENTLIST(GroupChanged, groupID);
723 	return false;
724 }
725 
726 
727 
GameSetup(const string & state,bool & ready,const map<int,string> & playerStates)728 bool CEventHandler::GameSetup(const string& state, bool& ready,
729                                   const map<int, string>& playerStates)
730 {
731 	CONTROL_REVERSE_ITERATE_DEF_TRUE(GameSetup, state, ready, playerStates)
732 	return false;
733 }
734 
735 
WorldTooltip(const CUnit * unit,const CFeature * feature,const float3 * groundPos)736 string CEventHandler::WorldTooltip(const CUnit* unit,
737                                    const CFeature* feature,
738                                    const float3* groundPos)
739 {
740 	CONTROL_REVERSE_ITERATE_STRING(WorldTooltip, unit, feature, groundPos)
741 	return "";
742 }
743 
744 
MapDrawCmd(int playerID,int type,const float3 * pos0,const float3 * pos1,const string * label)745 bool CEventHandler::MapDrawCmd(int playerID, int type,
746                                const float3* pos0, const float3* pos1,
747                                    const string* label)
748 {
749 	CONTROL_REVERSE_ITERATE_DEF_TRUE(MapDrawCmd, playerID, type, pos0, pos1, label)
750 	return false;
751 }
752 
753 
754 /******************************************************************************/
755 /******************************************************************************/
756 
UnsyncedProjectileCreated(const CProjectile * proj)757 void CEventHandler::UnsyncedProjectileCreated(const CProjectile* proj) {
758 	//FIXME no real event
759 	(eventBatchHandler->GetUnsyncedProjectileCreatedDestroyedBatch()).insert(proj);
760 }
761 
UnsyncedProjectileDestroyed(const CProjectile * proj)762 void CEventHandler::UnsyncedProjectileDestroyed(const CProjectile* proj) {
763 	//FIXME no real event
764 	(eventBatchHandler->GetUnsyncedProjectileCreatedDestroyedBatch()).erase_delete(proj);
765 }
766 
LoadedModelRequested()767 void CEventHandler::LoadedModelRequested() {
768 	//FIXME no real event
769 	eventBatchHandler->LoadedModelRequested();
770 }
771 
772 
773 /******************************************************************************/
774 /******************************************************************************/
775 
776