View Javadoc

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