/* PairTrader.java - A multiport pair trading script for SWATH (http://www.swath.net) Copyright (C) 2003 Zamfir (swather@zamfir.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. I'd like to thank the following people for unknowingly letting me steal code and ideas: Vito Corleone (for VitoTrade.java) Cryptkeepr (for code, ideas, and being there) Reaper (for being always willing to test my scripts) Still left to do: Port trading along the way to maximum credits. Better scanning along the way. Prevent stumbling onto enemny figs. Calculate an optimum route between all the ports using distance between each one. Revision History: =============================================================== 04-10-2003 Initial version 04-11-2003 Added tracking of credits earned */ import com.swath.*; import com.swath.cmd.*; import java.io.*; import java.util.*; public class PairTrader extends UserDefinedScript { protected Parameter m_parHomeBase; protected Parameter m_parFigsDropNum; protected Parameter m_parFigsDropType; protected Parameter m_parQuit; protected Parameter m_parVerbosity; // Output verbose output to console protected Parameter m_parPPList; private int iStartTotalCredits; private int iStartTotalTurns; private static final int MIN_REMAINING_TURNS = 100; private static final int DEFAULT_FIG_DROP_NUM = 1; private static final int DEFAULT_FIG_DROP_TYPE = Swath.TOLL_FTRS; private static final boolean DEFAULT_VERBOSITY = false; private static final String TITLE = "Pair Trader"; private static final String DESCRIPTION = "Pair Port Trader script - version 1.02"; private String m_strFile; public String getName() { return TITLE; } public String getDescription() { return DESCRIPTION; } public boolean initScript() throws Exception { // Check that we are at the correct prompt if (!atPrompt(Swath.COMMAND_PROMPT)) { MessageBox.exec("You must be at the command prompt.","Error", MessageBox.ICON_ERROR, MessageBox.TYPE_OK); return false; } // number of figs to drop in each sector m_parFigsDropNum = new Parameter("Number of figs to drop:"); m_parFigsDropNum.setType(Parameter.INTEGER); m_parFigsDropNum.setInteger(DEFAULT_FIG_DROP_NUM); m_parFigsDropNum.setHelpText("Sets figs in each sector along the way"); registerParam(m_parFigsDropNum); // type of figs to drop m_parFigsDropType = new Parameter("Type of figs to drop:"); m_parFigsDropType.setType(Parameter.CHOICE); m_parFigsDropType.addChoice(Swath.TOLL_FTRS,"Toll"); m_parFigsDropType.addChoice(Swath.DEFENSIVE_FTRS,"Defensive"); m_parFigsDropType.addChoice(Swath.OFFENSIVE_FTRS,"Offensive"); m_parFigsDropType.setCurrentChoice(DEFAULT_FIG_DROP_TYPE); m_parFigsDropType.setHelpText("Sets the type of figs to drop"); registerParam(m_parFigsDropType); // return to home base m_parHomeBase = new Parameter("Return to this sector when done:"); m_parHomeBase.setType(Parameter.INTEGER); m_parHomeBase.setIntegerRange(0,Swath.main.sectors()); m_parHomeBase.setInteger(Swath.main.currSector()); registerParam(m_parHomeBase); m_parQuit = new Parameter("Quit when done:"); m_parQuit.setType(Parameter.BOOLEAN); m_parQuit.setBoolean(false); m_parQuit.setHelpText("Quit out of game when done trading"); registerParam(m_parQuit); m_parVerbosity = new Parameter("Verbose output to console:"); m_parVerbosity.setType(Parameter.BOOLEAN); m_parVerbosity.setBoolean(true); registerParam(m_parVerbosity); m_parPPList = new Parameter("Pair Port List file:"); m_parPPList.setType(Parameter.STRING); m_parPPList.setString("PairTrader-"+Swath.main.gameName()+".txt"); m_parPPList.setHelpText("Return to this sector when done trading"); registerParam(m_parPPList); iStartTotalCredits = Swath.you.credits(); iStartTotalTurns = Swath.you.turns(); return true; } public void endScript(boolean finished) throws Exception { PrintTrace.exec("============== Pair Trader Totals =============="); PrintTrace.exec("Total Credits Earned: " + String.valueOf(Swath.you.credits() - iStartTotalCredits)); PrintTrace.exec("Total Turns Used: " + String.valueOf(iStartTotalTurns - Swath.you.turns())); PrintTrace.exec("Credits per turn: " + String.valueOf((Swath.you.credits() - iStartTotalCredits) / (iStartTotalTurns - Swath.you.turns()))); } public boolean runScript() throws Exception { // keep track of how much we make boolean bQuit = false; // read in the port pairs file String strFile = Swath.main.gamePath()+"\\"+m_parPPList.getString(); PrintTrace.exec("PPLISTFILE = " + strFile); int [] brPPList = ReadPPList(strFile); PrintTrace.exec("Done reading Pair Port List file"); for (int i = 0; i < (brPPList.length / 2); i += 2) { int iSector1, iSector2; Sector Sector1, Sector2; if (brPPList[i] == 0) { // kick out when we reach the end of the list bQuit = true; break; } iSector1 = brPPList[i]; iSector2 = brPPList[i+1]; PrintTrace.exec("Port Pair trading: " + String.valueOf(brPPList[i]) + " and " + String.valueOf(brPPList[i+1])); // update the port statics before we attempt to port at it EnterComputer.exec(); PortReport.exec(iSector1); PortReport.exec(iSector2); LeaveComputer.exec(); Sector1 = Swath.getSector(iSector1); Sector2 = Swath.getSector(iSector2); int iStartCredits = Swath.you.credits(); int iStartTurns = Swath.you.turns(); while (true) { if (Swath.you.turns() < MIN_REMAINING_TURNS) { PrintText.exec("Minimum turns remaining"); bQuit = true; break; } // now that we have currenct info check if the port has got stuff if ((!CheckPort(Sector1)) || (!CheckPort(Sector2))) { PrintTrace.exec("Port values too low. Moving to next pair..."); break; } // before we move to the port, lets check that the stuff currently in our holds can be traded there // if not we have to dump it if (IsCargoGood(Sector1)) { // dont have to do anything, we will trade when we get there } else if (IsCargoGood(Sector2)) { // if the cargo is good at the next paired port, switch them around Sector secTemp = Sector1; Sector1 = Sector2; Sector2 = secTemp; } else { // the current cargo cannot be traded at either one of the next sectors, so we must dump it // this should only occur when you are mixing port types PrintTrace.exec("Jettisoned cargo!"); JettisonCargo.exec(); } // move the the port sector if (! MoveToSector(Sector1)) { break; } DisplaySector.exec(); // trade at this port if (! TradeAtCurrentPort(Sector1)) { break; } // move the the paired port if (! MoveToSector(Sector2)) { break; } DisplaySector.exec(); // trade at this port if (! TradeAtCurrentPort(Sector2)) { break; } } PrintTrace.exec("Pair port credits earned: " + String.valueOf(Swath.you.credits() - iStartCredits)); PrintTrace.exec("Pair port turns used: " + String.valueOf(iStartTurns - Swath.you.turns())); if ((iStartTurns - Swath.you.turns()) > 0) { PrintTrace.exec("Credits per turn: " + String.valueOf((Swath.you.credits() - iStartCredits) / (iStartTurns - Swath.you.turns()))); } if (bQuit) { // break out of list, cause when you gotta go, you gotta go break; } } // move back home if we want to if (m_parHomeBase.getInteger() != 0) { // turn off dropping figs, we dont want to lead anyone back here m_parFigsDropNum.setInteger(0); MoveToSector(Swath.getSector(m_parHomeBase.getInteger())); } // quit out of the game if the users wants too if (m_parQuit.getBoolean()) { QuitTW.exec(); } return true; } public int [] ReadPPList(String strFile) throws Exception { BufferedReader listin; // we should only really need at most half of these, // but lets be lazy int [] PortList = new int[Swath.main.sectors()+1]; // load ugly.txt if it exists into memory if ( new File(strFile).exists() ) { listin = new BufferedReader(new FileReader(strFile)); String strLine; int i = 0; while ((strLine = listin.readLine()) != null) { // PrintTrace.exec(strLine); strLine = strLine.trim(); // ignore bad/comment lines if ((strLine.length() < 3) || (strLine.charAt(0) == '=')) { // PrintTrace.exec("Ignored"); continue; } String strPort1 = strLine.substring(0,strLine.indexOf('-')); strPort1 = strPort1.trim(); // PrintTrace.exec("strPort1 = " + strPort1); // PrintTrace.exec("next - is at " + String.valueOf(strLine.indexOf('-'))); // PrintTrace.exec("next ( is at " + String.valueOf(strLine.indexOf('('))); String strPort2 = strLine.substring(strLine.indexOf('-')+1,strLine.indexOf('(')); strPort2 = strPort2.trim(); // PrintTrace.exec("strPort2 = " + strPort2); PortList[i] = Integer.parseInt(strPort1); PortList[i+1] = Integer.parseInt(strPort2); i += 2; } listin.close(); } else { MessageBox.exec("Input file " + strFile+ " not found","Error", MessageBox.ICON_ERROR, MessageBox.TYPE_OK); return null; } return PortList; } public boolean IsCargoGood(Sector currSector) throws Exception { int fuel = Swath.ship.fuel(); // Fuel Onboard int org = Swath.ship.organics(); // Organics Onboard int equ = Swath.ship.equipment(); // Equipment Onboard switch (currSector.portClass()) { case 1: // BSS if ((fuel > 0) || (org > 0)) return true; break; case 2: // BSB if ((fuel > 0) || (equ > 0)) return true; break; case 3: // SBB if ((org > 0) || (equ > 0)) return true; break; case 4: // SSB if (equ > 0) return true; break; case 5: // SBS if (org > 0) return true; break; case 6: // BSS if (fuel > 0) return true; break; case 8: // BBB return true; } return false; } public boolean MoveToSector(Sector destSector) throws Exception { int iCurLoc; Sector currSector = Swath.sector; // Keep plotting course, and moving, until we've reached our destination EnterComputer.exec(); Swath.main.currSector(); Sector [] currCourse = PlotCourse.exec(currSector,destSector); LeaveComputer.exec(); // PlotCourse returns an empty array if the destination couldnt be reached if (currCourse.length == 0) { PrintTrace.exec("Invalid destination sector"); return false; } int seccount = 1; while (Swath.sector.sector() != destSector.sector()) { //drop a toll fig in every sector if ((m_parFigsDropNum.getInteger() > 0) && // if we are dropping figs (currSector.fighters() == 0) && // and the sector doesnt already have any (currSector.spaceName().equals("The Federation.") == false) && // and we are not in fedspace (Swath.ship.fighters() > 0)) { // and we have some figs on us //then lay a toll fighter down DropTakeFighters.exec(m_parFigsDropNum.getInteger(),Swath.CORPORATE,m_parFigsDropType.getCurrentChoice()); } // check if we are almost out of turns if (Swath.you.turns() < MIN_REMAINING_TURNS) { return false; } // otherwise lets keep moving Move.exec(currCourse[seccount]); // increment our place in the array seccount++;; } //end while // signal that we made it return true; } // End MoveToSector public boolean TradeAtCurrentPort(Sector currSector) throws Exception { int fuel = Swath.ship.fuel(); // Fuel Onboard int org = Swath.ship.organics(); // Organics Onboard int equ = Swath.ship.equipment(); // Equipment Onboard int warps = 0; // Storage for warps out boolean bTradeOk = false; // determine if the trading went okay // check that the port is available if (currSector.portStatus() != Sector.PORT_AVAILABLE) { PrintTrace.exec("Port in " + String.valueOf(currSector.sector()) + "is not available"); return false; } // now that we have currenct info check if the port has got stuff if (! CheckPort(currSector)) { return false; } // if ship is empty if (Swath.ship.emptyHolds() == Swath.ship.holds()) // Empty ship { switch (currSector.portClass()) { case 1: TradeAtClassOne(); break; case 5: TradeAtClassFive(); break; case 6: TradeAtClassSix(); break; case 7: TradeAtClassSeven(); break; case 2: TradeAtClassTwo(); break; case 4: TradeAtClassFour(); break; case 3: TradeAtClassThree(); break; default: break; } // we are full up with stuff being sold here, so we might as well keep moving on // PrintTrace.exec("Ship was empty, traded and now moving on"); return true; } if (fuel > 0) // ship has fuel on board { switch (currSector.portClass()) { case 1: TradeAtClassOne(); break; case 2: TradeAtClassTwo(); break; case 6: TradeAtClassSix(); break; case 8: TradeAtClassEight(); break; default: break; } // update these in case we trade some more org = Swath.ship.organics(); equ = Swath.ship.equipment(); } if (org > 0)// ship has organics on board { switch (currSector.portClass()) { case 1: TradeAtClassOne(); break; case 3: TradeAtClassThree(); break; case 5: TradeAtClassFive(); break; case 8: TradeAtClassEight(); break; default: break; } // update these in case we trade some more equ = Swath.ship.equipment(); } if (equ > 0) // ship has equipment on board { switch (currSector.portClass()) { case 2: TradeAtClassTwo(); break; case 3: TradeAtClassThree(); break; case 4: TradeAtClassFour(); break; case 8: TradeAtClassEight(); break; default: break; } } return true; } public boolean CheckPort(Sector currSector) throws Exception { int [] portPercents = currSector.portPercentages(); int [] portAmounts = currSector.portAmounts(); boolean bRtn = true; for (int i = 0; i < 3; i++) { // if (portPercents[i] < 15) { if (portAmounts[i] < Swath.ship.holds()) { bRtn = false; } } // PrintTrace.exec("CheckPort returning " + String.valueOf(bRtn)); return bRtn; } public void TradeAtClassOne() throws Exception // class 1 port { int fuel = Swath.ship.fuel(); int org = Swath.ship.organics(); int equ = Swath.ship.holds(); Trade.exec(-fuel, -org, equ); } public void TradeAtClassTwo() throws Exception // class 2 port { int fuel = Swath.ship.fuel(); int org = Swath.ship.holds(); int equ = Swath.ship.equipment(); Trade.exec(-fuel, org, -equ); } public void TradeAtClassThree() throws Exception // class 3 port { int fuel = Swath.ship.holds(); int org = Swath.ship.organics(); int equ = Swath.ship.equipment(); Trade.exec(fuel, -org, -equ); } public void TradeAtClassFour() throws Exception // 1,5,6,7 { int fuel = Swath.ship.fuel(); int org = Swath.ship.holds(); int equ = Swath.ship.equipment(); Trade.exec(fuel, org, -equ); } public void TradeAtClassFive() throws Exception // 1,2,6,8 { int fuel = Swath.ship.fuel(); int org = Swath.ship.organics(); int equ = Swath.ship.holds(); Trade.exec(fuel, -org, equ); } public void TradeAtClassSix() throws Exception // Class 2, 6 { int fuel = Swath.ship.fuel(); int org = Swath.ship.organics(); int equ = Swath.ship.holds(); Trade.exec(-fuel, org, equ); } public void TradeAtClassSeven() throws Exception // Class 1, 6 { int fuel = Swath.ship.fuel(); int org = Swath.ship.organics(); int equ = Swath.ship.holds(); Trade.exec(fuel, org, equ); } public void TradeAtClassEight() throws Exception // Class 1,3,5,8 { int fuel = Swath.ship.fuel(); int org = Swath.ship.organics(); int equ = Swath.ship.equipment(); Trade.exec(-fuel, -org, -equ); } }