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