/** * Select a random spawnpoint, but exclude the two points closest * to other players. * @return q2jgame.GameEntity */ public static GenericSpawnpoint getSpawnpointRandom() { GenericSpawnpoint spawnPoint = null; GenericSpawnpoint spot1 = null; GenericSpawnpoint spot2 = null; float range1 = Float.MAX_VALUE; float range2 = Float.MAX_VALUE; int count = 0; // find the two deathmatch spawnpoints that are closest to any players Vector list = Game.getLevelRegistryList(q2java.baseq2.spawn.info_player_deathmatch.REGISTRY_KEY); // if no deathmatch spawnpoint, try single-player ones if (list.size() < 1) list = Game.getLevelRegistryList(q2java.baseq2.spawn.info_player_start.REGISTRY_KEY); Enumeration enum = list.elements(); while (enum.hasMoreElements()) { count++; spawnPoint = (GenericSpawnpoint) enum.nextElement(); float range = MiscUtil.nearestPlayerDistance(spawnPoint); if (range < range1) { range1 = range; spot1 = spawnPoint; } else { if (range < range2) { range2 = range; spot2 = spawnPoint; } } } if (count == 0) return null; if (count <= 2) spot1 = spot2 = null; else count -= 2; int selection = (GameUtil.randomInt() & 0x0fff) % count; spawnPoint = null; enum = list.elements(); while (enum.hasMoreElements()) { spawnPoint = (GenericSpawnpoint) enum.nextElement(); // skip the undesirable spots if ((spawnPoint == spot1) || (spawnPoint == spot2)) continue; if ((selection--) == 0) break; } return spawnPoint; }
/** * This method finds a ctf spawnpoint for the TEAM, * but NOT the two points closest to other players. **/ public GenericSpawnpoint getSpawnpoint() { GenericSpawnpoint spawnPoint = null; GenericSpawnpoint spot1 = null; GenericSpawnpoint spot2 = null; float range1 = Float.MAX_VALUE; float range2 = Float.MAX_VALUE; int count = 0; String regKey; regKey = ( this == TEAM1 ? info_player_team1.REGISTRY_KEY : info_player_team2.REGISTRY_KEY ); // find the two ctf-team spawnpoints that are closest to any players Vector list = Game.getLevelRegistryList( regKey ); Enumeration enum = list.elements(); while (enum.hasMoreElements()) { count++; spawnPoint = (GenericSpawnpoint) enum.nextElement(); float range = q2java.baseq2.MiscUtil.nearestPlayerDistance(spawnPoint); if (range < range1) { range1 = range; spot1 = spawnPoint; } else { if (range < range2) { range2 = range; spot2 = spawnPoint; } } } if (count == 0) return null; if (count <= 2) spot1 = spot2 = null; else count -= 2; int selection = (GameUtil.randomInt() & 0x0fff) % count; spawnPoint = null; enum = list.elements(); while (enum.hasMoreElements()) { spawnPoint = (GenericSpawnpoint) enum.nextElement(); // skip the undesirable spots if ((spawnPoint == spot1) || (spawnPoint == spot2)) continue; if ((selection--) == 0) break; } return spawnPoint; }
/** * Fire a lead projectile. * @param p q2jgame.Player * @param start q2java.Vec3 * @param aimDir q2java.Vec3 * @param damage int * @param kick int * @param teImpact int * @param hSpread int * @param vSpread int */ public static void fireLead(GameObject p, Point3f start, Vector3f aimDir, int damage, int kick, int teImpact, int hSpread, int vSpread, String obitKey) { TraceResults tr; Vector3f forward = new Vector3f(); Vector3f right = new Vector3f(); Vector3f up = new Vector3f(); Point3f end = new Point3f(); float r; float u; Point3f waterStart = null; boolean water = false; int content_mask = Engine.MASK_SHOT | Engine.MASK_WATER; tr = Engine.trace(p.fEntity.getOrigin(), start, p.fEntity, Engine.MASK_SHOT); if (!(tr.fFraction < 1.0)) { // limit the scope of "dir" { Angle3f dir = Q2Recycler.getAngle3f(); dir.set(aimDir); dir.getVectors(forward, right, up); Q2Recycler.put(dir); } r = (float) (GameUtil.cRandom() * hSpread); u = (float) (GameUtil.cRandom() * vSpread); end.scaleAdd(8192, forward, start); end.scaleAdd(r, right, end); end.scaleAdd(u, up, end); if ((Engine.getPointContents(start) & Engine.MASK_WATER) != 0) { water = true; waterStart = new Point3f(start); content_mask &= ~Engine.MASK_WATER; } tr = Engine.trace(start, end, p.fEntity, content_mask); // see if we hit water if ((tr.fContents & Engine.MASK_WATER) != 0) { int color; water = true; waterStart = new Point3f(tr.fEndPos); if (!start.equals(tr.fEndPos)) { if ((tr.fContents & Engine.CONTENTS_WATER) != 0) { if (tr.fSurfaceName.equals("*brwater")) color = Engine.SPLASH_BROWN_WATER; else color = Engine.SPLASH_BLUE_WATER; } else if ((tr.fContents & Engine.CONTENTS_SLIME) != 0) color = Engine.SPLASH_SLIME; else if ((tr.fContents & Engine.CONTENTS_LAVA) != 0) color = Engine.SPLASH_LAVA; else color = Engine.SPLASH_UNKNOWN; if (color != Engine.SPLASH_UNKNOWN) { Engine.writeByte(Engine.SVC_TEMP_ENTITY); Engine.writeByte(Engine.TE_SPLASH); Engine.writeByte(8); Engine.writePosition(tr.fEndPos); Engine.writeDir(tr.fPlaneNormal); Engine.writeByte(color); Engine.multicast(tr.fEndPos, Engine.MULTICAST_PVS); } // change bullet's course when it enters water Vector3f diff = Q2Recycler.getVector3f(); Angle3f ang = Q2Recycler.getAngle3f(); diff.sub(end, start); ang.set(diff); ang.getVectors(forward, right, up); r = (float)(GameUtil.cRandom() * hSpread * 2); u = (float)(GameUtil.cRandom() * vSpread * 2); end.scaleAdd(8192, forward, waterStart); end.scaleAdd(r, right, end); end.scaleAdd(u, up, end); Q2Recycler.put(ang); Q2Recycler.put(diff); } // re-trace ignoring water this time tr = Engine.trace(waterStart, end, p.fEntity, Engine.MASK_SHOT); } } // send gun puff / flash if ((tr.fSurfaceName == null) || ((tr.fSurfaceFlags & Engine.SURF_SKY) == 0)) { if ((tr.fFraction < 1.0) && (!tr.fSurfaceName.startsWith("sky"))) { if (tr.fEntity.getReference() instanceof GameObject) ((GameObject)tr.fEntity.getReference()).damage(p, p, aimDir, tr.fEndPos, tr.fPlaneNormal, damage, kick, GameObject.DAMAGE_BULLET, teImpact, obitKey); } } // if went through water, determine where the end and make a bubble trail if (water) { Point3f pos = Q2Recycler.getPoint3f(); Vector3f leadDir = Q2Recycler.getVector3f(); leadDir.sub(tr.fEndPos, waterStart); leadDir.normalize(); pos.scaleAdd(-2, leadDir, tr.fEndPos); // = tr.fEndPos.vectorMA(-2, dir); if ((Engine.getPointContents(pos) & Engine.MASK_WATER) != 0) tr.fEndPos = new Point3f(pos); else tr = Engine.trace(pos, waterStart, tr.fEntity, Engine.MASK_WATER); pos.add(tr.fEndPos, waterStart); pos.scale(0.5F); Engine.writeByte(Engine.SVC_TEMP_ENTITY); Engine.writeByte(Engine.TE_BUBBLETRAIL); Engine.writePosition(waterStart); Engine.writePosition(tr.fEndPos); Engine.multicast(pos, Engine.MULTICAST_PVS); Q2Recycler.put(leadDir); Q2Recycler.put(pos); } }