/*
* ModdedBot.java
* by: Vuen
*
* version 1.1
* Last edited on December 5, 2003
*/
package mod;
import robocode.*;
import java.util.*;
import robocode.exception.EventInterruptedException;
/* This is the robot template for creating a Robocode mod. Robots playing your
* mod should extend this rather than AdvancedRobot; you can then add any
* functionality you like.
*/
public class ModdedBot extends AdvancedRobot {
//These are pr ivate variables that hold needed info
private boolean isInit;
private Vector events; //Holds all robot events
private Vector eventsfake; //Holds fake events before they are added to events vector
/* This is the initialization method of your robot. It gets called at the
* start of every round. The robot usually can perform a few calculations
* before this is called, but you should not have to worry; if you would
* like this to be guaranteed to be called before the robot does something,
* an example of this is below.
*/
private void init() {
if (isInit) return;
isInit = true;
super.addCustomEvent(new Condition("ModdedBot", 99) {public boolean test() {events(); return false;}});
eventsfake = new Vector();
//Add any code you would like that initializes your mod in here.
}
/* Suppose we would like to guarantee that the robot be initialized before
* the robot uses getHeading():
*/
public double getHeading() {
init();
return super.getHeading();
}
/* You can delete this example method if you like. */
/* This method handles the events in the robot. Whatever you would like the
* mod to do upon receiving an event, do it here. Do NOT override the
* onXXX(XXXEvent) methods.
*/
private void events() {
if (events != null) events.clear();
events = super.getAllEvents();
eventsfake.clear();
super.clearAllEvents();
Iterator i = events.iterator();
while (i.hasNext()) {
Event event = (Event)i.next();
//This is where we handle the events we want to handle.
//This contains sample code to remove certain scans, and
// to catch robot deaths. Remove the below sample code when
// you create your mod.
if (event instanceof ScannedRobotEvent) {
//Suppose we would like to disallow a robot from scanning a ScoreBot:
ScannedRobotEvent scan = (ScannedRobotEvent)event;
if (scan.getName().indexOf("ScoreBot") > -1)
i.remove(); //remove the event from the events vector
//it is now impossible for the robot to receive ScoreBot scans.
} else if (event instanceof BulletMissedEvent) {
//Suppose we want to do something when a bullet goes offscreen:
BulletMissedEvent miss = (BulletMissedEvent)event;
//do stuff using this event
//Note that the robot will still receive this event even if we used it.
} else if (event instanceof BulletHitEvent) {
//Suppose we want to generate a RobotDeathEvent instead of a
// BulletHitEvent when the enemy's bullet hits another robot
BulletHitEvent hit = (BulletHitEvent)event;
//create new RobotDeathEvent
Event newevent = new RobotDeathEvent(hit.getName());
//DON'T FORGET to set the priority and time of the event!
newevent.setPriority(getEventPriority("RobotDeathEvent"));
newevent.setTime(getTime());
//add RobotDeathEvent to eventsfake (NOT events)
eventsfake.add(newevent);
//remove the BulletHitEvent
i.remove();
//The robot will now receive a RobotDeathEvemt instead of a
// BulletHitEvent; the robot will not be able to tell the
// difference between the real RobotDeathEvents and the ones
// created by the mod.
}
}
/**Here you can create any fake events you would like. You can also
* make your own event classes, or make event classes that extend
* some of the events that already exist. I suggest you package custom
* event classes in the same package as your ModdedBot. Whatever events
* you create, add them to the eventsfake Vector when you want them to
* be sent to the robot.
*/
events.addAll(eventsfake);
eventsfake.clear();
Collections.sort(events);
}
/* These variables handle prioritization. */
private boolean isHandlingEvents = false;
private int currentEventPriority = Integer.MIN_VALUE;
private boolean[] interruptible = new boolean[101];
/* This method handles setting interruptibility. Since we hold all blocking
* calls from the robot, we have to handle interruptibility manually.
*/
public void setInterruptible(boolean interruptible) {
init();
if (!isHandlingEvents) return;
this.interruptible[currentEventPriority] = interruptible;
}
/* This event parses the events and calls the proper event handlers.
*
* This method is configured to automatically handle interruptibility the
* same way Robocode does. An error is thrown through the robot's event
* handler and caught by ModdedBot to interrupt an event.
*/
private void dump() {
//set this to true. we shouldn't have to worry about setting it false
// again because from then on we always handle events.
isHandlingEvents = true;
if (events == null) return;
while (events.size() > 0) {
Event event = (Event)events.firstElement();
//since the list is sorted, all events remaining are lower priority
// than the current one, so we cannot interrupt it and so we can
// stop dumping events.
if (event.getPriority() < currentEventPriority)
break;
//we need to interrupt the current event
if (event.getPriority() == currentEventPriority && interruptible[currentEventPriority]) {
interruptible[currentEventPriority] = false;
throw new EventInterruptedException(event.getPriority());
}
//we haven't interrupted the current event; since the list is
// sorted, all events after this one will have the same or lower
// priority, so we can stop dumping events.
if (event.getPriority() == currentEventPriority)
break;
//we can now remove the event from the vector. we remove it after
// interrupting so that we don't remove the event that we
// want to interrupt with!
events.remove(0);
int oldEventPriority = currentEventPriority;
currentEventPriority = event.getPriority();
try {
//If you have created any of your own custom event classes, add them
// here BEFORE the rest of the events get parsed, and change the
// next line to else if so that any events you have extended won't
// fire twice.
//If you haven't created any custom event classes, you don't need
// to modify this method.
if (event instanceof ScannedRobotEvent)
onScannedRobot((ScannedRobotEvent)event);
else if (event instanceof RobotDeathEvent)
onRobotDeath((RobotDeathEvent)event);
else if (event instanceof HitRobotEvent)
onHitRobot((HitRobotEvent)event);
else if (event instanceof HitWallEvent)
onHitWall((HitWallEvent)event);
else if (event instanceof HitByBulletEvent)
onHitByBullet((HitByBulletEvent)event);
else if (event instanceof BulletHitEvent)
onBulletHit((BulletHitEvent)event);
else if (event instanceof BulletMissedEvent)
onBulletMissed((BulletMissedEvent)event);
else if (event instanceof BulletHitBulletEvent)
onBulletHitBullet((BulletHitBulletEvent)event);
else if (event instanceof CustomEvent)
onCustomEvent((CustomEvent)event);
else if (event instanceof SkippedTurnEvent)
onSkippedTurn((SkippedTurnEvent)event);
else if (event instanceof WinEvent)
onWin((WinEvent)event);
else if (event instanceof DeathEvent)
onDeath((DeathEvent)event);
else
printError("Unknown Event!! This event is unhandled: " + event.getClass().getName());
} catch (EventInterruptedException e) {
//we dropped down the stack, and we resume event dumping with
// the new events vector using the old dump method.
}
currentEventPriority = oldEventPriority;
}
events.clear();
events = null;
}
/* This is your go method. This is always called at the end of every tick,
* after the robot has performed its actions.
*/
private void go() {
init();
//Put anything you would like your mod to do each tick in here.
}
/* The following chunk of methods provides the functionality of all the
* getXXXEvents methods in the robot. Since we parse the events manually,
* we have to rebuild these methods to allow the extending robot to use
* them. If you have any custom event classes, you should add a
* getXXXEvents for your class to provide the robot with this function.
* Note that if you extend any of the existing events, they will NOT be
* returned by the getXXXEvents method of the class they extend; you can
* modify the parseEvents method to provide this functionality if you want.
*
* If you have not created any custom event classes, you do not need to
* modify this code.
*/
public Vector getAllEvents() {return events;}
public void clearAllEvents() {events.clear(); events = null;}
public Vector getScannedRobotEvents() {return parseEvents("robocode.ScannedRobotEvent");}
public Vector getRobotDeathEvents() {return parseEvents("robocode.RobotDeathEvent");}
public Vector getHitRobotEvents() {return parseEvents("robocode.HitRobotEvent");}
public Vector getHitWallEvents() {return parseEvents("robocode.HitWallEvent");}
public Vector getHitByBulletEvents() {return parseEvents("robocode.HitByBulletEvent");}
public Vector getBulletHitEvents() {return parseEvents("robocode.BulletHitEvent");}
public Vector getBulletMissedEvents() {return parseEvents("robocode.BulletMissedEvent");}
public Vector getBulletHitBulletEvents() {return parseEvents("robocode.BulletHitBulletEvent");}
private Vector parseEvents(String type) {
Vector newevents = new Vector();
for (int i = 0; i < events.size(); i++) {if (events.get(i).getClass().getName().equals(type)) newevents.add(events.get(i));}
return newevents;
}
public void addCustomEvent(Condition condition) {
init(); //make sure our condition is first
super.addCustomEvent(condition);
}
/* Here's the fun part: you can now add any mod methods to the robot you
* want! Suppose the robot has a powerup, and we want it to return the time
* remaining on the powerup:
*/
private long powerUpTime;
public long getPowerUpTime() {
return powerUpTime;
}
/* You can see here that you can add to your mod any method you could
* possibly want the extending robot to call. Note that for methods like
* this, you would put in the go() method the code to handle the amount
* of time remaining on the powerup.
*/
/* This is just a debugger method; it will call whenever an error occurs
* within the mod. You can call this or remove this or do whatever you want
* with it; debug your mod however you like.
*/
private void printError(String text) {
System.out.println("[" + getTime() + "] Mod Error! " + text);
}
/* The following block of code is what allows the extending robot to use
* any blocking calls they wish, and still allow the mod to get a go()
* every tick. You should not need to modify any of the below code, unless
* you want to prevent the robot from performing any of these actions.
*/
public void execute() {
go();
super.execute();
dump();
}
public void doNothing() {execute();}
public void scan() {
go();
super.scan();
dump();
}
public void fire(double power) {
go();
super.fire(power);
dump();
}
public Bullet fireBullet(double power) {
go();
Bullet bullet = super.fireBullet(power);
dump();
return bullet;
}
public void ahead(double distance) {
setAhead(distance);
while (getDistanceRemaining() > 0) {
scan();
}
}
public void back(double distance) {ahead(-distance);}
public void turnRightRadians(double angle) {
setTurnLeftRadians(angle);
while (getTurnRemaining() != 0) {
scan();
}
}
public void turnLeftRadians(double angle) {turnRightRadians(-angle);}
public void turnRight(double angle) {turnRightRadians(Math.toRadians(angle));}
public void turnLeft(double angle) {turnRight(-angle);}
public void turnGunRightRadians(double angle) {
setTurnGunRightRadians(angle);
while (getGunTurnRemaining() != 0) {
scan();
}
}
public void turnGunLeftRadians(double angle) {turnGunRightRadians(-angle);}
public void turnGunRight(double angle) {turnGunRightRadians(Math.toRadians(angle));}
public void turnGunLeft(double angle) {turnGunRight(-angle);}
public void turnRadarRightRadians(double angle) {
setTurnRadarRightRadians(angle);
while (getRadarTurnRemaining() != 0) {
scan();
}
}
public void turnRadarLeftRadians(double angle) {turnRadarRightRadians(-angle);}
public void turnRadarRight(double angle) {turnRadarRightRadians(Math.toRadians(angle));}
public void turnRadarLeft(double angle) {turnRadarRight(-angle);}
}