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