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