View Javadoc

1   package nl.tudelft.pogamut.ut2004.agent.module.shooting.weapon;
2   
3   import nl.tudelft.pogamut.ut2004.agent.module.shooting.AbstractWeaponShooting;
4   import nl.tudelft.pogamut.ut2004.agent.module.shooting.WeaponShooting;
5   import nl.tudelft.pogamut.ut2004.agent.module.shooting.util.FacingUtil;
6   import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
7   import cz.cuni.amis.pogamut.ut2004.agent.module.sensomotoric.Weaponry;
8   import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentInfo;
9   import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.WeaponPref;
10  import cz.cuni.amis.pogamut.ut2004.bot.command.ImprovedShooting;
11  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
12  import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType;
13  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
14  
15  /**
16   * <p>
17   * Module to efficient work with the link gun. Will power up team mates when
18   * possible.
19   * </p>
20   * 
21   * <p>
22   * To power up a team mate the
23   * {@link ShockRifleShooting#shoot(WeaponPref, ILocated)} must be called with a
24   * target that is a friendly player. In which case the weaponPref will be
25   * ignored. The module will only shoot at team mates who are in less then
26   * {@link LinkGunShooting#LINK_GUN_SEC_MAX_RANGE} UT units away. To conserve
27   * ammo this shooting will not shoot at friendly players when they are not in
28   * range.
29   * </p>
30   * 
31   * <p>
32   * When facing a shielded player, the module will switch to secondary fire mode
33   * if the target is within secondary range or stop shooting all together.
34   * </p>
35   * 
36   * @author mpkorstanje
37   * 
38   */
39  public class LinkGunShooting extends AbstractWeaponShooting implements WeaponShooting {
40  
41  	/**
42  	 * Angle at which shield gun can deflect projectiles.
43  	 */
44  	protected static final int SHIELD_GUN_DEFLECT_ANGLE = 90;
45  
46  	/**
47  	 * Practical experiments show that the link guns secondary fire has a range
48  	 * of 1150UT units. When attached to a friendly player, the range is ~1500UT
49  	 * unit. Since we can't test attachment we use 1150UT units.
50  	 */
51  	protected static final int LINK_GUN_SEC_MAX_RANGE = 1150;
52  	/**
53  	 * Secondary mode preference.
54  	 */
55  	protected static final WeaponPref LINK_GUN_SECONDARY = new WeaponPref(ItemType.LINK_GUN, false);;
56  	/**
57  	 * Primary mode preference.
58  	 */
59  	protected static final WeaponPref LINK_GUN_PRIMARY = new WeaponPref(ItemType.LINK_GUN, true);
60  
61  	private static final double LINK_GUN_FACING_ANGLE = 10;
62  
63  	private static final double LINK_GUN_WIDE_FACING_ANGLE = 15;
64  
65  	public LinkGunShooting(UT2004Bot<?, ?, ?> bot, AgentInfo info, ImprovedShooting shoot, Weaponry weaponry) {
66  		super(bot, info, shoot, weaponry);
67  	}
68  
69  	@Override
70  	protected void shoot() {
71  
72  		// Wrong weapon, wait up.
73  		if (!isWeaponReady()) {
74  			return;
75  		}
76  
77  		// No target, no shoot.
78  		if (!hasTarget()) {
79  			shoot.stopShooting();
80  			return;
81  		}
82  
83  		// Not a player. Blast away.
84  		if (!(target instanceof Player)) {
85  			shoot.shoot(weaponPref, target);
86  			return;
87  		}
88  
89  		Player player = (Player) target;
90  
91  		// Target not visible, hold fire.
92  		if (!player.isVisible()) {
93  			shoot.stopShooting();
94  			return;
95  		}
96  
97  		// Assist friend, or hold fire if out of range, or shoot foe.
98  		if (info.isFriend(player)) {
99  			shootFriend(player);
100 			return;
101 		}
102 
103 		if (FacingUtil.isFacing2D(info, target, LINK_GUN_FACING_ANGLE)) {
104 			shoot.stopShooting();
105 			return;
106 		}
107 
108 		boolean targetFacing = FacingUtil.isFacing2D(player, agent, SHIELD_GUN_DEFLECT_ANGLE);
109 		boolean targetShieldGun = ItemType.SHIELD_GUN.equals(ItemType.getItemType(player.getWeapon()));
110 		boolean targetShielded = player.getFiring() == 2;
111 		boolean targetCanDeflect = targetShieldGun && targetFacing && targetShielded;
112 		boolean closeEnough = info.getLocation().getDistance(player.getLocation()) < LINK_GUN_SEC_MAX_RANGE;
113 
114 		if (targetCanDeflect && closeEnough) {
115 			shoot.shoot(LINK_GUN_SECONDARY, target);
116 		} else if (!targetCanDeflect && !closeEnough) {
117 			shoot.shoot(LINK_GUN_PRIMARY, target);
118 		} else if (!targetCanDeflect) {
119 			shoot.shoot(weaponPref, target);
120 		} else {
121 			shoot.stopShooting();
122 		}
123 
124 	}
125 
126 	protected void shootFriend(Player player) {
127 		if (canAssist(player) && !FacingUtil.isFacing2D(info, target, LINK_GUN_WIDE_FACING_ANGLE)) {
128 			shoot.shoot(LINK_GUN_SECONDARY, player);
129 		} else {
130 			shoot.stopShooting();
131 		}
132 	}
133 
134 	protected boolean canAssist(Player player) {
135 		if (player == null) {
136 			return false;
137 		}
138 
139 		boolean friend = info.isFriend(player);
140 		boolean hasLinkGun = ItemType.LINK_GUN.equals(ItemType.getItemType(player.getWeapon()));
141 		boolean closeEnough = info.getLocation().getDistance(player.getLocation()) < LINK_GUN_SEC_MAX_RANGE;
142 
143 		return friend && hasLinkGun && closeEnough;
144 	}
145 
146 	/**
147 	 * Primary fire mode is preferred for the link gun.
148 	 */
149 	@Override
150 	protected WeaponPref getDefaultWeaponPref() {
151 		return LINK_GUN_PRIMARY;
152 	}
153 
154 }