import java.lang.*; import java.io.*; import java.awt.*; /** * A simple torp */ class Torp implements Cloneable { public final int NUMDETFRAMES = 5; public final static byte TFREE = 0; public final static byte TMOVE = 1; public final static byte TEXPLODE = 2; public final static byte TDET = 3; public final static byte TOFF = 4; public final static byte TSTRAIGHT = 5; /* Non-wobbling torp */ public int t_no; public int t_status; // State information public Player t_owner; public int t_x; public int t_y; public byte t_dir; /* direction */ public short t_turns; /* rate of change of direction if tracking */ public int t_damage; /* damage for direct hit */ public int t_speed; /* Moving speed */ public int t_fuse; /* Life left in current state */ public byte t_war; /* enemies */ public byte t_team; /* launching team */ public byte t_whodet; /* who detonated... */ int c_race; boolean c_friend; Image c_torp; Image c_exp[]; public Torp() { t_status = TFREE; c_torp = null; c_exp = new Image[NUMDETFRAMES]; t_fuse = NUMDETFRAMES; } public Torp copy(Player owner) { Torp ret = null; try { ret = (Torp) clone(); } catch(CloneNotSupportedException ex) { } ret.c_torp = null; ret.c_exp = new Image[NUMDETFRAMES]; ret.t_owner = owner; return ret; } public void SetOwner(Player p) { t_owner = p; } void DoSetStatus(byte status) { if (status == t_status) return; if (t_status == TFREE) t_owner.p_ntorp++; if (status == TFREE) t_owner.p_ntorp--; if (status == TEXPLODE) t_fuse = NUMDETFRAMES; t_status = status; } public void SetStatus(byte status) { if (status == TEXPLODE && t_status == TFREE) return; if (t_status == Torp.TEXPLODE && status == TFREE) return; DoSetStatus(status); } public void SetInfo(byte status, byte war) { SetStatus(status); t_war = war; } public void SetPos(int x, int y) { t_x = x; t_y = y; if (t_status != TMOVE) DoSetStatus(TMOVE); else if (t_owner.IsSelf() && t_status == TEXPLODE) DoSetStatus(TMOVE); } public void SetPos(int x, int y, byte dir) { t_dir = dir; SetPos(x, y); } public void SetPosInfo(int x, int y, byte status, byte war) { t_x = x; t_y = y; SetInfo(status, war); } public void Step() { if (t_status == TEXPLODE) { t_fuse--; if (t_fuse <= 0) { t_fuse = NUMDETFRAMES; DoSetStatus(TFREE); } } } void UpdateCache(NetrekImageLib lib, int race, boolean friend) { if (c_torp == null || c_race != race || c_friend != friend) { if (c_torp == null || c_race != race) for (int i = 0; i < NUMDETFRAMES; i++) c_exp[i] = lib.GetImage("STDALL", "TEXP", race, i); c_race = race; c_friend = friend; if (friend) c_torp = lib.GetImage("STDALL", "MTORP", race, 0); else c_torp = lib.GetImage("STDALL", "ETORP", race, 0); } } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { Image img; if (t_status == TFREE) return; if (t_owner.p_status == Player.PFREE) { DoSetStatus(TFREE); return; } int x = state.RealToRelativeXCoordinate(t_x); int y = state.RealToRelativeYCoordinate(t_y); if (!state.IsVisible(x, y)) { if (!t_owner.IsSelf() && t_status == TEXPLODE) DoSetStatus(TFREE); return; } int color = t_owner.GetColorNum(); boolean friend = (t_owner.IsSelf() || ((t_war & state.me.p_team) == 0 && ((t_owner.p_hostile | state.me.p_swar) & state.me.p_team) == 0 && ((state.me.p_hostile | state.me.p_swar) & t_owner.p_team) == 0)); UpdateCache(lib, color, friend); /* if (t_status == TEXPLODE) img = c_exp[t_fuse-1]; else img = c_torp; if (img != null) g.drawImage(img, x - img.getWidth(null)/2, y - img.getHeight(null)/2, null); */ if (t_status == TEXPLODE) { img = c_exp[t_fuse-1]; if (img != null) g.drawImage(img, x - img.getWidth(null)/2, y - img.getHeight(null)/2, null); } else { g.setColor(lib.GetRaceColor(color)); if (friend) { g.drawLine(x-1, y, x+1, y); g.drawLine(x, y-1, x, y+1); } else { g.drawLine(x-1, y-1, x+1, y+1); g.drawLine(x+1, y-1, x-1, y+1); } } } }; /** * The set of all torps in the game. * This is the interface for applying operations on the torps */ class Torps implements Cloneable { final byte vtsize[] = {4, 8, 8, 12, 12, 16, 20, 20, 24}; final byte vtisize[] = {4, 7, 9, 11, 13, 16, 18, 20, 22}; int per_player; Torp torps[]; byte buf[]; byte buf2[]; public Torps(Players players, int per_player) { this.per_player = per_player; int num = players.Number() * per_player; torps = new Torp[num]; for (int i = 0; i < num; i++) { torps[i] = new Torp(); torps[i].SetOwner(players.GetPlayer(i/per_player)); } buf = new byte[128]; buf2 = new byte[128]; } public Torps copy(Players players) { Torps ret = null; try { ret = (Torps) clone(); } catch(CloneNotSupportedException ex) { } ret.torps = new Torp[torps.length]; for (int i = 0; i < torps.length; i++) ret.torps[i] = torps[i].copy(players.GetPlayer(i/per_player)); //buf = new byte[128]; //buf2 = new byte[128]; return ret; } public int Number() { return torps.length; } public Torp GetTorp(int index) { return torps[index]; } public void DumpStateInit(DataOutput data) throws IOException { } public void DumpState(DataOutput data) throws IOException { for (short i = 0; i < torps.length; i++) { sendTorpInfo(data, i); if (torps[i].t_status != Torp.TFREE) sendTorp(data, i); } } // struct torp_info_spacket { // char type; /* SP_TORP_INFO */ // char war; // char status; /* TFREE, TDET, etc... */ // char pad1; /* pad needed for cross cpu compatibility */ // short tnum; // short pad2; // }; public void handleTorpInfo(DataInput data) throws IOException { byte war = data.readByte(); byte status = data.readByte(); byte pad1 = data.readByte(); short tnum = data.readShort(); short pad2 = data.readShort(); Torp torp = torps[tnum]; torp.SetInfo(status, war); } public void sendTorpInfo(DataOutput data, short tnum) throws IOException { Torp t = torps[tnum]; data.writeByte(NetrekState.SP_TORP_INFO); data.writeByte(t.t_war); data.writeByte(t.t_status); data.writeByte(0); data.writeShort(tnum); data.writeShort(0); } // struct torp_spacket { // char type; /* SP_TORP */ // unsigned char dir; // short tnum; // LONG x, y; // }; public void handleTorp(DataInput data) throws IOException { byte dir = data.readByte(); short tnum = data.readShort(); int x = data.readInt(); int y = data.readInt(); Torp torp = torps[tnum]; torp.SetPos(x, y, dir); } public void sendTorp(DataOutput data, short tnum) throws IOException { Torp t = torps[tnum]; data.writeByte(NetrekState.SP_TORP); data.writeByte((byte)t.t_dir); data.writeShort(tnum); data.writeInt(t.t_x); data.writeInt(t.t_y); } // struct torp_s_spacket { // char type; /* SP_S_TORP */ // unsigned char bitset; /* bit=1 that torp is in packet */ // unsigned char whichtorps; /* Torpnumber of first torp / 8 */ // unsigned char data[21]; /* For every torp 2*9 bit coordinates */ // }; byte numOfBits(byte a) { byte cnt; for (cnt = 0; a != 0; cnt++) a &= a-1; return cnt; } public void handleSTorp(DataInput data, ServerState state) throws IOException { byte bitset = data.readByte(); int which = data.readByte(); if (which < 0) which = 256 + which; int size = vtsize[numOfBits(bitset)]; byte info[] = buf; data.readFully(info, 0, size-3); parseSTorp(which, bitset, info, 0, null, state); } // same as above public void handleSTorpInfo(DataInput data, ServerState state) throws IOException { byte bitset = data.readByte(); int which = data.readByte(); if (which < 0) which = 256 + which; byte arg = data.readByte(); int size1 = vtisize[numOfBits(bitset)]; int size2 = numOfBits(arg); size2 = size2+3 - ((size1+size2+3)%4); byte info1[] = buf; data.readFully(info1, 0, size1-4); byte info2[] = buf2; data.readFully(info2, 0, size2); parseSTorp(which, bitset, info1, arg, info2, state); } // same as above public void handleS8Torp(DataInput data, ServerState state) throws IOException { int which = data.readByte(); if (which < 0) which = 256 + which; byte info[] = buf; data.readFully(info, 0, 18); parseSTorp(which, 0xFF, info, 0, null, state); } void parseSTorp(int which, int bitset, byte data[], int infset, byte info[], ServerState state) { int x = 0, y = 0, dx, dy; int shift = 0; int dptr = 0; int iptr = 0; for (int i = 0; i < 8; i++) { Torp torp = torps[which*8+i]; if ((bitset & 0x01) != 0) { dx = (0xFF & (int) data[dptr++]) >> shift; dx |= ((int) data[dptr] << (8 - shift)) & 0x1FF; shift++; dy = (0xFF & (int) data[dptr++]) >> shift; dy |= ((int) data[dptr] << (8 - shift)) & 0x1FF; shift++; if (shift == 8) { shift = 0; dptr++; } x = state.RelativeToRealXCoordinate(dx); y = state.RelativeToRealYCoordinate(dy); if ((infset & 0x01) != 0) { byte war = (byte) (info[iptr] & 0x0F); byte status = (byte) ((info[iptr] >> 4) & 0x0F); iptr++; torp.SetPosInfo(x, y, status, war); } else torp.SetPos(x, y); } else if ((infset & 0x01) == 0) torp.SetInfo(torp.TFREE, (byte) 0); else { byte war = (byte) (info[iptr] & 0x0F); byte status = (byte) ((info[iptr] >> 4) & 0x0F); iptr++; torp.SetInfo(status, war); } bitset = bitset >> 1; infset = infset >> 1; } } public void Step() { for (int i = 0; i < Number(); i++) { torps[i].Step(); } } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { for (int i = 0; i < Number(); i++) torps[i].paintLocal(lib, g, state, eraser); } public void paint(Graphics g) { } } // end of torps class PlasmaTorp implements Cloneable { public final static int NUMDETFRAMES = 5; public final static byte PTFREE = 0; public final static byte PTMOVE = 1; public final static byte PTEXPLODE = 2; public final static byte PTDET = 3; public int pt_no; public int pt_status; /* State information */ public Player pt_owner; public int pt_x; public int pt_y; public byte pt_dir; /* direction */ public short pt_turns; /* ticks turned per cycle */ public int pt_damage; /* damage for direct hit */ public int pt_speed; /* Moving speed */ public int pt_fuse; /* Life left in current state */ public byte pt_war; /* enemies */ public byte pt_team; /* launching team */ int c_race; boolean c_friend; Image c_torp; Image c_exp[]; public PlasmaTorp() { pt_status = PTFREE; c_torp = null; c_exp = new Image[NUMDETFRAMES]; pt_fuse = NUMDETFRAMES; } public PlasmaTorp copy(Player owner) { PlasmaTorp ret = null; try { ret = (PlasmaTorp) clone(); } catch(CloneNotSupportedException ex) { } ret.c_torp = null; ret.c_exp = new Image[NUMDETFRAMES]; ret.pt_owner = owner; return ret; } public void SetOwner(Player p) { pt_owner = p; } void DoSetStatus(byte status) { if (status == pt_status) return; if (pt_status == PTFREE) pt_owner.p_nplasmatorp++; if (status == PTFREE) pt_owner.p_nplasmatorp--; if (status == PTEXPLODE) pt_fuse = NUMDETFRAMES; pt_status = status; } public void SetInfo(byte status, byte war) { if (status == pt_status) return; if (status == PTEXPLODE && pt_status == PTFREE) return; if (pt_status == PTEXPLODE && status == PTFREE) return; pt_war = war; DoSetStatus(status); } public void SetPos(int x, int y) { pt_x = x; pt_y = y; if (pt_status != PTMOVE) { DoSetStatus(PTMOVE); } else if (pt_owner.IsSelf() && pt_status == PTEXPLODE) DoSetStatus(PTMOVE); } public void SetPos(int x, int y, byte dir) { pt_dir = dir; SetPos(x, y); } public void Step() { if (pt_status == PTEXPLODE) { pt_fuse--; if (pt_fuse <= 0) { pt_fuse = NUMDETFRAMES; DoSetStatus(PTFREE); } } } void UpdateCache(NetrekImageLib lib, int race, boolean friend) { if (c_torp == null || c_race != race || c_friend != friend) { if (c_torp == null || c_race != race) for (int i = 0; i < NUMDETFRAMES; i++) c_exp[i] = lib.GetImage("STDALL", "PTEXP", race, i); c_race = race; c_friend = friend; if (friend) c_torp = lib.GetImage("STDALL", "MPTORP", race, 0); else c_torp = lib.GetImage("STDALL", "EPTORP", race, 0); } } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { Image img; if (pt_status == PTFREE) return; if (pt_owner.p_status == Player.PFREE) { DoSetStatus(PTFREE); return; } int x = state.RealToRelativeXCoordinate(pt_x); int y = state.RealToRelativeYCoordinate(pt_y); if (!state.IsVisible(x, y)) { if (!pt_owner.IsSelf() && pt_status == PTEXPLODE) DoSetStatus(PTFREE); return; } int color = pt_owner.GetColorNum(); boolean friend = (pt_owner.IsSelf() || ((pt_war & state.me.p_team) == 0 && ((pt_owner.p_hostile | state.me.p_swar) & state.me.p_team) == 0 && ((state.me.p_hostile | state.me.p_swar) & pt_owner.p_team) == 0)); UpdateCache(lib, color, friend); if (pt_status == PTEXPLODE) img = c_exp[pt_fuse-1]; else img = c_torp; if (img != null) g.drawImage(img, x - img.getWidth(null)/2, y - img.getHeight(null)/2, null); } } class PlasmaTorps implements Cloneable { int per_player; PlasmaTorp torps[]; PlasmaTorps(Players players, int per_player) { this.per_player = per_player; int num = players.Number() * per_player; torps = new PlasmaTorp[num]; for (int i = 0; i < num; i++) { torps[i] = new PlasmaTorp(); torps[i].SetOwner(players.GetPlayer(i/per_player)); } } public PlasmaTorps copy(Players players) { PlasmaTorps ret = null; try { ret = (PlasmaTorps) clone(); } catch(CloneNotSupportedException ex) { } ret.torps = new PlasmaTorp[torps.length]; for (int i = 0; i < torps.length; i++) ret.torps[i] = torps[i].copy(players.GetPlayer(i/per_player)); return ret; } public int Number() { return torps.length; } public void DumpStateInit(DataOutput data) throws IOException { } public void DumpState(DataOutput data) throws IOException { for (short i = 0; i < torps.length; i++) { sendPlasmaInfo(data, i); if (torps[i].pt_status != PlasmaTorp.PTFREE) sendPlasma(data, i); } } // struct plasma_info_spacket { // char type; /* SP_PLASMA_INFO */ // char war; // char status; /* TFREE, TDET, etc... */ // char pad1; /* pad needed for cross cpu compatibility */ // short pnum; // short pad2; // }; public void handlePlasmaInfo(DataInput data) throws IOException { byte war = data.readByte(); byte status = data.readByte(); byte pad1 = data.readByte(); short pnum = data.readShort(); short pad2 = data.readShort(); PlasmaTorp plasma = torps[pnum]; plasma.SetInfo(status, war); } public void sendPlasmaInfo(DataOutput data, short tnum) throws IOException { PlasmaTorp t = torps[tnum]; data.writeByte(NetrekState.SP_PLASMA_INFO); data.writeByte(t.pt_war); data.writeByte(t.pt_status); data.writeByte(0); data.writeShort(tnum); data.writeShort(0); } // struct plasma_spacket { // char type; /* SP_PLASMA */ // char pad1; // short pnum; // LONG x, y; // }; public void handlePlasma(DataInput data) throws IOException { byte pad1 = data.readByte(); short pnum = data.readShort(); int x = data.readInt(); int y = data.readInt(); PlasmaTorp plasma = torps[pnum]; plasma.SetPos(x, y); } public void sendPlasma(DataOutput data, short tnum) throws IOException { PlasmaTorp t = torps[tnum]; data.writeByte(NetrekState.SP_PLASMA); data.writeByte(0); data.writeShort(tnum); data.writeInt(t.pt_x); data.writeInt(t.pt_y); } public void Step() { for (int i = 0; i < Number(); i++) { torps[i].Step(); } } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { for (int i = 0; i < Number(); i++) torps[i].paintLocal(lib, g, state, eraser); } public void paint(Graphics g) { } } class Phaser implements Cloneable { public final static int PHFREE = 0x00; public final static int PHHIT = 0x01;/* When it hits a person */ public final static int PHMISS = 0x02; public final static int PHHIT2 = 0x04;/* When it hits a photon */ final static int PHASEDIST = 6000; public int ph_status; /* What it's up to */ public byte ph_dir; /* direction */ public int ph_targetnum; /* Who's being hit (for drawing) */ public Player ph_target; /* Who's being hit (for drawing) */ public int ph_x, ph_y; /* For when it hits a torp */ public int ph_fuse; /* Life left for drawing */ public int ph_damage; /* Damage inflicted on victim */ public Player ph_owner; static float Sin[] = null; static float Cos[] = null; public Phaser() { ph_status = PHFREE; if (Sin == null) { Sin = new float[256]; Cos = new float[256]; for (int i = 0; i < 256; i++) { double theta = i * 2 * Math.PI / 256 - Math.PI/2; Sin[i] = (float) Math.sin(theta); Cos[i] = (float) Math.cos(theta); } } } public Phaser copy(Player owner) { Phaser ret = null; try { ret = (Phaser) clone(); } catch(CloneNotSupportedException ex) { } ret.ph_target = null; ret.ph_owner = owner; return ret; } public void SetOwner(Player p) { ph_owner = p; } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { Image img; int fx, fy, tx, ty; if (ph_status == PHFREE) return; if (ph_owner.p_status != Player.PALIVE) return; fx = state.RealToRelativeXCoordinate(ph_owner.p_x); fy = state.RealToRelativeYCoordinate(ph_owner.p_y); switch (ph_status) { case PHMISS: int dir = ph_dir; if (dir < 0) dir += 256; int power = PHASEDIST * ph_owner.p_ship.s_phaserdamage / 100; tx = ph_owner.p_x + (int) (power * Cos[dir]); ty = ph_owner.p_y + (int) (power * Sin[dir]); break; case PHHIT2: tx = ph_x; ty = ph_y; break; default: // PHHIT if (ph_target == null) return; tx = ph_target.p_x; ty = ph_target.p_y; } tx = state.RealToRelativeXCoordinate(tx); ty = state.RealToRelativeYCoordinate(ty); if (!state.IsVisible(fx, fy) && !state.IsVisible(tx, ty)) return; g.setColor(lib.GetRaceColor(ph_owner.GetRace())); g.drawLine(fx, fy, tx, ty); } public void paint(Graphics g) { } } class Phasers implements Cloneable { int per_player; Players the_players; Phaser phasers[]; byte buf[]; public Phasers(Players players, int per_player) { this.per_player = per_player; int num = players.Number() * per_player; phasers = new Phaser[num]; for (int i = 0; i < num; i++) { phasers[i] = new Phaser(); phasers[i].SetOwner(players.GetPlayer(i/per_player)); } the_players = players; buf = new byte[128]; } public Phasers copy(Players players) { Phasers ret = null; try { ret = (Phasers) clone(); } catch(CloneNotSupportedException ex) { } ret.the_players = players; ret.phasers = new Phaser[phasers.length]; for (int i = 0; i < phasers.length; i++) { ret.phasers[i] = phasers[i].copy(players.GetPlayer(i/per_player)); if (phasers[i].ph_target != null) ret.phasers[i].ph_target = players.GetPlayer(phasers[i].ph_target.p_no); } return ret; } public int Number() { return phasers.length; } public void DumpStateInit(DataOutput data) throws IOException { } public void DumpState(DataOutput data) throws IOException { for (byte i = 0; i < phasers.length; i++) sendPhaser(data, i); } int CalcInt(byte data[], int off) { return ((((int) data[off]) << 24) + (((int) data[off+1] & 0xFF) << 16) + (((int) data[off+2] & 0xFF) << 8) + ((int) data[off+3] & 0xFF)); } // struct phaser_spacket { // char type; /* SP_PHASER */ // char pnum; // char status; /* PH_HIT, etc... */ // unsigned char dir; // LONG x, y; // LONG target; // }; void handlePhaser(DataInput data) throws IOException { data.readFully(buf, 1, 15); byte pnum = buf[1]; byte status = buf[2]; byte dir = buf[3]; int x = CalcInt(buf, 4); int y = CalcInt(buf, 8); int target = CalcInt(buf, 12); Phaser phaser = phasers[pnum]; phaser.ph_status = status; phaser.ph_dir = dir; phaser.ph_fuse = 0; phaser.ph_x = x; phaser.ph_y = y; phaser.ph_targetnum = target; if (target < 0 || target >= the_players.Number()) phaser.ph_target = null; else phaser.ph_target = the_players.GetPlayer(target); } void sendPhaser(DataOutput data, byte pnum) throws IOException { Phaser p = phasers[pnum]; data.writeByte(NetrekState.SP_PHASER); data.writeByte(pnum); data.writeByte(p.ph_status); data.writeByte((byte)p.ph_dir); data.writeInt(p.ph_x); data.writeInt(p.ph_y); data.writeInt(p.ph_targetnum); } public void paintLocal(NetrekImageLib lib, Graphics g, ServerState state, Eraser eraser) { for (int i = 0; i < Number(); i++) phasers[i].paintLocal(lib, g, state, eraser); } }