package equipment;
import static dcpu.DcpuConstants.REG_A;
import static dcpu.DcpuConstants.REG_B;
import static dcpu.DcpuConstants.REG_C;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import physics.Body;
import ships.Equipment;
import ships.Ship;
import dcpu.CpuWatcher;
import dcpu.Dcpu;
import dcpu.Hardware;
import env.Beacon;
import env.Ncn450;
import env.Space;
public class BeaconTracker implements Equipment {
int strength;
int trackingSlots;
char trackingIds[];
private char hwid;
private Ship ship;
public BeaconTracker(int strength, int trackingSlots, char hwid) {
super();
this.strength = strength;
this.trackingSlots = trackingSlots;
this.trackingIds = new char[trackingSlots];
this.hwid = hwid;
}
public void addedTo(Ship s) {
this.ship = s;
s.addPluginHardware(hwid, new Hardware() {
public void query(Dcpu parent) {
parent.queryResult(0xEA9C6232, 0x32610000 | strength
| (trackingSlots << 8), 8);
}
public void plugged_in(Dcpu parent, char id) {
}
public void interrupted(Dcpu parent) {
if (parent.regs.gp[REG_A] == (char) 0) {
fullScan(parent);
} else if (parent.regs.gp[REG_A] == (char) 1) {
lookup(parent, parent.regs.gp[REG_B], ship.me);
} else if (parent.regs.gp[REG_A] == (char) 2) {
startTrack(parent, parent.regs.gp[REG_B],
parent.regs.gp[REG_C]);
}
}
private void startTrack(final Dcpu parent, final char beacon,
final char id) {
if (id < trackingSlots) {
parent.regs.gp[REG_A] = (char) 0;
CpuWatcher w = new CpuWatcher() {
int cycles = 40;
public void cpu_changed(Dcpu cpu, long cyclesAdvanced,
boolean idle) {
cycles -= cyclesAdvanced;
if (cycles <= 0) {
final CpuWatcher that = this;
parent.runInCpuThread(new Runnable() {
public void run() {
parent.removeWatcher(that);
trackingIds[id] = beacon;
}
});
}
}
};
parent.addWatcher(w);
} else {
parent.regs.gp[REG_A] = 0x4;
}
parent.cyclecnt += 4;
}
private void lookup(Dcpu parent, char id, Body self) {
boolean fast = false;
for (int i = 0; i < trackingIds.length; i++) {
if (id == trackingIds[i])
fast = true;
}
parent.cyclecnt += fast ? 4 : 40;
ship.power.sink(fast ? 0 : 15);
Beacon lookingUp = null;
for (Beacon b : ship.space.beacons()) {
if (b.id() == id) {
if (lookingUp == null) {
lookingUp = b;
} else {
if (b.apparentStrength(ship.me.x, ship.me.y, strength) >
lookingUp.apparentStrength(ship.me.x, ship.me.y, strength)) {
lookingUp = b;
}
}
}
}
char addr = parent.regs.gp[REG_C];
if (lookingUp == null) {
parent.memory.set((char) (addr+5), (char)0x1);
return;
}
int apparentStr = lookingUp.apparentStrength(ship.me.x,
ship.me.y, strength);
if (apparentStr==-1) {
parent.memory.set((char) (addr+5), (char)0x2);
} else if (apparentStr > 0) {
parent.memory.set((char) (addr+5), (char)0);
char strOctets = (char) (lookingUp.strength() << 8 | apparentStr);
parent.memory.set(addr++, (char)strOctets);
float fheading = ship.me.headingTo(lookingUp.me);
Ncn450 heading = new Ncn450(fheading);
parent.memory.set(addr++, heading.upper);
parent.memory.set(addr++, heading.lower);
Body next = ship.me.predictNextState();
Body beaconNext = lookingUp.me.predictNextState();
float nfheading = next.headingTo(beaconNext);
Ncn450 av = new Ncn450((nfheading - fheading) * 1000 / Space.MS_PER_TICK);
parent.memory.set(addr++, av.upper);
parent.memory.set(addr++, av.lower);
} else {
parent.memory.set((char) (addr+5), (char)1);
}
}
private void fullScan(Dcpu parent) {
ArrayList<Beacon> beacons = new ArrayList<>();
beacons.addAll(ship.space.beacons());
Collections.sort(beacons, new Comparator<Beacon>() {
public int compare(Beacon b1, Beacon b2) {
return b1.apparentStrength(ship.me.x, ship.me.y, strength)-
b2.apparentStrength(ship.me.x, ship.me.y, strength);
}
});
parent.cyclecnt+=20;
char addr = parent.regs.gp[REG_C];
for (int i=0; i<parent.regs.gp[REG_B] && i<beacons.size(); i++) {
char str = (char)beacons.get(i)
.apparentStrength(ship.me.x, ship.me.y, strength);
if (str >= 0) {
parent.memory.set(addr++, beacons.get(i).id());
parent.memory.set(addr++, str);
Ncn450 n = new Ncn450(beacons.get(i).apparentAngle(ship));
parent.memory.set(addr++, n.upper);
parent.memory.set(addr++, n.lower);
parent.cyclecnt += 50;
ship.power.sink(10);
}
}
}
});
}
public void reset() {
this.trackingIds = new char[trackingSlots];
}
public void physicsTickPreForce() {
ship.power.sink(trackingSlots);
}
public void physicsTickPostForce() {
}
public void triggerSynchronizedEvent(char id, int cyclesAgo) {
}
}