View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2   
3   import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
4   import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
5   import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
6   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
7   import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
8   import cz.cuni.amis.pogamut.base3d.worldview.object.event.WorldObjectAppearedEvent;
9   import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
10  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.FlagInfo;
11  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
12  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ItemPickedUp;
13  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
14  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
15  
16  /**
17   * CTF module is encapsulating basic CTF-game logic. That is it tracks state of our/enemy flag and can quickly tells you
18   * whether you can score / your team can score / enemy team can score, etc... 
19   * 
20   * This info is available only for CTF games.
21   * 
22   * @author Jimmy
23   */
24  public class CTF extends SensorModule<UT2004Bot> {
25  	
26  	protected Self self;
27  	
28  	protected FlagInfo ourFlag;
29  	
30  	protected NavPoint ourBase;
31  
32  	protected FlagInfo enemyFlag;
33  	
34  	protected NavPoint enemyBase;
35  	
36  	/**
37  	 * Module is enabled ONLY for CTF games.
38  	 * 
39  	 * INITIALLY SET TO: false
40  	 */
41  	protected boolean enabled = false;
42  	
43  	/**
44  	 * Enabled/disabled based on the game that is currently running, see {@link GameInfoListener}.
45  	 * @param value
46  	 */
47  	protected void setEnabled(boolean value) {
48  		if (value == this.enabled) return;
49  		this.enabled = value;		
50  		if (this.enabled) {
51  			log.info("Module enabled, registering event listeners.");
52  		} else {
53  			log.info("Module disabled, removing event listeners.");			
54  		}		
55  	}
56  	
57  	// =======================
58  	// ENEMY FLAG/BASE METHODS
59  	// =======================
60  	
61  	/**
62  	 * Returns ENEMY flag. Available since first logic().
63  	 * @return
64  	 */
65  	public FlagInfo getEnemyFlag() {
66  		return enemyFlag;
67  	}
68  
69  	/**
70  	 * Returns ENEMY BASE navpoint. Available since first logic().
71  	 * @return
72  	 */
73  	public NavPoint getEnemyBase() {
74  		return enemyBase;
75  	}
76  	
77  	/**
78  	 * Whether enemy team may score == enemy flag is at home, alias for {@link CTF#isEnemyFlagHome()}.
79  	 * @return
80  	 */
81  	public boolean canEnemyTeamPossiblyScore() {
82  		return isEnemyFlagHome();
83  	}
84  	
85  	/**
86  	 * Whether enemy team can currently SCORE by carrying our flag into enemy (their) base == enemy flag is at home && some of enemy player is carrying our flag.
87  	 * @return
88  	 */
89  	public boolean canEnemyTeamScore() {
90  		return isEnemyFlagHome() && isEnemyTeamCarryingOurFlag();
91  	}
92  	
93  	/**
94  	 * Whether enemy team is currently carrying our flag, alias for {@link CTF#isOurFlagHeld()}.
95  	 * @return
96  	 */
97  	public boolean isEnemyTeamCarryingOurFlag() {
98  		return isOurFlagHeld();
99  	}
100 	
101 	/**
102 	 * ENEMY FLAG is safe at enemy home.
103 	 * @return
104 	 */
105 	public boolean isEnemyFlagHome() {
106 		return enemyFlag != null && enemyFlag.getState().toLowerCase().contains("home");
107 	}
108 	
109 	/**
110 	 * ENEMY FLAG IS LAYING SOMEWHERE!
111 	 * @return
112 	 */
113 	public boolean isEnemyFlagDropped() {
114 		return enemyFlag != null && enemyFlag.getState().toLowerCase().contains("dropped");
115 	}
116 	
117 	/**
118 	 * ENEMY FLAG is being carried by some team-mate.
119 	 * @return
120 	 */
121 	public boolean isEnemyFlagHeld() {
122 		return enemyFlag != null && enemyFlag.getState().toLowerCase().contains("held");
123 	}
124 	
125 	// =====================
126 	// OUR FLAG/BASE METHODS
127 	// =====================
128 	
129 	/**
130 	 * Returns OUR flag. Available since first logic().
131 	 * @return
132 	 */
133 	public FlagInfo getOurFlag() {
134 		return ourFlag;
135 	}
136 
137 	/**
138 	 * Returns OUR BASE navpoint. Available since first logic().
139 	 * @return
140 	 */
141 	public NavPoint getOurBase() {
142 		return ourBase;
143 	}
144 	
145 	/**
146 	 * Whether your team may score == your flag is at home, alias for {@link CTF#isOurFlagHome()}.
147 	 * @return
148 	 */
149 	public boolean canOurTeamPossiblyScore() {
150 		return isOurFlagHome();
151 	}
152 	
153 	/**
154 	 * Whether our team can currently SCORE by carrying enemy flag into our base == our flag is at home && some of my team-mate is carrying enemy flag.
155 	 * @return
156 	 */
157 	public boolean canOurTeamScore() {
158 		return isOurFlagHome() && isOurTeamCarryingEnemyFlag();
159 	}
160 	
161 	/**
162 	 * Whether this bot can currently SCORE == our flag is at home AND this bot is carrying the flag.
163 	 * @return
164 	 */
165 	public boolean canBotScore() {
166 		return isOurFlagHome() && isBotCarryingEnemyFlag();
167 	}
168 
169 	/**
170 	 * Whether this bot (you) is carrying enemy flag.
171 	 * @return
172 	 */
173 	public boolean isBotCarryingEnemyFlag() {
174 		return enemyFlag != null && isEnemyFlagHeld() && enemyFlag.getHolder() != null && enemyFlag.getHolder().equals(info.getId());
175 	}
176 	
177 	/**
178 	 * Whether our team is currently carrying enemy flag, alias for {@link CTF#isEnemyFlagHeld()}.
179 	 * @return
180 	 */
181 	public boolean isOurTeamCarryingEnemyFlag() {
182 		return isEnemyFlagHeld();
183 	}
184 	
185 	/**
186 	 * OUR FLAG is safe at home.
187 	 * @return
188 	 */
189 	public boolean isOurFlagHome() {
190 		return ourFlag != null && ourFlag.getState().toLowerCase().contains("home");
191 	}
192 	
193 	/**
194 	 * OUR FLAG IS LAYING SOMEWHERE!
195 	 * @return
196 	 */
197 	public boolean isOurFlagDropped() {
198 		return ourFlag != null && ourFlag.getState().toLowerCase().contains("dropped");
199 	}
200 	
201 	/**
202 	 * OUR FLAG is being carried by some enemy player.
203 	 * @return
204 	 */
205 	public boolean isOurFlagHeld() {
206 		return ourFlag != null && ourFlag.getState().toLowerCase().contains("held");
207 	}
208 
209 	/**
210 	 * Check whether the module is enabled. The module is enabled only for CTF games.
211 	 * @return
212 	 */
213 	public boolean isEnabled() {
214 		return enabled;
215 	}	
216 	
217 	/////////////////////////////////////////
218 	// GAME LISTENER
219 	/////////////////////////////////////////
220 	
221 	/**
222 	 * {@link ItemPickedUp} listener.
223 	 */
224 	protected class GameInfoListener implements IWorldEventListener<GameInfo>
225 	{
226 		/**
227 		 * Constructor. Registers itself on the given WorldView object.
228 		 * @param worldView WorldView object to listen to.
229 		 */
230 		public GameInfoListener(IWorldView worldView)
231 		{
232 			worldView.addEventListener(GameInfo.class, this);
233 		}
234 
235 		@Override
236 		public void notify(GameInfo event)
237 		{
238 			gameInfoSensed(event);
239 		}
240 
241 	}
242 
243 	public void gameInfoSensed(GameInfo gameInfo) {
244 		setEnabled(gameInfo.getGametype() != null && gameInfo.getGametype().toLowerCase().contains("ctf"));		
245 	}
246 	
247 	protected GameInfoListener gameInfoListener;
248 	
249 	/*========================================================================*/
250 	
251 	/////////////////////////////////////////
252 	// FLAG APPEARED LISTENER
253 	/////////////////////////////////////////
254 	
255 	protected class FlagUpdatedListener implements IWorldObjectEventListener<FlagInfo, WorldObjectUpdatedEvent<FlagInfo>>
256 	{
257 
258 		@Override
259 		public void notify(WorldObjectUpdatedEvent<FlagInfo> event)
260 		{
261 			flagAppeared(event.getObject());
262 		}
263 		
264 	}
265 
266 	public void flagAppeared(FlagInfo flag) {
267 		if (flag.getTeam() == info.getTeam()) {
268 			ourFlag = flag;
269 			log.info("Got our flag: " + flag);
270 		} else {
271 			enemyFlag = flag;
272 			log.info("Got enemy flag: " + flag);
273 		}		
274 		if (ourFlag != null && enemyFlag != null) {
275 			worldView.removeObjectListener(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener);
276 		}
277 	}
278 	
279 	protected FlagUpdatedListener flagUpdatedListener;
280 
281 	/*========================================================================*/
282 	
283 	/////////////////////////////////////////
284 	// SELF APPEARED LISTENER
285 	/////////////////////////////////////////
286 	
287 	protected class SelfUpdatedListener implements IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>>
288 	{
289 
290 		@Override
291 		public void notify(WorldObjectUpdatedEvent<Self> event)
292 		{
293 			selfAppeared(event.getObject());
294 		}
295 		
296 	}
297 
298 	public void selfAppeared(Self self) {
299 		this.self = self;	
300 		
301 		ourBase = null;
302 		enemyBase = null;
303 		
304 		for (NavPoint np : worldView.getAll(NavPoint.class).values()) {
305 			if (np.getId().getStringId().toLowerCase().contains("redflagbase")) {
306 				if (self.getTeam() == AgentInfo.TEAM_RED) {
307 					ourBase = np;
308 				} else {
309 					enemyBase = np;
310 				}
311 			} else
312 			if (np.getId().getStringId().toLowerCase().contains("blueflagbase")) {
313 				if (self.getTeam() == AgentInfo.TEAM_BLUE) {
314 					ourBase = np;
315 				} else {
316 					enemyBase = np;
317 				}
318 			}
319 			if (ourBase != null && enemyBase != null) break; 
320 		}
321 		
322 		worldView.removeObjectListener(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener);
323 	}
324 	
325 	protected SelfUpdatedListener selfAppearedListener;
326 	
327 	/*========================================================================*/
328 
329 	/** Agent info module. */
330 	public AgentInfo info;
331 	
332 	/**
333 	 * Constructor. Setups the memory module based on bot's world view.
334 	 * @param game game info module
335 	 */
336 	public CTF(UT2004Bot bot) {
337 		this(bot, new AgentInfo(bot));
338 	}
339 	
340 	/**
341 	 * Constructor. Setups the memory module based on bot's world view.
342 	 * @param bot owner of the module
343 	 * @param info agent info module
344 	 */
345 	public CTF(UT2004Bot bot, AgentInfo info) {
346 		super(bot);
347 		this.info = info;
348 		gameInfoListener = new GameInfoListener(bot.getWorldView());
349 		selfAppearedListener = new SelfUpdatedListener();
350 		worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener);
351 		flagUpdatedListener = new FlagUpdatedListener();
352 		worldView.addObjectListener(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener);
353 	}
354 	
355 	@Override
356 	protected void start(boolean startToPaused) {
357 		super.start(startToPaused);
358 		if (!worldView.isListening(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener)) {
359 			worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener);
360 		}
361 		if (!worldView.isListening(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener)) {
362 			worldView.addObjectListener(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener);
363 		}
364 	}
365 
366 	@Override
367 	protected void cleanUp() {
368 		super.cleanUp();
369 		ourFlag = null;
370 		enemyFlag = null;
371 		ourBase = null;
372 		enemyBase = null;
373 		setEnabled(false);
374 		if (!worldView.isListening(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener)) {
375 			worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, selfAppearedListener);
376 		}
377 		if (!worldView.isListening(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener)) {
378 			worldView.addObjectListener(FlagInfo.class, WorldObjectUpdatedEvent.class, flagUpdatedListener);
379 		}
380 	}
381 
382 }