View Javadoc

1   /**
2    * UT2004 Environment, an implementation of the environment interface standard that 
3    * facilitates the connection between GOAL and UT2004. 
4    * 
5    * Copyright (C) 2012 UT2004 Environment authors.
6    * 
7    * This program is free software: you can redistribute it and/or modify it under
8    * the terms of the GNU General Public License as published by the Free Software
9    * Foundation, either version 3 of the License, or (at your option) any later
10   * version.
11   * 
12   * This program is distributed in the hope that it will be useful, but WITHOUT
13   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15   * details.
16   * 
17   * You should have received a copy of the GNU General Public License along with
18   * this program. If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package nl.tudelft.goal.ut2004.agent;
22  
23  import java.lang.reflect.Method;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.LinkedList;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.logging.Level;
30  
31  import nl.tudelft.goal.unreal.actions.Action;
32  import nl.tudelft.goal.unreal.actions.ActionQueue;
33  import nl.tudelft.goal.unreal.messages.BotParameters;
34  import nl.tudelft.goal.unreal.messages.None;
35  import nl.tudelft.goal.unreal.messages.Parameters;
36  import nl.tudelft.goal.unreal.messages.Percept;
37  import nl.tudelft.goal.unreal.messages.UnrealIdOrLocation;
38  import nl.tudelft.goal.unreal.util.Selector;
39  import nl.tudelft.goal.ut2004.actions.Chat;
40  import nl.tudelft.goal.ut2004.actions.DropWeapon;
41  import nl.tudelft.goal.ut2004.actions.Look;
42  import nl.tudelft.goal.ut2004.actions.Navigate;
43  import nl.tudelft.goal.ut2004.actions.Prefer;
44  import nl.tudelft.goal.ut2004.actions.Respawn;
45  import nl.tudelft.goal.ut2004.actions.Shoot;
46  import nl.tudelft.goal.ut2004.actions.Stop;
47  import nl.tudelft.goal.unreal.floydwarshall.SharedFloydWarshallMap;
48  import nl.tudelft.goal.ut2004.messages.Combo;
49  import nl.tudelft.goal.ut2004.messages.FireMode;
50  import nl.tudelft.goal.ut2004.messages.FlagState;
51  import nl.tudelft.goal.ut2004.messages.Scope;
52  import nl.tudelft.goal.ut2004.messages.SelectorList;
53  import nl.tudelft.goal.ut2004.messages.WeaponPrefList;
54  import nl.tudelft.goal.ut2004.selector.ContextSelector;
55  import nl.tudelft.goal.ut2004.selector.NearestEnemy;
56  import nl.tudelft.goal.ut2004.util.Team;
57  import nl.tudelft.pogamut.unreal.agent.module.sensor.Projectiles;
58  import nl.tudelft.pogamut.unreal.agent.module.shooting.WeaponryShooting;
59  import nl.tudelft.pogamut.unreal.agent.module.shooting.util.FocusProvider;
60  import nl.tudelft.pogamut.unreal.agent.module.shooting.util.OrderedFocusProvider;
61  import nl.tudelft.pogamut.ut2004.agent.module.sensor.UT2004Projectiles;
62  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.AssaultRifleShooting;
63  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.BioRifleShooting;
64  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.FlakCannonShooting;
65  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.LigthningGunShooting;
66  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.LinkGunShooting;
67  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.MinigunShooting;
68  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.RocketLauncherShooting;
69  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.ShieldGunShooting;
70  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.ShockRifleShooting;
71  import nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon.SniperRifleShooting;
72  import cz.cuni.amis.pogamut.base.agent.navigation.IPathPlanner;
73  import cz.cuni.amis.pogamut.base.communication.worldview.listener.annotation.EventListener;
74  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObject;
75  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
76  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
77  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
78  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
79  import cz.cuni.amis.pogamut.ut2004.agent.module.sensomotoric.Weapon;
80  import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.WeaponPref;
81  import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004AStarPathPlanner;
82  import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004GetBackToNavGraph;
83  import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004Navigation;
84  import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004PathExecutor;
85  import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004RunStraight;
86  import cz.cuni.amis.pogamut.ut2004.agent.navigation.loquenavigator.LoqueNavigator;
87  import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004DistanceStuckDetector;
88  import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004PositionStuckDetector;
89  import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.UT2004TimeStuckDetector;
90  import cz.cuni.amis.pogamut.ut2004.agent.params.UT2004AgentParameters;
91  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
92  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004BotModuleController;
93  import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType;
94  import cz.cuni.amis.pogamut.ut2004.communication.messages.UT2004ItemType;
95  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.GetPath;
96  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
97  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
98  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.FlagInfo;
99  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
100 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
101 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PathList;
102 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
103 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerKilled;
104 import cz.cuni.amis.pogamut.ut2004.utils.UT2004BotRunner;
105 import cz.cuni.amis.utils.exception.PogamutException;
106 import eis.eis2java.annotation.AsAction;
107 import eis.eis2java.annotation.AsPercept;
108 import eis.eis2java.translation.Filter.Type;
109 import eis.eis2java.util.AllPerceptsModule;
110 import eis.eis2java.util.AllPerceptsProvider;
111 import eis.exceptions.EntityException;
112 import eis.exceptions.PerceiveException;
113 
114 @SuppressWarnings("rawtypes")
115 public class UT2004BotBehavior extends UT2004BotModuleController<UT2004Bot>
116 		implements AllPerceptsProvider {
117 
118 	protected List<ContextSelector> targetSelector = new ArrayList<ContextSelector>();
119 	protected List<ContextSelector> lookSelector = new ArrayList<ContextSelector>();
120 	protected Projectiles projectiles;
121 	protected WeaponryShooting weaponShooting;
122 	protected FocusProvider lookFocus = new FocusProvider();
123 	protected OrderedFocusProvider focus = new OrderedFocusProvider();
124 
125 	protected AllPerceptsModule percepts;
126 	/**
127 	 * Settings for the bot.
128 	 */
129 	protected BotParameters parameters;
130 
131 	/**
132 	 * Maximum size of the action queue.
133 	 * 
134 	 * The reason the action queue has a size of eight is because at most eight
135 	 * actions can sensibly be executed in combination. After that GOAL must be
136 	 * sending duplicate actions.
137 	 */
138 	private static final int ACTION_QUEUE_SIZE = 8;
139 
140 	/**
141 	 * Queued up actions. Once the queue if full GOAL has to wait.
142 	 * 
143 	 */
144 	private ActionQueue actions = new ActionQueue(ACTION_QUEUE_SIZE);
145 
146 	protected long logicIteration;
147 	protected long actionCount;
148 
149 	@Override
150 	public void initializeController(UT2004Bot bot) {
151 		super.initializeController(bot);
152 
153 		// Setup parameters
154 		UT2004AgentParameters parameters = bot.getParams();
155 		if ((parameters instanceof BotParameters)) {
156 			this.parameters = (BotParameters) parameters;
157 		} else {
158 			log.warning("Provided parameters were not a subclass of UnrealGoalParameters, using defaults.");
159 			this.parameters = new BotParameters();
160 		}
161 		Parameters defaults = BotParameters.getDefaults();
162 		this.parameters.assignDefaults(defaults);
163 
164 	}
165 
166 	/**
167 	 * Initialize projectiles and weaponshooting modules.
168 	 */
169 	protected void initializeModules(UT2004Bot bot) {
170 		super.initializeModules(bot);
171 
172 		projectiles = new UT2004Projectiles(bot, info);
173 		weaponShooting = new WeaponryShooting(bot, info, weaponry, weaponPrefs,
174 				shoot);
175 
176 		// Setup percept module.
177 		try {
178 			percepts = new AllPerceptsModule(this);
179 		} catch (EntityException e) {
180 			throw new PogamutException("Could not create percept module", e);
181 		}
182 
183 		initializeWeaponShootings();
184 	}
185 
186 	/**
187 	 * Adds handlers to deal with different weapons.
188 	 */
189 	protected void initializeWeaponShootings() {
190 		weaponShooting.addWeaponShooting(new LinkGunShooting(bot, info, shoot,
191 				weaponry));
192 		weaponShooting.addWeaponShooting(new ShockRifleShooting(bot, info,
193 				shoot, weaponry, projectiles));
194 		weaponShooting.addWeaponShooting(new MinigunShooting(bot, info, shoot,
195 				weaponry));
196 		weaponShooting.addWeaponShooting(new FlakCannonShooting(bot, info,
197 				shoot, weaponry));
198 		weaponShooting.addWeaponShooting(new ShieldGunShooting(bot, info,
199 				shoot, weaponry, projectiles, senses));
200 		weaponShooting.addWeaponShooting(new BioRifleShooting(bot, info, shoot,
201 				weaponry));
202 		weaponShooting.addWeaponShooting(new AssaultRifleShooting(bot, info,
203 				shoot, weaponry));
204 		weaponShooting.addWeaponShooting(new RocketLauncherShooting(bot, info,
205 				shoot, weaponry));
206 		weaponShooting.addWeaponShooting(new LigthningGunShooting(bot, info,
207 				shoot, weaponry));
208 		weaponShooting.addWeaponShooting(new SniperRifleShooting(bot, info,
209 				shoot, weaponry));
210 	}
211 
212 	/**
213 	 * Path-planner ({@link IPathPlanner} using {@link NavPoint}s), you may use
214 	 * it to find paths inside the environment wihtout waiting for round-trip of
215 	 * {@link GetPath} command and {@link PathList}s response from UT2004. It is
216 	 * much faster than {@link UT2004BotModuleController#pathPlanner} but you
217 	 * need to pass {@link NavPoint} instances to planner instead of
218 	 * {@link ILocated} ... to find the nearest {@link NavPoint} instance,
219 	 * {@link DistanceUtils} is a handy, check especially
220 	 * {@link DistanceUtils#getNearest(java.util.Collection, ILocated)}.
221 	 */
222 	protected SharedFloydWarshallMap sfwMap;
223 
224 	/**
225 	 * Initializes path-finding modules:
226 	 * {@link UT2004BotModuleControllerNew#pathPlanner},
227 	 * {@link UT2004BotModuleController#fwMap} and
228 	 * {@link UT2004BotModuleControllerNew#pathExecutor}. If you need different
229 	 * path planner / path executor - override this method and initialize your
230 	 * own modules.
231 	 * 
232 	 * @param bot
233 	 */
234 	@Override
235 	protected void initializePathFinding(UT2004Bot bot) {
236 		pathPlanner = new UT2004AStarPathPlanner(bot);
237 		sfwMap = new SharedFloydWarshallMap(bot);
238 		pathExecutor = new UT2004PathExecutor<ILocated>(
239         		bot, info,move, new LoqueNavigator<ILocated>(bot, info,move,bot.getLog()),
240                         bot.getLog());
241                 
242 		// add stuck detectors that watch over the path-following, if it
243 		// (heuristicly) finds out that the bot has stuck somewhere,
244 		// it reports an appropriate path event and the path executor will stop
245 		// following the path which in turn allows
246 		// us to issue another follow-path command in the right time
247 		pathExecutor.addStuckDetector(new UT2004TimeStuckDetector(bot, 3000,
248 				100000));
249 		pathExecutor.addStuckDetector(new UT2004PositionStuckDetector(bot));
250 		pathExecutor.addStuckDetector(new UT2004DistanceStuckDetector(bot));
251 
252 		getBackToNavGraph = new UT2004GetBackToNavGraph(bot, info, move);
253 		runStraight = new UT2004RunStraight(bot, info, move);
254 		navigation = new UT2004Navigation(bot, pathExecutor, sfwMap,
255 				getBackToNavGraph, runStraight);
256 	}
257 
258 	/**
259 	 * Prepares the initialization message for Gamebots using the
260 	 * {@link BotParameters} provided to the {@link UT2004BotRunner}.
261 	 * 
262 	 */
263 	@Override
264 	public Initialize getInitializeCommand() {
265 		assert parameters != null;
266 
267 		// Prepare init command
268 		Initialize init = super.getInitializeCommand();
269 		init.setDesiredSkill(parameters.getSkill());
270 		init.setSkin(parameters.getSkin().getUnrealName());
271 		init.setTeam(parameters.getTeam());
272 		init.setShouldLeadTarget(parameters.shouldLeadTarget());
273 
274 		init.setLocation(parameters.getInitialLocation());
275 		init.setRotation(parameters.getInitialRotation());
276 		// Set log level.
277 		log.setLevel(this.parameters.getLogLevel());
278 
279 		return init;
280 
281 	}
282 
283 	/**
284 	 * Finish controller initialisation. Connects the weaponshooting to the
285 	 * navigation.
286 	 */
287 	@Override
288 	public void finishControllerInitialization() {
289 		// Connects focus providers. Ordered focus provider will first check the
290 		// focus provided by weapon shooting. If none is provided it will go to
291 		// the
292 		// look location.
293 		focus.add(weaponShooting.getFocus());
294 		focus.add(lookFocus);
295 		navigation.setFocus(focus);
296 
297 		// TODO: This is executed for every bot while we use a shared map.
298 		if (navBuilder.isUsed()) {
299 			log.info("Navigation graph has been altered by 'navBuilder', triggering recomputation of Floyd-Warshall path matrix...");
300 			Level oldLevel = sfwMap.getLog().getLevel();
301 			sfwMap.getLog().setLevel(Level.FINER);
302 			sfwMap.refreshPathMatrix();
303 			sfwMap.getLog().setLevel(oldLevel);
304 		}
305 	}
306 
307 	/**
308 	 * Called before the evaluation of the first logic. Use this to set up
309 	 * elements that need information about the world.
310 	 */
311 
312 	@Override
313 	public void beforeFirstLogic() {
314 		targetSelector.add(new NearestEnemy().setContext(this));
315 		lookSelector.add(new NearestEnemy().setContext(this));
316 
317 		weaponPrefs.addGeneralPref(UT2004ItemType.SHOCK_RIFLE, false);
318 		weaponPrefs.addGeneralPref(UT2004ItemType.ROCKET_LAUNCHER, true);
319 		weaponPrefs.addGeneralPref(UT2004ItemType.FLAK_CANNON, true);
320 		weaponPrefs.addGeneralPref(UT2004ItemType.SNIPER_RIFLE, true);
321 		weaponPrefs.addGeneralPref(UT2004ItemType.LIGHTNING_GUN, true);
322 		weaponPrefs.addGeneralPref(UT2004ItemType.MINIGUN, true);
323 		weaponPrefs.addGeneralPref(UT2004ItemType.LINK_GUN, true);
324 		weaponPrefs.addGeneralPref(UT2004ItemType.BIO_RIFLE, false);
325 		weaponPrefs.addGeneralPref(UT2004ItemType.ASSAULT_RIFLE, true);
326 		weaponPrefs.addGeneralPref(UT2004ItemType.ASSAULT_RIFLE, false);
327 		weaponPrefs.addGeneralPref(UT2004ItemType.SHIELD_GUN, false);
328 		weaponPrefs.addGeneralPref(UT2004ItemType.SHIELD_GUN, true);
329 
330 	}
331 
332 	/**
333 	 * The bot will evaluate its the logic every 100ms. In each evaluation it
334 	 * will do the following:
335 	 * 
336 	 * <ol>
337 	 * <li>Execute all outstanding action.</li>
338 	 * <li>Determine a target to shoot and look at. The target is determined by
339 	 * the first {@link Selector} in the list set by
340 	 * {@link UT2004BotBehavior#target(SelectorList)} that returns a valid
341 	 * target.</li>
342 	 * <li>Determine a target to look at. The target is determined by the first
343 	 * {@link Selector} in the list set by
344 	 * {@link UT2004BotBehavior#look(SelectorList)} that returns a valid target.
345 	 * </li>
346 	 * <li>Look at something</li>
347 	 * <ol>
348 	 * <li>If we are navigating, navigation will ensure that we look at either
349 	 * our target or at the path ahead.</li>
350 	 * <li>If we have a target to look at, we turn to that target.</li>
351 	 * <li>If we don't have a target to look at, we turn around looking for a
352 	 * target.</li>
353 	 * </ol>
354 	 * <li>Prepare a batch of percepts for the Environment.</li>
355 	 * 
356 	 * </ol>
357 	 * 
358 	 */
359 	@Override
360 	public void logic() {
361 		super.logic();
362 
363 		// 0. Execute all outstanding actions.
364 		for (Action action : actions.drain()) {
365 			action.execute();
366 			actionCount++;
367 		}
368 
369 		// 1. The target that we may shoot at...
370 		// ...is determined by the first filter to match.
371 		ILocated shootSelected = null;
372 		for (Selector<ILocated> selector : targetSelector) {
373 			shootSelected = selector.select(players.getVisiblePlayers()
374 					.values());
375 			if (shootSelected != null) {
376 				break;
377 			}
378 		}
379 		weaponShooting.shoot(shootSelected);
380 
381 		// 2. We determine a target to look at.
382 		// This will be look at if our shoot target is not visible.
383 		ILocated lookSelected = null;
384 		for (Selector<ILocated> selector : lookSelector) {
385 			lookSelected = selector
386 					.select(players.getVisiblePlayers().values());
387 			if (lookSelected != null) {
388 				break;
389 			}
390 		}
391 		lookFocus.setFocus(lookSelected);
392 
393 		// 3. If we are navigating now, we are done.
394 		if (!navigation.isNavigating()) {
395 			// 4a. If we have a target but are not moving, turn to the target.
396 			if (focus.getLocation() != null) {
397 				move.turnTo(focus.getLocation());
398 			}
399 			// 4b. If we see no one, we spin around.
400 			else {
401 				move.turnHorizontal(30);
402 			}
403 		}
404 
405 		logicIteration++;
406 
407 		// 5. Prepare new batch of percepts
408 		try {
409 			percepts.updatePercepts();
410 		} catch (PerceiveException e) {
411 			throw new PogamutException("Could not update percepts", e);
412 		}
413 
414 	}
415 
416 	/**
417 	 * Queues up the action to be executed on the first evaluation of the logic
418 	 * cycle. When the queue is full, this action will block until the queue is
419 	 * free.
420 	 * 
421 	 * @param action
422 	 * @throws InterruptedException
423 	 */
424 	public void addAction(Action action) throws InterruptedException {
425 		actions.put(action);
426 	}
427 
428 	/**
429 	 * Returns a previously prepared batch of percepts.
430 	 * 
431 	 * @return a previously prepared batch of percepts.
432 	 */
433 	public Map<Method, Object> getAllPercepts() {
434 		return percepts.getAllPercepts();
435 	}
436 
437 	/**
438 	 * When called the bot will make a best effort attempt to navigate to
439 	 * requested destination. The destination either be a {@link Location} or
440 	 * the UnrealId of an {@link ILocated} such as {@link NavPoint} or
441 	 * {@link Player}. When provided with a player the bot will actively pursue
442 	 * the player provided the player remains visible.
443 	 * 
444 	 * The destination is considered reached when the bot is within 50 UT units
445 	 * from the destination. Or 100 UT units when trying to navigate to a
446 	 * player.
447 	 * 
448 	 * The navigation can fail when there is no path to the destination, when
449 	 * the bot gets stuck. A bot can be considered stuck by three heuristics.
450 	 * Either the {@link UT2004DistanceStuckDetector} when the bot has not be
451 	 * closing in on its target enough, {@link UT2004PositionStuckDetector} when
452 	 * it has not been moving at all, or the {@link UT2004TimeStuckDetector}
453 	 * when it has not moved enough over time.
454 	 * 
455 	 * When the bot dies or respawns the navigation will reset to waiting.
456 	 * 
457 	 * @param destination
458 	 *            where the bot should go.
459 	 */
460 	@AsAction(name = "navigate")
461 	public void navigate(final UnrealIdOrLocation destination)
462 			throws InterruptedException {
463 		log.fine(String.format("called navigate to %s", destination));
464 
465 		addAction(new Navigate() {
466 
467 			@Override
468 			public void execute() {
469 
470 				ILocated object = destination.toILocated(world, info);
471 
472 				if (object == null) {
473 					log.warning(String
474 							.format("failed to navigate to %s. The object associated with this Id was not located in the world. Halting.",
475 									destination));
476 					navigation.stopNavigation();
477 					return;
478 				}
479 
480 				log.fine(String.format("executed navigate to %s", destination));
481 				navigation.navigate(object);
482 			}
483 		});
484 
485 	}
486 
487 	// /**
488 	// * When called the bot will navigate to the new destination after reaching
489 	// * the old one. When the bot is not navigating the navigate action will be
490 	// * executed instead.
491 	// *
492 	// * Please note that you using continue when following a player has no
493 	// * effect.
494 	// *
495 	// * The navigation state will be updated to reflect the new destination.
496 	// *
497 	// * NOTE: This action is experimental and does not work properly let.
498 	// * Currently if there is no path to the continue location the
499 	// * {@link UT2004Navigation} will ignore this.
500 	// *
501 	// * @param destination
502 	// * where the bot should go.
503 	// */
504 	// @AsAction(name = "continue")
505 	// public void continueAction(final UnrealIdOrLocation destination) throws
506 	// InterruptedException {
507 	// log.fine(String.format("called continue to %s", destination));
508 	//
509 	// addAction(new Continue() {
510 	//
511 	// @Override
512 	// public void execute() {
513 	//
514 	// ILocated object = destination.toILocated(world, info);
515 	// if (object == null) {
516 	// log.warning(String.format("failed to continue to %s. The object associated with this Id was not located in the world.",
517 	// object));
518 	// return;
519 	// }
520 	//
521 	// if (!navigation.isNavigating()) {
522 	// navigation.navigate((ILocated) object);
523 	// } else if (navigation.isNavigatingToPlayer()) {
524 	// log.warning(String.format("failed to continue to %s. Navigation is navigating to a player",
525 	// object));
526 	// } else {
527 	// navigation.setContinueTo((ILocated) object);
528 	// }
529 	//
530 	// log.info(String.format("executed continue to %s", object));
531 	//
532 	// }
533 	// });
534 	// }
535 
536 	/**
537 	 * When called the bot will stop.
538 	 * 
539 	 * Navigation will reset to waiting.
540 	 */
541 	@AsAction(name = "stop")
542 	public void stop() throws InterruptedException {
543 		log.fine("called stop");
544 
545 		addAction(new Stop() {
546 			@Override
547 			public void execute() {
548 				log.info("executed stop");
549 				navigation.stopNavigation();
550 			}
551 		});
552 	}
553 
554 	/**
555 	 * When called the bot will respawn in at a random spawn point of its team.
556 	 * 
557 	 * When the bot respawns he will have 100 health, 0 adrenaline, 0 armor, a
558 	 * shield gun and an assault rifle with 100 bullets and 4 grenades. The
559 	 * navigating will be reset to waiting.
560 	 * 
561 	 */
562 	@AsAction(name = "respawn")
563 	public void respawn() throws InterruptedException {
564 		log.fine("called respawn");
565 		addAction(new Respawn() {
566 			@Override
567 			public void execute() {
568 				log.info("executed respawn");
569 				bot.respawn();
570 			}
571 		});
572 	}
573 
574 	/**
575 	 * <p>
576 	 * When called the bot will use the given combo.
577 	 * </p>
578 	 * 
579 	 * <p>
580 	 * Syntax: combo(Combo)<br>
581 	 * <ul>
582 	 * <li>Combo: Either booster, berserk, invisibility or speed</li>
583 	 * </ul>
584 	 * </p>
585 	 * 
586 	 * <p>
587 	 * A combo can only be activated when the bot has 100 or more adrenaline.
588 	 * When active the combo will give the bot a small powerup and consume the
589 	 * bots adrenaline until none remains. When the adrenaline runs out the
590 	 * combo will stop.
591 	 * </p>
592 	 * <p>
593 	 * For more information about the effects of a combo see:
594 	 * http://liandri.beyondunreal.com/Adrenaline
595 	 * </p>
596 	 * 
597 	 * 
598 	 * 
599 	 * @param combo
600 	 *            to be activated.
601 	 */
602 	@AsAction(name = "combo")
603 	public void combo(final Combo combo) throws InterruptedException {
604 		log.fine("called combo %s", combo);
605 
606 		addAction(new nl.tudelft.goal.ut2004.actions.Combo() {
607 			@Override
608 			public void execute() {
609 
610 				if (info.isAdrenalineSufficient()) {
611 					log.info("executed combo %s", combo);
612 					body.getAction().startCombo(combo.toString());
613 				} else {
614 					log.warning("combo %s failed, insufficient adrenaline",
615 							combo);
616 				}
617 			}
618 		});
619 	}
620 
621 	/**
622 	 * <p>
623 	 * Drops the weapon the bot is currently holding.
624 	 * </p>
625 	 * <p>
626 	 * Syntax: dropWeapon
627 	 * </p>
628 	 * 
629 	 * <p>
630 	 * The weapon will be dropped a few UT hundred units in the direction the
631 	 * bot is looking. When a weapon is dropped it can be picked up again,
632 	 * either by this bot or other other bots.
633 	 * </p>
634 	 * <p>
635 	 * Note: The translocator and the shield gun can not be dropped.
636 	 * <p>
637 	 */
638 	@AsAction(name = "dropWeapon")
639 	public void dropWeapon() throws InterruptedException {
640 		log.fine("called drop");
641 
642 		addAction(new DropWeapon() {
643 			@Override
644 			public void execute() {
645 				Weapon weapon = weaponry.getCurrentWeapon();
646 
647 				body.getAction().throwWeapon();
648 
649 				if (weapon == null) {
650 					log.warning(String
651 							.format("Could not drop weapon. Not holding a weapon."));
652 				} else if (weapon.getType() == UT2004ItemType.SHIELD_GUN
653 						|| weapon.getType() == UT2004ItemType.TRANSLOCATOR) {
654 					log.warning(String.format("Could not drop weapon %s",
655 							weapon));
656 				} else {
657 					log.info("executed drop %s", weapon);
658 				}
659 			}
660 		});
661 	}
662 
663 	/**
664 	 * <p>
665 	 * The bot computes a path from a to b.</a>
666 	 * 
667 	 * <p>
668 	 * Syntax: path(From,To)<br>
669 	 * <ul>
670 	 * <li>From: UnrealId of a nav point.</li>
671 	 * <li>To: UnrealId of a nav point.</li>
672 	 * </ul>
673 	 * </p>
674 	 * 
675 	 * <p>
676 	 * The action results in a path percept containing the path from a to b.
677 	 * </p>
678 	 * 
679 	 * <p>
680 	 * Syntax: path(StartId, EndId, Length,[NavPointId])<br>
681 	 * <ul>
682 	 * <li>StartId: start of the path as UnrealId.</li>
683 	 * <li>EndId: end of the path as UnrealId.</li>
684 	 * <li>Length: Length of the path in UT units.</li>
685 	 * <li>NavPointId: A list of UnrealIds in the path.</li>
686 	 * </ul>
687 	 * </p>
688 	 * 
689 	 * 
690 	 * @param from
691 	 *            the navpoint from which the path starts.
692 	 * @param to
693 	 *            the navpoint where the path should go to
694 	 * @return the path between from and to, including the distance of the path.
695 	 */
696 	@AsAction(name = "path")
697 	public Percept path(UnrealIdOrLocation from, UnrealIdOrLocation to) {
698 
699 		ILocated toObject = to.toILocated(world, info);
700 		ILocated fromObject = from.toILocated(world, info);
701 
702 		if (fromObject == null) {
703 			throw new PogamutException(
704 					String.format(
705 							"Failed to compute path from %s to %s. The start was not located in the world.",
706 							from, to), this);
707 		}
708 		if (toObject == null) {
709 			throw new PogamutException(
710 					String.format(
711 							"Failed to compute path from %s to %s. The destination was not located in the world.",
712 							from, to), this);
713 		}
714 
715 		// Not put into action queue. Doesn't require dynamic info from world.
716 		log.info(String.format("executed path from  %s to %s", from, to));
717 
718 		// Extract locations. This action is off the pogamut thread so we want
719 		// to use the immutables for consistent results.
720 		// We are using volitile information here but that is okay.
721 		// Location objects, Navpoints, Items don't move. Players can but only
722 		// for a limited distance. Not enough to invalidate the path or cause
723 		// strange results.
724 		Location fromLocation = fromObject.getLocation();
725 		Location toLocation = toObject.getLocation();
726 
727 		NavPoint fromNav = DistanceUtils.getNearest(world
728 				.getAll(NavPoint.class).values(), fromLocation);
729 		NavPoint toNav = DistanceUtils.getNearest(world.getAll(NavPoint.class)
730 				.values(), toLocation);
731 
732 		double distance = sfwMap.getDistance(fromNav, toNav);
733 		List<NavPoint> navPoints = sfwMap.getPath(fromNav, toNav);
734 		List<UnrealId> unrealIds = new ArrayList<UnrealId>(navPoints.size());
735 		for (NavPoint n : navPoints) {
736 			unrealIds.add(n.getId());
737 		}
738 		return new Percept(from, to, distance, unrealIds);
739 	}
740 
741 	/**
742 	 * 
743 	 * <p>
744 	 * Tells the bot how to prioritize who it shoots.
745 	 * </p>
746 	 * <p>
747 	 * Syntax: shoot([Selector])<br>
748 	 * Syntax: shoot(Selector)<br>
749 	 * <ul>
750 	 * <li>[Selector]: A list of selectors. A selector either selects a target
751 	 * from the list of visible players, provides a fixed location or selects
752 	 * nothing if no suitable target was available for selection. The bot
753 	 * evaluates each selector in order. The target provided by the first first
754 	 * selector to select a target will be shot at. Should no selector provide a
755 	 * valid target will be shot at. If no targets are selected the bot will
756 	 * stop shooting.</li>
757 	 * <li>Selector: A selector will select a target from the visible players.
758 	 * Can be, nearestEnemy, nearestFriendly, nearestFriendlyWithLinkGun,
759 	 * enemyFlagCarrier, friendlyFlagCarrier, a PlayerID or a location(X,Y,Z).</li>
760 	 * </ul>
761 	 * </p>
762 	 * 
763 	 * <p>
764 	 * Note:
765 	 * <ol>
766 	 * <li>To stop shooting, use shoot([]) or stopShooting.</li>
767 	 * <li>By default the bot will shoot the nearest visible enemy.</li>
768 	 * </ol>
769 	 * </p>
770 	 */
771 	@AsAction(name = "shoot")
772 	public void shoot(final SelectorList targets) throws InterruptedException {
773 		log.fine(String.format("called shoot %s", targets));
774 
775 		addAction(new Shoot() {
776 
777 			@Override
778 			public void execute() {
779 				log.info(String.format("executed shoot %s ", targetSelector));
780 
781 				targetSelector = targets.setContext(UT2004BotBehavior.this);
782 			}
783 		});
784 
785 	}
786 
787 	/**
788 	 * *
789 	 * <p>
790 	 * Tells the bot to stop shooting.
791 	 * </p>
792 	 * <p>
793 	 * Syntax: stopShoot
794 	 * </p>
795 	 * <p>
796 	 * Note: Executes shoot([])
797 	 * </p>
798 	 */
799 
800 	@AsAction(name = "stopShooting")
801 	public void stopShooting() throws InterruptedException {
802 		shoot(new SelectorList());
803 	}
804 
805 	/**
806 	 * <p>
807 	 * Tells the bot which weapon it should prefer. The bot will select the
808 	 * first weapon from the list it can use. A weapon can be used when the bot
809 	 * has the and the ammo for it.
810 	 * </p>
811 	 * 
812 	 * <p>
813 	 * Syntax: prefer([weapon(WeaponId, FireMode)])<br>
814 	 * Syntax: prefer(weapon(WeaponId, FireMode))<br>
815 	 * <ul>
816 	 * <li>WeaponId: The id of the weapon.</li>
817 	 * <li>FireMode: How the bot should use the weapon, either primary or
818 	 * secondary.</li>
819 	 * </ul>
820 	 * </p>
821 	 * 
822 	 * <p>
823 	 * Note: By Default the bot prefers the weapons in this order:
824 	 * <ol>
825 	 * <li>weapon(shock_rifle, secondary)</li>
826 	 * <li>weapon(rocket_launcher, primary)</li>
827 	 * <li>weapon(flack_cannon, primary)</li>
828 	 * <li>weapon(sniper_rifle, primary)</li>
829 	 * <li>weapon(lightning_gun, primary)</li>
830 	 * <li>weapon(mini_gun, primary)</li>
831 	 * <li>weapon(link_gun, primary)</li>
832 	 * <li>weapon(bio_rifle, secondary)</li>
833 	 * <li>weapon(assault_rifle, primary)</li>
834 	 * <li>weapon(assault_rfile, secondary)</li>
835 	 * <li>weapon(shield_gun, secondary)</li>
836 	 * <li>weapon(shield_gun, primary)</li>
837 	 * </ol>
838 	 * 
839 	 * </p>
840 	 */
841 	@AsAction(name = "prefer")
842 	public void prefer(final WeaponPrefList weaponList)
843 			throws InterruptedException {
844 		log.fine(String.format("called prefer %s", weaponList));
845 
846 		addAction(new Prefer() {
847 
848 			@Override
849 			public void execute() {
850 				weaponPrefs.clearAllPrefs();
851 
852 				for (WeaponPref pref : weaponList) {
853 					weaponPrefs.addGeneralPref(pref.getWeapon(),
854 							pref.isPrimary());
855 				}
856 
857 				log.info(String.format("executed prefer %s", weaponList));
858 			}
859 		});
860 	}
861 
862 	/**
863 	 * 
864 	 * <p>
865 	 * Tells the bot how to prioritize what it looks at.
866 	 * </p>
867 	 * <p>
868 	 * Syntax: look([Selector])<br>
869 	 * Syntax: look(Selector)<br>
870 	 * <ul>
871 	 * <li>[Selector]: A list of selectors. A selector either selects a target
872 	 * from the list of visible players, provides a fixed location or selects
873 	 * nothing if no suitable target was available for selection. The bot
874 	 * evaluates each selector in order. The target provided by the first first
875 	 * selector to select a target will be shot at. Should no selector provide a
876 	 * valid target will be looked at. If no targets are selected the bot will
877 	 * slowly turn around.</li>
878 	 * <li>Selector: A selector will select a target from the visible players.
879 	 * Can be, nearestEnemy, nearestFriendly, nearestFriendlyWithLinkGun,
880 	 * enemyFlagCarrier, friendlyFlagCarrier, a PlayerID or a location(X,Y,Z).</li>
881 	 * </ul>
882 	 * </p>
883 	 * 
884 	 * <p>
885 	 * Note:
886 	 * <ol>
887 	 * <li>To to start looking around, use look([]).</li>
888 	 * <li>By default the bot will look at the nearest visible enemy.</li>
889 	 * </ol>
890 	 * </p>
891 	 */
892 	@AsAction(name = "look")
893 	public void look(final SelectorList targets) throws InterruptedException {
894 		log.fine(String.format("called look %s", targets));
895 
896 		addAction(new Look() {
897 
898 			@Override
899 			public void execute() {
900 				log.info(String.format("executed look %s", targets));
901 
902 				lookSelector = targets.setContext(UT2004BotBehavior.this);
903 			}
904 		});
905 	}
906 
907 	/**
908 	 * 
909 	 * <p>
910 	 * Does nothing.
911 	 * </p>
912 	 * <p>
913 	 * Syntax: skip
914 	 * </p>
915 	 * 
916 	 * TODO: Check DOC
917 	 */
918 	@AsAction(name = "skip")
919 	public void skip() {
920 		// Does nothing.
921 	}
922 
923 	/**
924 	 * TODO: Doc.
925 	 * 
926 	 * @param scope
927 	 * @param message
928 	 * @throws InterruptedException
929 	 */
930 	@AsAction(name = "chat")
931 	public void chat(final Scope scope, final String message)
932 			throws InterruptedException {
933 		log.fine(String.format("called chat: %s", message));
934 
935 		addAction(new Chat() {
936 			@Override
937 			public void execute() {
938 				log.info(String.format("executed chat: %s", message));
939 				switch (scope) {
940 				case GLOBAL:
941 					body.getCommunication().sendGlobalTextMessage(message);
942 					break;
943 				case TEAM:
944 					body.getCommunication().sendTeamTextMessage(message);
945 					break;
946 				// No need for default when switching on an enum. If you're
947 				// worried about missing
948 				// cases in which the enum is extended you can use the Exclipse
949 				// Settings. Java ->
950 				// Compier -> Errors/Warnings -> Enum type constant not covered
951 				// on 'switch'.
952 				// default:
953 				// log.severe("unknown chat scope");
954 				// break;
955 				}
956 
957 			}
958 		});
959 	}
960 
961 	/**
962 	 * <p>
963 	 * Information about iteration of the bots logic.
964 	 * </p>
965 	 * <p>
966 	 * Type: On Change
967 	 * </p>
968 	 * 
969 	 * <p>
970 	 * Syntax: logic(Iteration)
971 	 * <ul>
972 	 * <li>Iteration: The number of iterations of the bots logic so far.</li>
973 	 * </ul>
974 	 * </p>
975 	 * <p>
976 	 * Notes:
977 	 * <ol>
978 	 * <li>While the bot is capable of executing multiple actions in single
979 	 * logic iteration, it does not always make sense. Use this iteration to
980 	 * check if the bot is clear again.</li>
981 	 * </ol>
982 	 * </p>
983 	 */
984 	@AsPercept(name = "logic", filter = Type.ON_CHANGE)
985 	@Deprecated
986 	public Percept logicIteration() {
987 		return new Percept(logicIteration);
988 	}
989 
990 	@AsPercept(name = "actionCount", filter = Type.ON_CHANGE)
991 	@Deprecated
992 	public Percept actionCount() {
993 		return new Percept(actionCount);
994 	}
995 
996 	/**
997 	 * <p>
998 	 * Information about the bot's identity and team.
999 	 * </p>
1000 	 * <p>
1001 	 * Type: On Change
1002 	 * </p>
1003 	 * 
1004 	 * <p>
1005 	 * Syntax: self(UnrealId, NickName, Team)
1006 	 * <ul>
1007 	 * <li>UnrealId: Unique identifier assigned by Unreal.</li>
1008 	 * <li>NickName: Name as it appears in the game.</li>
1009 	 * <li>Team: Either red, blue, or none.</li>
1010 	 * </ul>
1011 	 * </p>
1012 	 * 
1013 	 */
1014 	@AsPercept(name = "self", filter = Type.ON_CHANGE)
1015 	public Percept self() {
1016 		return new Percept(info.getId(), info.getName(), Team.valueOf(info
1017 				.getTeam()));
1018 	}
1019 
1020 	/**
1021 	 * <p>
1022 	 * Information about the bot's position, rotation and velocity.
1023 	 * </p>
1024 	 * <p>
1025 	 * Type: On Change
1026 	 * </p>
1027 	 * <p>
1028 	 * Syntax: orientation(location(X,Y,Z), rotation(Pitch,Yaw,Roll),
1029 	 * velocity(Vx, Vy,Vz))
1030 	 * <ul>
1031 	 * <li>Location: the position in UT units.</li>
1032 	 * <li>Rotation: the bots rotation in degrees.</li>
1033 	 * <li>Velocity: the velocity in UT units per second.</li>
1034 	 * </ul>
1035 	 * </p>
1036 	 * 
1037 	 */
1038 	@AsPercept(name = "orientation", filter = Type.ON_CHANGE)
1039 	public Percept orientation() {
1040 		return new Percept(info.getLocation(), info.getRotation(),
1041 				info.getVelocity());
1042 	}
1043 
1044 	/**
1045 	 * <p>
1046 	 * Information about the bot's current physical state.
1047 	 * </p>
1048 	 * <p>
1049 	 * Type: On Change
1050 	 * </p>
1051 	 * 
1052 	 * <p>
1053 	 * Syntax status(Health, Armour, Adrenaline,ActiveCombo)
1054 	 * <ul>
1055 	 * <li>Health: A number between 0 and 199, indicating the health.</li>
1056 	 * <li>Armour: A number between 0 and 150, indicating the armor.</li>
1057 	 * <li>Adrenaline: An number between 0 and 100, indicating the adrenaline.</li>
1058 	 * <li>ActiveCombo: The combo that is currently active, or none when none is
1059 	 * active.</li>
1060 	 * </ul>
1061 	 * </p>
1062 	 * 
1063 	 */
1064 	@AsPercept(name = "status", filter = Type.ON_CHANGE)
1065 	public Percept status() {
1066 		return new Percept(info.getHealth(), info.getArmor(),
1067 				info.getAdrenaline(), Combo.parseCombo(info.getSelf()
1068 						.getCombo()));
1069 	}
1070 
1071 	/**
1072 	 * <p>
1073 	 * Information about the number of kills, deaths, and suicides this bot
1074 	 * accumulated.
1075 	 * </p>
1076 	 * <p>
1077 	 * Type: On Change
1078 	 * </p>
1079 	 * 
1080 	 * <p>
1081 	 * Syntax: score(Kills, Deaths, Suicides)
1082 	 * <ul>
1083 	 * <li>Kills: Number of people the bot fragged during this game.</li>
1084 	 * <li>Deaths: Number of times the bot died during this game.</li>
1085 	 * <li>Suicides: Number of times the bot got himself killed.</li>
1086 	 * </ul>
1087 	 * </p>
1088 	 * 
1089 	 * <p>
1090 	 * <em>Note</em>: Using the respawn action and being fragged by an opponent
1091 	 * both count as a death. Being killed by the your own weapon counts as a
1092 	 * suicide.
1093 	 * </p>
1094 	 * 
1095 	 */
1096 	@AsPercept(name = "score", filter = Type.ON_CHANGE)
1097 	public Percept score() {
1098 		return new Percept(info.getKills(), info.getDeaths(),
1099 				info.getSuicides());
1100 	}
1101 
1102 	/**
1103 	 * <p>
1104 	 * Information about weapon the bot is currently holding.
1105 	 * </p>
1106 	 * <p>
1107 	 * Type: On Change
1108 	 * </p>
1109 	 * 
1110 	 * <p>
1111 	 * Syntax: currentWeapon(WeaponType,FireMode)
1112 	 * <ul>
1113 	 * <li>WeaponType: Name of the weapon.</li>
1114 	 * <li>FireMode: How the weapon is shooting. Either primary, secondary or
1115 	 * none.</li>
1116 	 * </ul>
1117 	 * </p>
1118 	 * <p>
1119 	 * TODO: List available weapons.
1120 	 * 
1121 	 */
1122 
1123 	@AsPercept(name = "currentWeapon", filter = Type.ON_CHANGE)
1124 	public Percept currentWeapon() {
1125 		final Weapon weapon = weaponry.getCurrentWeapon();
1126 
1127 		if (weapon == null) {
1128 			return new Percept(new None(), FireMode.NONE);
1129 		}
1130 
1131 		return new Percept(weapon.getType(), FireMode.valueOf(
1132 				info.isPrimaryShooting(), info.isSecondaryShooting()));
1133 	}
1134 
1135 	/**
1136 	 * <p>
1137 	 * Information about weapons the bot has in its inventory.
1138 	 * </p>
1139 	 * <p>
1140 	 * Type: On change
1141 	 * </p>
1142 	 * <p>
1143 	 * Syntax: weapon(WeaponType, PriAmmo, SecAmmo)
1144 	 * <ul>
1145 	 * <li>WeaponType: Name of the weapon.</li>
1146 	 * <li>PriAmmo: A number between 0 and the maximum for the weapon,
1147 	 * indicating the available ammo for the primary fire mode.</li>
1148 	 * <li>SecAmmo: A number between 0 and the maximum for the weapon,
1149 	 * indicating the available ammo for the secondary fire mode.</li>
1150 	 * </ul>
1151 	 * </p>
1152 	 * 
1153 	 * <p>
1154 	 * <em>Note</em>: The Shield Gun has infinite primary ammo. Its secondary
1155 	 * ammo recharges when not used.
1156 	 * </p>
1157 	 * 
1158 	 * 
1159 	 * TODO: List available weapons.
1160 	 * 
1161 	 */
1162 	@AsPercept(name = "weapon", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1163 	public Collection<Percept> weapon() {
1164 		Collection<Weapon> weapons = weaponry.getWeapons().values();
1165 		Collection<Percept> percepts = new ArrayList<Percept>(weapons.size());
1166 
1167 		for (Weapon w : weapons) {
1168 			if (w.getType() == UT2004ItemType.SHIELD_GUN) {
1169 				// Pogamut reports the secondary ammo twice. It reports this
1170 				// because UT reports this. Not trivial to fix so we do it here.
1171 				// 1 will stand in for infinity
1172 				percepts.add(new Percept(w.getType(), 1, w.getSecondaryAmmo()));
1173 			} else {
1174 				percepts.add(new Percept(w.getType(), w.getPrimaryAmmo(), w
1175 						.getSecondaryAmmo()));
1176 			}
1177 		}
1178 
1179 		return percepts;
1180 	}
1181 
1182 	/**
1183 	 * List of all fragged percepts.
1184 	 */
1185 	private List<Percept> fragged = new LinkedList<Percept>();
1186 
1187 	/**
1188 	 * Adds a new fragged percept to the list.
1189 	 * 
1190 	 * @param time
1191 	 * @param killer
1192 	 * @param victem
1193 	 * @param weaponName
1194 	 */
1195 	private void fraggedEvent(final long time, final UnrealId killer,
1196 			final UnrealId victem, final String damageType) {
1197 		fragged.add(new Percept(time, killer, victem, WeaponDamage
1198 				.weaponForDamage(damageType)));
1199 	}
1200 
1201 	/**
1202 	 * Event listener for deaths of this bot.
1203 	 * 
1204 	 * @param msg
1205 	 */
1206 	@EventListener(eventClass = BotKilled.class)
1207 	public void msgBotKilled(BotKilled msg) {
1208 		fraggedEvent(msg.getSimTime(), msg.getKiller(), info.getId(),
1209 				msg.getDamageType());
1210 	}
1211 
1212 	/**
1213 	 * Event listener for deaths of other bots & players.
1214 	 * 
1215 	 * @param msg
1216 	 */
1217 
1218 	@EventListener(eventClass = PlayerKilled.class)
1219 	public void msgPlayerKilled(PlayerKilled msg) {
1220 		fraggedEvent(msg.getSimTime(), msg.getKiller(), msg.getId(),
1221 				msg.getDamageType());
1222 	}
1223 
1224 	/**
1225 	 * <p>
1226 	 * This percept is provided when one bot is violently fragmented by another.
1227 	 * </p>
1228 	 * <p>
1229 	 * Type: Always
1230 	 * </p>
1231 	 * 
1232 	 * <p>
1233 	 * Syntax: fragged(Time,KillerID,VictemID,Weapon)
1234 	 * </p>
1235 	 * 
1236 	 * <p>
1237 	 * Notes:
1238 	 * <ol>
1239 	 * <li>When the killer and victim id are equal, the bot committed suicide.</li>
1240 	 * <li>When the killer is none, the bot respawned.</li>
1241 	 * </ol>
1242 	 * </p>
1243 	 * 
1244 	 */
1245 	@AsPercept(name = "fragged", multiplePercepts = true, filter = Type.ALWAYS, event = true)
1246 	public List<Percept> fragged() {
1247 		ArrayList<Percept> percepts = new ArrayList<Percept>(fragged);
1248 		fragged.clear();
1249 		return percepts;
1250 	}
1251 
1252 	/**
1253 	 * <p>
1254 	 * Information about the state of the navigation. The available states are:
1255 	 * </p>
1256 	 * 
1257 	 * <ul>
1258 	 * <li>navigating: The bot is traveling to its destination.</li>
1259 	 * <li>stuck: The botcould not reach its destination.</li>
1260 	 * <li>noPath: The bot could not find a path to its destination.</li>
1261 	 * <li>reached: The bot has arrived at its destination.</li>
1262 	 * <li>waiting: The bot is waiting for actions (initial state).</li>
1263 	 * </ul>
1264 	 * <p>
1265 	 * Type: On Change
1266 	 * </p>
1267 	 * 
1268 	 * <p>
1269 	 * Syntax: navigation(State,Destination)
1270 	 * <ul>
1271 	 * <li>State: State of the navigation. Either navigating, stuck, noPath,
1272 	 * reached or waiting.</li>
1273 	 * </ul>
1274 	 * </p>
1275 	 * 
1276 	 */
1277 	@AsPercept(name = "navigation", filter = Type.ON_CHANGE)
1278 	public Percept navigation() {
1279 		ILocated currentTarget = navigation.getCurrentTarget();
1280 
1281 		// We are going nowhere.
1282 		if (currentTarget == null) {
1283 			return new Percept(navigation.getState().getFlag(), new None());
1284 		}
1285 
1286 		// We are going some place that has an unrealid.
1287 		if (currentTarget instanceof IWorldObject) {
1288 			IWorldObject targetObject = (IWorldObject) navigation
1289 					.getCurrentTarget();
1290 			return new Percept(navigation.getState().getFlag(),
1291 					targetObject.getId());
1292 		}
1293 
1294 		// We are going to a location(x,y,z)
1295 		return new Percept(navigation.getState().getFlag(),
1296 				currentTarget.getLocation());
1297 	}
1298 
1299 	/**
1300 	 * <p>
1301 	 * Information about point in the map. Together these form a directed graph
1302 	 * that spans the entire map.
1303 	 * </p>
1304 	 * <p>
1305 	 * Type: Once
1306 	 * </p>
1307 	 * 
1308 	 * <p>
1309 	 * Syntax: navPoint(UnrealID, location(X,Y,Z), [NeigsUnrealID])
1310 	 * <ol>
1311 	 * <li>UnrealID: The unique id of this navpoint.</li>
1312 	 * <li>Location: The location of this navpoint in the map.</li>
1313 	 * <li>[NeigsUnrealID]: A list of Id's for the neighbouring navpoints that
1314 	 * are reachable from this navpoint.</li>
1315 	 * </ol>
1316 	 * </p>
1317 	 * *
1318 	 * 
1319 	 */
1320 	@AsPercept(name = "navPoint", multiplePercepts = true, filter = Type.ONCE)
1321 	public Collection<Percept> navPoint() {
1322 		Collection<NavPoint> navPoints = world.getAll(NavPoint.class).values();
1323 		List<Percept> percepts = new ArrayList<Percept>(navPoints.size());
1324 
1325 		for (NavPoint p : navPoints) {
1326 			percepts.add(new Percept(p.getId(), p.getLocation(), p
1327 					.getOutgoingEdges().keySet()));
1328 		}
1329 
1330 		return percepts;
1331 	}
1332 
1333 	/**
1334 	 * <p>
1335 	 * Information indicating at which navpoint weapons, ammo, and health can be
1336 	 * found.
1337 	 * </p>
1338 	 * <p>
1339 	 * Type: Once
1340 	 * </p>
1341 	 * 
1342 	 * <p>
1343 	 * Syntax: pickup(UnrealID, Label, ItempType)
1344 	 * <ul>
1345 	 * <li>UnrealID: The UnrealId of the nav point this pickup spot is placed
1346 	 * on.</li>
1347 	 * <li>Label: The category of the pickup.</li>
1348 	 * <li>UT2004Group: The type of the of the item located on the pickup.</li>
1349 	 * </ul>
1350 	 * </p>
1351 	 * 
1352 	 * 
1353 	 * <p>
1354 	 * Notes:
1355 	 * <ol>
1356 	 * <li>Depending on the game setting "weapon stay", there may not always be
1357 	 * a weapon present on a pick up point.</li>
1358 	 * <li>If "weapon stay" is enabled, a weapon can only be picked up if one of
1359 	 * the same type is not present in the bots inventory yet.</li>
1360 	 * <li>TODO: A full overview of which category Label belongs to which item
1361 	 * type.</li>
1362 	 * 
1363 	 * </ol>
1364 	 * </p>
1365 	 */
1366 	@AsPercept(name = "pickup", multiplePercepts = true, filter = Type.ONCE)
1367 	public Collection<Percept> pickup() {
1368 		Collection<Item> pickups = items.getKnownPickups().values();
1369 		Collection<Percept> percepts = new ArrayList<Percept>(pickups.size());
1370 
1371 		for (Item item : pickups) {
1372 			// Ignore dropped items && items placed manually.
1373 			// Pogamut does not consider the manually placed items to be
1374 			// dropped. See ticket #2487.
1375 			if (!item.isDropped() && item.getNavPoint() != null) {
1376 				percepts.add(new Percept(item.getNavPointId(), item.getType()
1377 						.getCategory(), item.getType()));
1378 			}
1379 		}
1380 		return percepts;
1381 	}
1382 
1383 	/**
1384 	 * <p>
1385 	 * Information indicating which pickup is visible.
1386 	 * </p>
1387 	 * <p>
1388 	 * Type: On change with negation
1389 	 * </p>
1390 	 * 
1391 	 * <p>
1392 	 * Syntax: pickup(UnrealID)
1393 	 * <ul>
1394 	 * <li>UnrealID: The UnrealId of the nav point this pickup spot is placed
1395 	 * on.</li>
1396 	 * </ul>
1397 	 * </p>
1398 	 */
1399 	@AsPercept(name = "pickup", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1400 	public Collection<Percept> visiblePickup() {
1401 		Collection<NavPoint> navPoints = world.getAll(NavPoint.class).values();
1402 		List<Percept> percepts = new ArrayList<Percept>(navPoints.size());
1403 
1404 		for (NavPoint p : navPoints) {
1405 			if (p.isVisible()) {
1406 				percepts.add(new Percept(p.getId()));
1407 			}
1408 		}
1409 
1410 		return percepts;
1411 	}
1412 
1413 	/**
1414 	 * <p>
1415 	 * Information about the location of the base. The opposing team will try to
1416 	 * steal the flag from this location. Your team must deliver any capture
1417 	 * flags to the base.
1418 	 * </p>
1419 	 * 
1420 	 * <p>
1421 	 * Type: Once
1422 	 * </p>
1423 	 * 
1424 	 * <p>
1425 	 * Syntax: base(Team, UnrealID)
1426 	 * <ul>
1427 	 * <li>Team: Either red or blue.</li>
1428 	 * <li>UnrealID: The UnrealId of the navpoint this flagbase is placed on.</li>
1429 	 * </ul>
1430 	 * </p>
1431 	 */
1432 	@AsPercept(name = "base", multiplePercepts = true, filter = Type.ONCE)
1433 	public Collection<Percept> base() {
1434 
1435 		Collection<FlagInfo> flags = game.getAllCTFFlagsCollection();
1436 		Collection<Percept> percepts = new ArrayList<Percept>(flags.size());
1437 		Collection<NavPoint> navPoints = world.getAll(NavPoint.class).values();
1438 
1439 		for (FlagInfo flag : flags) {
1440 			Team team = Team.valueOf(flag.getTeam());
1441 			NavPoint nav = DistanceUtils.getNearest(navPoints,
1442 					game.getFlagBase(team.id()));
1443 			percepts.add(new Percept(team, nav.getId()));
1444 		}
1445 
1446 		return percepts;
1447 
1448 	}
1449 
1450 	/**
1451 	 * <p>
1452 	 * Information about the type of game being played, the map and the score
1453 	 * required for winning the game.
1454 	 * </p>
1455 	 * 
1456 	 * 
1457 	 * <p>
1458 	 * Type: On Change
1459 	 * </p>
1460 	 * 
1461 	 * <p>
1462 	 * Syntax: game(Gametype, Map, TeamScoreLimit, RemainingTime)
1463 	 * <ul>
1464 	 * <li>Gametype: The type of game being played.</li>
1465 	 * <li>Map: The name of the map being played on.</li>
1466 	 * <li>TeamScoreLimit: Score needed to win the match. If the score is zero
1467 	 * or not reached by the end of the game, the team that has the highest
1468 	 * score when the time limit is reached wins.</li>
1469 	 * <li>RemainingTime: Time left in the game. If the score for both teams is
1470 	 * a tie, it is possible to go into over time.</li>
1471 	 * </ul>
1472 	 */
1473 	@AsPercept(name = "game", filter = Type.ON_CHANGE)
1474 	public Percept game() {
1475 		return new Percept(game.getGameType(), game.getMapName(),
1476 				game.getTeamScoreLimit(), game.getRemainingTime());
1477 	}
1478 
1479 	/**
1480 	 * <p>
1481 	 * Percept that provides information about the current state of the game.
1482 	 * </p>
1483 	 * 
1484 	 * <p>
1485 	 * Type: On change
1486 	 * </p>
1487 	 * 
1488 	 * <p>
1489 	 * Syntax: teamScore(TeamScore, OpponentTeamScore)
1490 	 * <ul>
1491 	 * <li>TeamScore score of the team this bot is on.</li>
1492 	 * <li>OpponentTeamScore score of the opponent team.</li>
1493 	 * </ul>
1494 	 * </p>
1495 	 * 
1496 	 * <p>
1497 	 * Notes
1498 	 * <ol>
1499 	 * <li>For CTF the score is the number of times the ag has been captured.</li>
1500 	 * <li>Once either team reaches the goal score from the Game- info percept,
1501 	 * the game is over.</li>
1502 	 * </ol>
1503 	 * </p>
1504 	 * 
1505 	 */
1506 	@AsPercept(name = "teamScore", filter = Type.ON_CHANGE)
1507 	public Percept teamScore() {
1508 		return new Percept(game.getTeamScore(info.getTeam()),
1509 				game.getTeamScore(1 - info.getTeam()));
1510 	}
1511 
1512 	/**
1513 	 * <p>
1514 	 * Description: Percept that provides information about the current state of
1515 	 * the flag.
1516 	 * </p>
1517 	 * 
1518 	 * <p>
1519 	 * Type: On change with negation.
1520 	 * </p>
1521 	 * 
1522 	 * <p>
1523 	 * Syntax: flagState(Team,FlagState)
1524 	 * <ul>
1525 	 * <li>Team: Either blue or red.</li>
1526 	 * <li>FlagState: State of the flag. Either home, held or dropped.</li>
1527 	 * </ul>
1528 	 * </p>
1529 	 * 
1530 	 * <p>
1531 	 * Notes:
1532 	 * <ol>
1533 	 * <li>
1534 	 * See also the flag percept</li>
1535 	 * </ol>
1536 	 * <p>
1537 	 * 
1538 	 */
1539 	@AsPercept(name = "flagState", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1540 	public Collection<Percept> flagState() {
1541 
1542 		Collection<FlagInfo> flags = game.getAllCTFFlagsCollection();
1543 		Collection<Percept> percepts = new ArrayList<Percept>(flags.size());
1544 
1545 		for (FlagInfo flag : flags) {
1546 			percepts.add(new Percept(Team.valueOf(flag.getTeam()), FlagState
1547 					.valueOfIgnoreCase(flag.getState())));
1548 		}
1549 
1550 		return percepts;
1551 
1552 	}
1553 
1554 	/**
1555 	 * <p>
1556 	 * Description: Provides information items the bot sees in the world.
1557 	 * </p>
1558 	 * 
1559 	 * <p>
1560 	 * Type: On change with negation.
1561 	 * </p>
1562 	 * 
1563 	 * <p>
1564 	 * Syntax: item(UnrealID, Label, ItemType, NavPointId)
1565 	 * </p>
1566 	 * <p>
1567 	 * Syntax: item(UnrealID, Label, ItemType, location(X,Y,Z)) when dropped.
1568 	 * </p>
1569 	 * 
1570 	 * <ul>
1571 	 * <li>UnrealID: The UnrealID of this item.</li>
1572 	 * <li>Label: The category of the pick up.</li>
1573 	 * <li>ItemType: The actual item type of the item located on the pickup.</li>
1574 	 * <li>NavPointId: The UnrealId of the navpoint this item is placed when
1575 	 * spawned.</li>
1576 	 * <li>Location: location in the world when this item is dropped.</li>
1577 	 * </ul>
1578 	 * </p>
1579 	 * 
1580 	 * <p>
1581 	 * Notes:
1582 	 * <ol>
1583 	 * <li>
1584 	 * TODO: A full over view of which category Label belongs to which item
1585 	 * type.</li>
1586 	 * </ol>
1587 	 * <p>
1588 	 * 
1589 	 */
1590 	@AsPercept(name = "item", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1591 	public Collection<Percept> item() {
1592 		Collection<Item> visibleItems = items.getVisibleItems().values();
1593 		Collection<Percept> percepts = new ArrayList<Percept>(
1594 				visibleItems.size());
1595 
1596 		for (Item item : visibleItems) {
1597 			// Pogamut does not consider the manually placed items to be
1598 			// dropped. See ticket #2487.
1599 			if (item.isDropped() || item.getNavPointId() == null) {
1600 				percepts.add(new Percept(item.getId(), item.getType()
1601 						.getCategory(), item.getType(), item.getLocation()));
1602 			} else {
1603 				percepts.add(new Percept(item.getId(), item.getType()
1604 						.getCategory(), item.getType(), item.getNavPointId()));
1605 			}
1606 		}
1607 
1608 		return percepts;
1609 	}
1610 
1611 	/**
1612 	 * <p>
1613 	 * Description: Percept provided when the flag is visible.
1614 	 * </p>
1615 	 * 
1616 	 * <p>
1617 	 * Type: On change with negation.
1618 	 * </p>
1619 	 * 
1620 	 * <p>
1621 	 * Syntax: flag(Team, UnrealId, location(X,Y,Z))
1622 	 * </p>
1623 	 * 
1624 	 * <ul>
1625 	 * <li>Team: Either red or blue.</li>
1626 	 * <li>UnrealId: The UnrealId of the player holding the flag, none when the
1627 	 * flag is not held.</li>
1628 	 * <li>Location: The location of the flag in the world.</li>
1629 	 * </ul>
1630 	 * </p>
1631 	 * 
1632 	 * <p>
1633 	 * Notes:
1634 	 * <ol>
1635 	 * <li>
1636 	 * See also the flagStatus percept.</li>
1637 	 * </ol>
1638 	 * <p>
1639 	 * 
1640 	 */
1641 	@AsPercept(name = "flag", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1642 	public Collection<Percept> flag() {
1643 
1644 		Collection<FlagInfo> flags = game.getAllCTFFlagsCollection();
1645 		Collection<Percept> percepts = new ArrayList<Percept>(flags.size());
1646 
1647 		for (FlagInfo flag : flags) {
1648 			if (flag.isVisible())
1649 				percepts.add(new Percept(Team.valueOf(flag.getTeam()), flag
1650 						.getHolder(), flag.getLocation()));
1651 		}
1652 
1653 		return percepts;
1654 	}
1655 
1656 	/**
1657 	 * <p>
1658 	 * Percept provided when another bot becomes visible to this bot.
1659 	 * </p>
1660 	 * 
1661 	 * <p>
1662 	 * Type: On change with negation.
1663 	 * </p>
1664 	 * 
1665 	 * <p>
1666 	 * Syntax: bot(UnrealId, Team, location(X,Y,Z), Weapon, FireMode)
1667 	 * </p>
1668 	 * 
1669 	 * <ul>
1670 	 * <li>UnrealId: Unique identifier for this bot assigned by Unreal.</li>
1671 	 * <li>Team: Either red or blue.</li>
1672 	 * <li>location(X,Y,Z): Location of the bot in the world.</li>
1673 	 * <li>Weapon: The weapon the bot is holding. TODO: Any of the following:</li>
1674 	 * <li>FireMode: Mode of shooting, either primary, secondary or none.</li>
1675 	 * </ul>
1676 	 * </p>
1677 	 * 
1678 	 * 
1679 	 */
1680 	@AsPercept(name = "bot", multiplePercepts = true, filter = Type.ON_CHANGE_NEG)
1681 	public Collection<Percept> bot() {
1682 		Collection<Player> visible = players.getVisiblePlayers().values();
1683 		Collection<Percept> wrapped = new ArrayList<Percept>(visible.size());
1684 
1685 		for (Player p : visible) {
1686 			wrapped.add(new Percept(p.getId(), p.getName(), Team.valueOf(p
1687 					.getTeam()), p.getLocation(), UT2004ItemType.getItemType(p
1688 					.getWeapon()), FireMode.valueOf(p.getFiring())));
1689 		}
1690 
1691 		return wrapped;
1692 	}
1693 
1694 	/**
1695 	 * <p>
1696 	 * Description: Percept provided when bot grabbed an udamage powerup.
1697 	 * </p>
1698 	 * 
1699 	 * <p>
1700 	 * Type: On change
1701 	 * </p>
1702 	 * 
1703 	 * <p>
1704 	 * Syntax: udamage(Time)
1705 	 * </p>
1706 	 * 
1707 	 * <ul>
1708 	 * <li>Time: Time in seconds (2 decimals)</li>
1709 	 * </ul>
1710 	 * 
1711 	 * @return
1712 	 */
1713 	@AsPercept(name = "udamage", filter = Type.ON_CHANGE)
1714 	public Percept udamage() {
1715 		return new Percept(info.hasUDamage() ? info.getRemainingUDamageTime()
1716 				: 0);
1717 	}
1718 }