/* * 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);} }