View Javadoc

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