View Javadoc

1   package cz.cuni.amis.pogamut.udk.agent.module.sensor;
2   
3   import java.util.List;
4   import java.util.logging.Logger;
5   
6   import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
7   import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
8   import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
9   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
10  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
11  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectFirstEncounteredEvent;
12  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
13  import cz.cuni.amis.pogamut.udk.bot.IUDKBotController;
14  import cz.cuni.amis.pogamut.udk.bot.impl.UDKBot;
15  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.BeginMessage;
16  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.FlagInfo;
17  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.GameInfo;
18  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.InitedMessage;
19  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.Mutator;
20  import cz.cuni.amis.pogamut.udk.communication.translator.shared.events.MutatorListObtained;
21  
22  import java.util.Collection;
23  import java.util.HashMap;
24  import java.util.Map;
25  import java.util.logging.Level;
26  
27  /**
28   * Memory module specialized on general info about the game.
29   * <p><p>
30   * It is designed to be initialized inside {@link IUDKBotController#prepareBot(UDKBot)} method call
31   * and may be used since {@link IUDKBotController#botInitialized(cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.GameInfo, cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.ConfigChange, cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.InitedMessage)}
32   * is called.
33   *
34   * @author Juraj 'Loque' Simlovic
35   * @author Jimmy
36   */
37  public class Game extends SensorModule<UDKBot>
38  {
39  	/**
40  	 * Enums for game types that shields you from Unreal's string ids of game types.
41  	 * @author Jimmy
42  	 *
43  	 */
44  	public enum GameType
45  	{
46  		/** Classic death-match: Kill or get killed. You're on you own! */
47  		BotDeathMatch,
48  		/** Team death-match: Strategic team killing. Shoot opponents only. */
49  		BotTeamGame,
50  		/** Capture the Flag! Raid the enemy base, steal their flag. */
51  		BotCTFGame,
52  		/** Capture the Flag! Raid the enemy base, steal their flag, with vehicles */
53  		BotVehicleCTFGame,
54  		/** This type of game is not supported. */
55  		Unknown;
56  
57  		/**
58  		 * Tedious work this is.. Let's do it once, shall we?
59  		 *
60  		 * @param type Name of the type of the game type.
61  		 * @return Game type associated with given name.
62  		 */
63  		public static GameType getType(String type)
64  		{
65  			if (type.equalsIgnoreCase("BotDeathMatch"))       return BotDeathMatch;
66  			if (type.equalsIgnoreCase("BotTeamGame"))         return BotTeamGame;
67  			if (type.equalsIgnoreCase("BotCTFGame"))          return BotCTFGame;
68  			if (type.equalsIgnoreCase("BotVehicleCTFGame"))   return BotVehicleCTFGame;
69  			return Unknown;
70  		}
71  	}
72  
73  	/**
74  	 * Retreives the type of the game.
75  	 *
76  	 * @return Type of the game.
77  	 */
78  	public GameType getGameType()
79  	{
80  		// retreive from GameInfo object and translate
81                  if (lastGameInfo == null) return null;
82  		return GameType.getType(lastGameInfo.getGametype());
83  	}
84  
85  	/*========================================================================*/
86  
87  	/**
88  	 * Retreives the name of current map.
89  	 *
90  	 * @return Name of the current map.
91  	 */
92  	public String getMapName()
93  	{
94  		// retreive from GameInfo object
95                  if (lastGameInfo == null) return null;
96  		return lastGameInfo.getLevel();
97  	}
98  
99  	/*========================================================================*/
100 
101 	/**
102 	 * Retreives current game time, since the game started.
103 	 *
104 	 * @return Current game timestamp.
105 	 *
106 	 * @todo Test, whether it is correct..
107 	 */
108 	public double getTime()
109 	{
110 		// retreive from last BeginMessage object
111                 if (lastBeginMessage == null) return 0;
112 		return lastBeginMessage.getTime();
113 	}
114 
115 	/**
116 	 * Retreives time limit for the game.
117 	 *
118 	 * <p>Note: Then the time limit is reached and the game is tie, special
119 	 * game modes might be turned on, e.g. <i>sudden death overtime</i>.
120 	 * Depends on the game type and game settings.
121 	 *
122 	 * @return Time limit of the game.
123 	 *
124 	 * @see getRemainingTime()
125 	 */
126 	public Double getTimeLimit()
127 	{
128 		// retreive from GameInfo object
129                 if (lastGameInfo == null) return null;
130 		return lastGameInfo.getTimeLimit();
131 	}
132 
133 	/**
134 	 * Retreives time remaining for the game.
135 	 *
136 	 * <p>Note: Then the time limit is reached and the game is tie, special
137 	 * game modes might be turned on, e.g. <i>sudden death overtime</i>.
138 	 * Depends on the game type and game settings.
139 	 *
140 	 * @return Time limit of the game.
141 	 *
142 	 * @see getTime()
143 	 * @see getTimeLimit()
144 	 *
145 	 * @todo Test, whether it is correct..
146 	 */
147 	public Double getRemainingTime()
148 	{
149 		// derive from the time limit and current time
150                 if (getTimeLimit() == null) return null;
151 		return getTimeLimit() - getTime();
152 	}
153 
154  	/*========================================================================*/
155 
156 	/**
157 	 * <i>BotDeathMatch only:</i><p>
158 	 * Number of points (e.g. kills) needed to win the game.
159 	 *
160 	 * @return Frag limit of the game.
161 	 *
162 	 * @see getTeamScoreLimit()
163 	 */
164 	public Integer getFragLimit()
165 	{
166 		// retreive from GameInfo object
167                 if (lastGameInfo == null) return null;
168 		return lastGameInfo.getFragLimit();
169 	}
170 
171 	/**
172 	 * <i>BotTeamGame, BotCTFGame, BotBombingRun, BotDoubleDomination only:</i><p>
173 	 * Number of points a team needs to win the game.
174 	 *
175 	 * @return Team score limit of the game.
176 	 *
177 	 * @see getFragLimit()
178 	 */
179 	public Integer getTeamScoreLimit()
180 	{
181 		// retreive from GameInfo object
182 		// we have to cast double to int because UT2004 exports it as double (duuno why)
183                 if (lastGameInfo == null) return null;
184 		return (int)lastGameInfo.getGoalTeamScore();
185 	}
186 
187 	/*========================================================================*/
188 
189 	/**
190 	 * <i>BotTeamGame, BotCTFGame, BotDoubleDomination only:</i><p>
191 	 * Retrieves number of teams in the game.
192 	 *
193 	 * <p> Team numbers start from 0.  Usually, there are just two teams: 0 and 1.
194 	 *
195 	 * @return Number of teams in the game.
196 	 */
197 	public Integer getMaxTeams()
198 	{
199 		// retreive from GameInfo object
200                 if (lastGameInfo == null) return null;
201 		return lastGameInfo.getMaxTeams();
202 	}
203 
204 	/**
205 	 * <i>BotTeamGame, BotCTFGame, BotDoubleDomination only:</i><p>
206 	 * Retreives maximum number of players per team.
207 	 *
208 	 * @return Maximum number of players per team.
209 	 */
210 	public Integer getMaxTeamSize()
211 	{
212 		// retreive from GameInfo object
213                 if (lastGameInfo == null) return null;
214 		return lastGameInfo.getMaxTeamSize();
215 	}
216 
217 	/*========================================================================*/
218 
219 	/**
220 	 * Retreives starting level of health. This is the level of health the
221 	 * players spawn with into the game.
222 	 *
223 	 * @return Starting level of health.
224 	 *
225 	 * @see getMaxHealth()
226 	 * @see getFullHealth()
227 	 */
228 	public Integer getStartHealth()
229 	{
230 		// retreive from InitedMessage object
231                 if (lastInitedMessage == null) return null;
232 		return lastInitedMessage.getHealthStart();
233 	}
234 
235 	/**
236 	 * Retreives maximum level of <i>non-boosted</i> health. This is the level
237 	 * achievable by foraging standard health kits.
238 	 *
239 	 * @return Maximum level of <i>non-boosted</i> health.
240 	 *
241 	 * @see getStartHealth()
242 	 * @see getMaxHealth()
243 	 */
244 	public Integer getFullHealth()
245 	{
246 		// retreive from InitedMessage object
247                 if (lastInitedMessage == null) return null;
248 		return lastInitedMessage.getHealthFull();
249 	}
250 
251 	/**
252 	 * Retreives maximum level of <i>boosted</i> health. This is the total
253 	 * maximum health achievable by any means of health kits, super health,
254 	 * or health vials.
255 	 *
256 	 * @return Maximum level of <i>boosted</i> health.
257 	 *
258 	 * @see getStartHealth()
259 	 * @see getFullHealth()
260 	 */
261 	public Integer getMaxHealth()
262 	{
263 		// retreive from InitedMessage object
264                 if (lastInitedMessage == null) return null;
265 		return lastInitedMessage.getHealthMax();
266 	}
267 
268 	/*========================================================================*/
269 
270 	/**
271 	 * Retreives maximum level of combined armor. The armor consist of two
272 	 * parts, which are summed together into combined armor value. However,
273 	 * each part is powered-up by different item (either by <i>small shield</i>
274 	 * or by <i>super-shield</i>).
275 	 *
276 	 * @return Maximum level of combined armor.
277 	 *
278 	 * @see getMaxLowArmor()
279 	 * @see getMaxHighArmor()
280 	 */
281 	public Integer getMaxArmor()
282 	{
283 		// retreive from InitedMessage object
284                 if (lastInitedMessage == null) return null;
285 		return lastInitedMessage.getShieldStrengthMax();
286 	}
287 
288 	/**
289 	 * Retreives maximum level of low armor. The armor consist of two
290 	 * parts, which are summed together into combined armor value. However,
291 	 * each part is powered-up by different item (either by <i>small shield</i>
292 	 * or by <i>super-shield</i>).
293 	 *
294 	 * <p>Low armor is powered-up by <i>small shield</i>.
295 	 *
296 	 * @return Maximum level of low armor.
297 	 *
298 	 * @see getMaxArmor()
299 	 * @see getMaxHighArmor()
300 	 */
301 	public int getMaxLowArmor()
302 	{
303 		// FIXME[js]: Where do we retreive the max low-armor info?
304 		return 50;
305 	}
306 
307 	/**
308 	 * Retreives maximum level of high armor. The armor consist of two
309 	 * parts, which are summed together into combined armor value. However,
310 	 * each part is powered-up by different item (either by <i>small shield</i>
311 	 * or by <i>super-shield</i>).
312 	 *
313 	 * <p>High armor is powered-up by <i>super-shield</i>.
314 	 *
315 	 * @return Maximum level of high armor.
316 	 *
317 	 * @see getMaxArmor()
318 	 * @see getMaxLowArmor()
319 	 */
320 	public int getMaxHighArmor()
321 	{
322 		// FIXME[js]: Where do we retreive the max high-armor info?
323 		return 100;
324 	}
325 
326 	/*========================================================================*/
327 
328 	/**
329 	 * Retreives starting level of adrenaline. This is the level of adrenaline
330 	 * the players spawn with into the game.
331 	 *
332 	 * @return Starting level of adrenaline.
333 	 */
334 	public Integer getStartAdrenaline()
335 	{
336 		// retreive from InitedMessage object
337 		// ut2004 exports it as double, must cast to int, ut's weirdness
338                 if (lastInitedMessage == null) return null;
339 		return (int)lastInitedMessage.getAdrenalineStart();
340 	}
341 
342 	/**
343 	 * Retreives target level of adrenaline that need to be gained to start
344 	 * special bonus actions.
345 	 *
346 	 * <p>Once the agent's adrenaline reaches this designated level, it can be
347 	 * used to start special bonus booster-actions like <i>invisibility</i>,
348 	 * <i>speed</i>, <i>booster</i>, etc. The adrenaline is then spent on the
349 	 * invoked action.
350 	 *
351 	 * @return Maximum level of adrenaline that can be gained.
352 	 */
353 	public Integer getTargetAdrenaline()
354 	{
355 		// retreive from InitedMessage object
356 		// ut2004 exports it as double, must cast to int, ut's weirdness
357                 if (lastInitedMessage == null) return null;
358 		return (int)lastInitedMessage.getAdrenalineMax();
359 	}
360 
361 	/**
362 	 * Retreives maximum level of adrenaline that can be gained.
363 	 *
364 	 * @return Maximum level of adrenaline that can be gained.
365 	 */
366 	public Integer getMaxAdrenaline()
367 	{
368 		// retreive from InitedMessage object
369 		// FIXME[js]: Return type!
370                 if (lastInitedMessage == null) return null;
371 		return (int)lastInitedMessage.getAdrenalineMax();
372 	}
373 
374 	/*========================================================================*/
375 
376 	/**
377 	 * Tells, whether the weapons stay on pick-up points, even when they are
378 	 * picked-up by players.
379 	 *
380 	 * <p>If so, each weapon type can be picked up from pick-up points only
381 	 * once. If the player already has the weapon the pick-up point offers, he
382 	 * can not pick it up. Also, each weapon pick-up point always contains its
383 	 * associated weapon.
384 	 *
385 	 * <p>If not, weapons can be picked up from pick-up points repeatedly.
386 	 * If the player already has the weapon the pick-up point offers, the
387 	 * pick-up will simply replenish ammo for that weapon. Also, upon each
388 	 * pick-up by a player, the offered weapon disappears (it is "taken" by
389 	 * that player). Weapons respawn on empty pick-up points after a while.
390 	 *
391 	 * @return True, if weapons stay on pick-up points.
392 	 */
393 	public Boolean getWeaponsStay()
394 	{
395 		// retreive from GameInfo object
396                 if (lastGameInfo == null) return null;
397 		return lastGameInfo.isWeaponStay();
398 	}
399 
400 	/*========================================================================*/
401 
402 	/**
403 	 * Retreives the maximum number of multi-jumping combos.
404 	 *
405 	 * <p>Note: Multi-jump combos are currently limited to double-jumps for
406 	 * bots.
407 	 *
408 	 * @return Maximum number of multi-jumping combos.
409 	 */
410 	public Integer getMaxMultiJump()
411 	{
412 		// retreive from InitedMessage object
413                 if (lastInitedMessage == null) return null;
414 		return lastInitedMessage.getMaxMultiJump();
415 	}
416 
417 	/*========================================================================*/
418 
419 	/**
420 	 * Returns list of mutators that are active in the current game.
421 	 * 
422 	 * @return Current game's mutators
423 	 */
424 	public List<Mutator> getMutators()
425 	{
426                 if (lastMutatorListObtained == null) return null;
427 		return lastMutatorListObtained.getMutators();
428 	}
429 
430 	/*========================================================================*/
431 
432 	/**
433 	 * Tells, whether the game is paused or running. When the game is paused,
434 	 * nobody can move or do anything (usually except posting text messages).
435 	 *
436 	 * @return True, if the game is paused. False otherwise.
437 	 *
438 	 * @see areBotsPaused()
439 	 */
440 	public Boolean isPaused()
441 	{
442 		// retreive from GameInfo object
443                 if (lastGameInfo == null) return null;
444 		return lastGameInfo.isGamePaused();
445 	}
446 
447 	/**
448 	 * Tells, whether the bots are paused or running. When the bots are paused,
449 	 * but the game is not paused as well, human controlled players can move.
450 	 * The bots are standing still and can do nothing  (usually except posting
451 	 * text messages).
452 	 *
453 	 * @return True, if the bots are paused. False otherwise.
454 	 *
455 	 * @see isPaused()
456 	 */
457 	public Boolean isBotsPaused()
458 	{
459 		// retreive from GameInfo object
460                 if (lastGameInfo == null) return null;
461 		return lastGameInfo.isBotsPaused();
462 	}
463 
464         /**
465          * Returns a map indexed by team numbers, holding all flags in the game.
466          * In non-Capture the Flag (CTF) gametypes the result map will be empty.
467          *
468          * @return Map containing all the flags in the game indexed by owner team number.
469          */
470 	public Map<Integer, FlagInfo> getAllCTFFlags()
471 	{
472 		return allCTFFlags;
473 	}
474 
475         /**
476          * Returns a collection of all the flags in the game.
477          * In non-Capture the Flag (CTF) gametypes the result collection will be empty.
478          *
479          * @return Collection containing all the flags in the game.
480          */
481 	public Collection<FlagInfo> getAllCTFFlagsCollection()
482 	{		
483 		return allCTFFlags.values();
484 	}
485 
486 	/*========================================================================*/
487 
488 	/** Most rescent message containing info about the game. */
489 	GameInfo lastGameInfo = null;
490 
491 	/** Most rescent message containing info about the game frame. */
492 	InitedMessage lastInitedMessage = null;
493 
494 	/** Most rescent message containing info about the game frame. */
495 	BeginMessage lastBeginMessage = null;
496 	
497 	/** Most recent info about game's mutators. */
498 	MutatorListObtained lastMutatorListObtained = null;
499 
500         /** All flags in the game - will be filled only in CTF games */
501         Map<Integer, FlagInfo> allCTFFlags = new HashMap();
502 
503 	/*========================================================================*/
504 
505 	/**
506 	 * GameInfo listener.
507 	 */
508 	private class GameInfoListener implements IWorldObjectEventListener<GameInfo, IWorldObjectEvent<GameInfo>>
509 	{
510 		@Override
511 		public void notify(IWorldObjectEvent<GameInfo> event)
512 		{
513 			lastGameInfo = event.getObject();
514 		}
515 
516 		/**
517 		 * Constructor. Registers itself on the given WorldView object.
518 		 * @param worldView WorldView object to listent to.
519 		 */
520 		public GameInfoListener(IWorldView worldView)
521 		{
522 			worldView.addObjectListener(GameInfo.class, this);
523 		}
524 	}
525 
526 	/** GameInfo listener */
527 	GameInfoListener gameInfoListener;
528 
529 	/*========================================================================*/
530 
531 	/**
532 	 * InitedMessage listener.
533 	 */
534 	private class InitedMessageListener implements IWorldObjectEventListener<InitedMessage, WorldObjectUpdatedEvent<InitedMessage>>
535 	{
536 		@Override
537 		public void notify(WorldObjectUpdatedEvent<InitedMessage> event)
538 		{
539 			lastInitedMessage = event.getObject();
540 		}
541 
542 		/**
543 		 * Constructor. Registers itself on the given WorldView object.
544 		 * @param worldView WorldView object to listent to.
545 		 */
546 		public InitedMessageListener(IWorldView worldView)
547 		{
548 			worldView.addObjectListener(InitedMessage.class, WorldObjectUpdatedEvent.class, this);
549 		}
550 	}
551 
552 	/** InitedMessage listener */
553 	InitedMessageListener initedMessageListener;
554 
555 	/*========================================================================*/
556 
557 	/**
558 	 * BeginMessage listener.
559 	 */
560 	private class BeginMessageListener implements IWorldEventListener<BeginMessage>
561 	{
562 		@Override
563 		public void notify(BeginMessage event)
564 		{
565 			lastBeginMessage = event;
566 		}
567 
568 		/**
569 		 * Constructor. Registers itself on the given WorldView object.
570 		 * @param worldView WorldView object to listent to.
571 		 */
572 		public BeginMessageListener(IWorldView worldView)
573 		{
574 			worldView.addEventListener(BeginMessage.class, this);
575 		}
576 	}
577 
578 	/** BeginMessage listener */
579 	BeginMessageListener beginMessageListener;
580 
581 	/*========================================================================*/
582 	
583 	/**
584 	 * MutatorListObtained listener.
585 	 */
586 	private class MutatorListObtainedListener implements IWorldEventListener<MutatorListObtained>
587 	{
588 		@Override
589 		public void notify(MutatorListObtained event)
590 		{
591 			lastMutatorListObtained = event;
592 		}
593 
594 		/**
595 		 * Constructor. Registers itself on the given WorldView object.
596 		 * @param worldView WorldView object to listent to.
597 		 */
598 		public MutatorListObtainedListener(IWorldView worldView)
599 		{
600 			worldView.addEventListener(MutatorListObtained.class, this);
601 		}
602 	}
603 
604 	/** MutatorListObtained listener */
605 	MutatorListObtainedListener mutatorListObtainedListener;
606 
607 	/*========================================================================*/
608 
609 	/**
610 	 * FlagInfo object listener.
611 	 */
612 	private class FlagInfoObjectListener implements IWorldObjectEventListener<FlagInfo,WorldObjectFirstEncounteredEvent<FlagInfo>>
613 	{
614 		/**
615                  * Save flag in our HashMap.
616                  * 
617                  * @param event
618                  */
619 		public void notify(WorldObjectFirstEncounteredEvent<FlagInfo> event)
620 		{
621                         if (allCTFFlags.containsKey(event.getObject().getTeam()))
622                                 if (log.isLoggable(Level.WARNING)) log.warning("Saving second Flag for team: " + event.getObject().getTeam() + ". Bug?");
623 
624 			allCTFFlags.put(event.getObject().getTeam(), event.getObject());
625 		}
626 
627 		/**
628 		 * Constructor. Registers itself on the given WorldView object.
629 		 * @param worldView WorldView object to listent to.
630 		 */
631 		public FlagInfoObjectListener(IWorldView worldView)
632 		{
633 			worldView.addObjectListener(FlagInfo.class, WorldObjectFirstEncounteredEvent.class, this);
634 		}        
635 	}
636 
637 	/** FlagInfo object listener */
638 	FlagInfoObjectListener flagInfoObjectListener;
639 
640 	/*========================================================================*/
641 
642 	/**
643 	 * Constructor. Setups the memory module based on bot's world view.
644 	 * @param bot owner of the module that is using it
645 	 */
646 	public Game(UDKBot bot) {
647 		this(bot, null);
648 	}
649 	
650 	/**
651 	 * Constructor. Setups the memory module based on bot's world view.
652 	 * @param bot owner of the module that is using it
653 	 * @param log Logger to be used for logging runtime/debug info. If <i>null</i>, the module creates its own logger.
654 	 */
655 	public Game(UDKBot bot, Logger log)
656 	{
657 		super(bot, log);
658 
659 		// create listeners
660 		gameInfoListener = new GameInfoListener(worldView);
661 		beginMessageListener = new BeginMessageListener(worldView);
662 		initedMessageListener = new InitedMessageListener(worldView);
663 		mutatorListObtainedListener = new MutatorListObtainedListener(worldView);
664                 flagInfoObjectListener = new FlagInfoObjectListener(worldView);
665 	}
666 	
667 	/**
668 	 * Provides initialization of the module (clearing internal data structures). Called automatically
669 	 * during the agent starting sequence.
670 	 */
671 	@Override
672 	protected void start(boolean startPaused) {
673 		super.start(startPaused);
674 		lastGameInfo = null;
675 		lastInitedMessage = null;
676 		lastBeginMessage = null;
677 		lastMutatorListObtained = null;
678 	}
679 }