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