Fix #563. Capture points in Minecraft!!!

Documentation coming soon :)
This commit is contained in:
Connor Monahan 2017-07-21 02:25:21 -04:00
parent 372576a396
commit 200bb5a3c0
9 changed files with 551 additions and 19 deletions

View File

@ -8,6 +8,7 @@ import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import com.tommytony.war.job.CapturePointTimer;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.ChatColor;
@ -286,6 +287,9 @@ public class War extends JavaPlugin {
// Start tasks
HelmetProtectionTask helmetProtectionTask = new HelmetProtectionTask();
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, helmetProtectionTask, 250, 100);
CapturePointTimer cpt = new CapturePointTimer();
cpt.runTaskTimer(this, 100, 20);
if (this.isSpoutServer) {
SpoutFadeOutMessageJob fadeOutMessagesTask = new SpoutFadeOutMessageJob();

View File

@ -8,6 +8,7 @@ import java.text.MessageFormat;
import java.util.*;
import java.util.logging.Level;
import com.tommytony.war.structure.*;
import net.milkbowl.vault.economy.EconomyResponse;
import org.apache.commons.lang.StringUtils;
@ -67,13 +68,6 @@ import com.tommytony.war.mapper.LoadoutYmlMapper;
import com.tommytony.war.mapper.VolumeMapper;
import com.tommytony.war.mapper.ZoneVolumeMapper;
import com.tommytony.war.spout.SpoutDisplayer;
import com.tommytony.war.structure.Bomb;
import com.tommytony.war.structure.Cake;
import com.tommytony.war.structure.HubLobbyMaterials;
import com.tommytony.war.structure.Monument;
import com.tommytony.war.structure.WarzoneMaterials;
import com.tommytony.war.structure.ZoneLobby;
import com.tommytony.war.structure.ZoneWallGuard;
import com.tommytony.war.utility.Direction;
import com.tommytony.war.utility.Loadout;
import com.tommytony.war.utility.LoadoutSelection;
@ -88,6 +82,8 @@ import com.tommytony.war.volume.ZoneVolume;
* @package com.tommytony.war
*/
public class Warzone {
public enum LeaveCause {
COMMAND, DISCONNECT, SCORECAP, RESET;
public boolean useRallyPoint() {
@ -100,6 +96,7 @@ public class Warzone {
private World world;
private final List<Team> teams = new ArrayList<Team>();
private final List<Monument> monuments = new ArrayList<Monument>();
private final List<CapturePoint> capturePoints = new ArrayList<CapturePoint>();
private final List<Bomb> bombs = new ArrayList<Bomb>();
private final List<Cake> cakes = new ArrayList<Cake>();
private Location teleport;
@ -276,6 +273,18 @@ public class Warzone {
monument.getVolume().resetBlocks();
}
for (CapturePoint cp : this.capturePoints) {
cp.getVolume().resetBlocks();
}
for (Bomb bomb : this.bombs) {
bomb.getVolume().resetBlocks();
}
for (Cake cake : this.cakes) {
cake.getVolume().resetBlocks();
}
if (this.lobby != null) {
this.lobby.getVolume().resetBlocks();
}
@ -362,6 +371,12 @@ public class Warzone {
monument.getVolume().resetBlocks();
monument.addMonumentBlocks();
}
// reset capture points
for (CapturePoint cp : this.capturePoints) {
cp.getVolume().resetBlocks();
cp.reset();
}
// reset bombs
for (Bomb bomb : this.bombs) {
@ -723,6 +738,19 @@ public class Warzone {
}
return null;
}
public boolean hasCapturePoint(String capturePointName) {
return this.getCapturePoint(capturePointName) != null;
}
public CapturePoint getCapturePoint(String capturePointName) {
for (CapturePoint cp : this.capturePoints) {
if (cp.getName().startsWith(capturePointName)) {
return cp;
}
}
return null;
}
public boolean hasBomb(String bombName) {
for (Bomb bomb : this.bombs) {
@ -770,6 +798,11 @@ public class Warzone {
return true;
}
}
for (CapturePoint cp : this.capturePoints) {
if (cp.getVolume().contains(block)) {
return true;
}
}
for (Bomb b : this.bombs) {
if (b.getVolume().contains(block)) {
return true;
@ -1643,6 +1676,10 @@ public class Warzone {
return cakes;
}
public List<CapturePoint> getCapturePoints() {
return capturePoints;
}
public List<String> getReallyDeadFighters() {
return this.reallyDeadFighters ;
}

View File

@ -0,0 +1,68 @@
package com.tommytony.war.command;
import com.tommytony.war.War;
import com.tommytony.war.Warzone;
import com.tommytony.war.mapper.WarzoneYmlMapper;
import com.tommytony.war.structure.CapturePoint;
import com.tommytony.war.structure.Monument;
import com.tommytony.war.structure.ZoneLobby;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.logging.Level;
/**
* Deletes a capture point.
*
* @author Connor Monahan
*/
public class DeleteCapturePointCommand extends AbstractZoneMakerCommand {
public DeleteCapturePointCommand(WarCommandHandler handler, CommandSender sender, String[] args) throws NotZoneMakerException {
super(handler, sender, args);
}
@Override
public boolean handle() {
Warzone zone;
if (this.args.length == 0) {
return false;
} else if (this.args.length == 2) {
zone = Warzone.getZoneByName(this.args[0]);
this.args[0] = this.args[1];
} else if (this.args.length == 1) {
if (!(this.getSender() instanceof Player)) {
return false;
}
zone = Warzone.getZoneByLocation((Player) this.getSender());
if (zone == null) {
ZoneLobby lobby = ZoneLobby.getLobbyByLocation((Player) this.getSender());
if (lobby == null) {
return false;
}
zone = lobby.getZone();
}
} else {
return false;
}
if (zone == null) {
return false;
} else if (!this.isSenderAuthorOfZone(zone)) {
return true;
}
CapturePoint cp = zone.getCapturePoint(this.args[0]);
if (cp != null) {
cp.getVolume().resetBlocks();
zone.getCapturePoints().remove(cp);
WarzoneYmlMapper.save(zone);
this.msg("Capture point " + cp.getName() + " removed.");
War.war.log(this.getSender().getName() + " deleted capture point " + cp.getName() + " in warzone " + zone.getName(), Level.INFO);
} else {
this.badMsg("No such capture point.");
}
return true;
}
}

View File

@ -0,0 +1,77 @@
package com.tommytony.war.command;
import com.tommytony.war.War;
import com.tommytony.war.Warzone;
import com.tommytony.war.config.TeamKind;
import com.tommytony.war.mapper.WarzoneYmlMapper;
import com.tommytony.war.structure.CapturePoint;
import com.tommytony.war.structure.Monument;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.logging.Level;
/**
* Sets a capture point
*
* @author Connor Monahan
*/
public class SetCapturePointCommand extends AbstractZoneMakerCommand {
public SetCapturePointCommand(WarCommandHandler handler, CommandSender sender, String[] args) throws NotZoneMakerException {
super(handler, sender, args);
}
@Override
public boolean handle() {
if (!(this.getSender() instanceof Player)) {
this.badMsg("You can't do this if you are not in-game.");
return true;
}
Player player = (Player) this.getSender();
if (this.args.length < 1) {
return false;
}
Warzone zone = Warzone.getZoneByLocation(player);
if (zone == null) {
return false;
} else if (!this.isSenderAuthorOfZone(zone)) {
return true;
}
if (this.args[0].equals(zone.getName())) {
return false;
}
if (zone.hasCapturePoint(this.args[0])) {
// move the existing capture point
CapturePoint cp = zone.getCapturePoint(this.args[0]);
cp.getVolume().resetBlocks();
cp.setLocation(player.getLocation());
this.msg("Capture point " + cp.getName() + " was moved.");
War.war.log(this.getSender().getName() + " moved capture point " + cp.getName() + " in warzone " + zone.getName(), Level.INFO);
} else {
// create a new capture point
TeamKind controller = null;
int strength = 0;
if (args.length > 1) {
controller = TeamKind.teamKindFromString(args[1]);
strength = 4;
if (controller == null || zone.getTeamByKind(controller) == null) {
this.badMsg("Failed to create capture point: team {0} does not exist", args[1]);
return true;
}
}
CapturePoint cp = new CapturePoint(this.args[0], player.getLocation(), controller, strength, zone);
zone.getCapturePoints().add(cp);
War.war.log(this.getSender().getName() + " created capture point " + cp.getName() + " in warzone " + zone.getName(), Level.INFO);
}
WarzoneYmlMapper.save(zone);
return true;
}
}

View File

@ -94,6 +94,10 @@ public class WarCommandHandler {
commandObj = new SetMonumentCommand(this, sender, arguments);
} else if (command.equals("deletemonument")) {
commandObj = new DeleteMonumentCommand(this, sender, arguments);
} else if (command.equals("setcapturepoint")) {
commandObj = new SetCapturePointCommand(this, sender, arguments);
} else if (command.equals("deletecapturepoint")) {
commandObj = new DeleteCapturePointCommand(this, sender, arguments);
} else if (command.equals("setbomb")) {
commandObj = new SetBombCommand(this, sender, arguments);
} else if (command.equals("deletebomb")) {

View File

@ -0,0 +1,97 @@
package com.tommytony.war.job;
import com.tommytony.war.Team;
import com.tommytony.war.War;
import com.tommytony.war.Warzone;
import com.tommytony.war.structure.CapturePoint;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
public class CapturePointTimer extends BukkitRunnable {
private static int iteration = 0;
@Override
public void run() {
iteration += 1;
if (!War.war.isLoaded()) {
return;
}
for (Player player : War.war.getServer().getOnlinePlayers()) {
Warzone zone = Warzone.getZoneByPlayerName(player.getName());
Team team = Team.getTeamByPlayerName(player.getName());
if (zone == null || team == null) {
continue;
}
for (CapturePoint cp : zone.getCapturePoints()) {
if (cp.getVolume().contains(player.getLocation())) {
// player is maintaining or contesting capture point.
if (cp.getController() == null) {
// take control of unclaimed point
incrementStrength(cp, player, zone, team);
} else if (cp.getController() != team.getKind()) {
// contest other team's point
decrementStrength(cp, player, zone, team);
} else if (cp.getController() == team.getKind()) {
// maintain your team's point
incrementStrength(cp, player, zone, team);
}
}
}
}
}
private static void decrementStrength(CapturePoint cp, Player player, Warzone zone, Team team) {
if (iteration % 5 != 0) {
return;
}
int strength = cp.getStrength();
if (strength < 1) {
// strength is already at minimum, ensure attributes are wiped
cp.setController(null);
cp.setStrength(0);
return;
}
strength -= 1;
if (strength == 0) {
zone.broadcast("Team {0} has lost control of capture point {1}.", cp.getController().getFormattedName(),
cp.getName());
cp.setController(null);
} else if (strength == 3) {
zone.broadcast("Capture point {0} is being contested by {1}!", cp.getName(),
team.getKind().getColor() + player.getName() + ChatColor.WHITE);
}
cp.setStrength(strength);
}
private static void incrementStrength(CapturePoint cp, Player player, Warzone zone, Team team) {
if (iteration % 5 != 0) {
return;
}
int strength = cp.getStrength();
if (strength > 4) {
// cap strength at 4
cp.setStrength(4);
return;
} else if (strength == 4) {
// do nothing
return;
}
strength += 1;
if (strength == 4) {
zone.broadcast("Team {0} has captured point {1}, gaining 1 extra point.",
cp.getController().getFormattedName(), cp.getName());
team.addPoint();
} else if (strength == 1) {
zone.broadcast("Team {0} is gaining control of point {1}!",
team.getKind().getFormattedName(), cp.getName());
cp.setController(team.getKind());
}
cp.setStrength(strength);
}
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import com.tommytony.war.structure.*;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
@ -22,10 +23,6 @@ import com.tommytony.war.War;
import com.tommytony.war.Warzone;
import com.tommytony.war.config.TeamConfig;
import com.tommytony.war.config.TeamKind;
import com.tommytony.war.structure.Bomb;
import com.tommytony.war.structure.Cake;
import com.tommytony.war.structure.Monument;
import com.tommytony.war.structure.ZoneLobby;
import com.tommytony.war.utility.Direction;
import com.tommytony.war.volume.Volume;
import com.tommytony.war.volume.ZoneVolume;
@ -145,7 +142,33 @@ public class WarzoneYmlMapper {
}
}
}
// capture points
if (warzoneRootSection.contains(zoneInfoPrefix + "capturepoint")) {
List<String> cpNames = warzoneRootSection.getStringList(zoneInfoPrefix + "capturepoint.names");
for (String cpName : cpNames) {
if (cpName != null && !cpName.equals("")) {
String cpPrefix = zoneInfoPrefix + "capturepoint." + cpName + ".";
if (!warzoneRootSection.contains(cpPrefix + "x")) {
// try lowercase instead
cpPrefix = zoneInfoPrefix + "capturepoint." + cpName.toLowerCase() + ".";
}
int cpX = warzoneRootSection.getInt(cpPrefix + "x");
int cpY = warzoneRootSection.getInt(cpPrefix + "y");
int cpZ = warzoneRootSection.getInt(cpPrefix + "z");
float cpYaw = (float) warzoneRootSection.getDouble(cpPrefix + "yaw");
TeamKind controller = null;
int strength = 0;
if (warzoneRootSection.contains(cpPrefix + "controller")) {
controller = TeamKind.teamKindFromString(warzoneRootSection.getString(cpPrefix + "controller"));
strength = 4;
}
CapturePoint cp = new CapturePoint(cpName, new Location(world, cpX, cpY, cpZ, cpYaw, 0), controller, strength, warzone);
warzone.getCapturePoints().add(cp);
}
}
}
// bombs
if (warzoneRootSection.contains(zoneInfoPrefix + "bomb")) {
List<String> bombNames = warzoneRootSection.getStringList(zoneInfoPrefix + "bomb.names");
@ -295,7 +318,16 @@ public class WarzoneYmlMapper {
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
}
}
// capture point blocks
for (CapturePoint cp : warzone.getCapturePoints()) {
try {
cp.setVolume(warzone.loadStructure("cp-" + cp.getName(), connection));
} catch (SQLException e) {
War.war.getLogger().log(Level.WARNING, "Failed to load warzone structures volume", e);
}
}
// bomb blocks
for (Bomb bomb : warzone.getBombs()) {
try {
@ -546,19 +578,42 @@ public class WarzoneYmlMapper {
monumentSection.set("yaw", toIntYaw(monument.getLocation().getYaw()));
}
}
// capture points
if (warzone.getCapturePoints().size() > 0) {
ConfigurationSection cpsSection = warzoneInfoSection.createSection("capturepoint");
List<String> cpNames = new ArrayList<String>();
for (CapturePoint cp : warzone.getCapturePoints()) {
cpNames.add(cp.getName());
}
cpsSection.set("names", cpNames);
for (CapturePoint cp : warzone.getCapturePoints()) {
ConfigurationSection cpSection = cpsSection.createSection(cp.getName());
cpSection.set("x", cp.getLocation().getBlockX());
cpSection.set("y", cp.getLocation().getBlockY());
cpSection.set("z", cp.getLocation().getBlockZ());
cpSection.set("yaw", cp.getLocation().getYaw());
if (cp.getDefaultController() != null) {
cpSection.set("controller", cp.getDefaultController().name());
}
}
}
// bombs
if (warzone.getBombs().size() > 0) {
ConfigurationSection bombsSection = warzoneInfoSection.createSection("bomb");
List<String> bombNames = new ArrayList<String>();
for (Bomb bomb : warzone.getBombs()) {
bombNames.add(bomb.getName());
}
bombsSection.set("names", bombNames);
for (Bomb bomb : warzone.getBombs()) {
ConfigurationSection bombSection = bombsSection.createSection(bomb.getName());
bombSection.set("x", bomb.getLocation().getBlockX());
bombSection.set("y", bomb.getLocation().getBlockY());
@ -566,7 +621,7 @@ public class WarzoneYmlMapper {
bombSection.set("yaw", toIntYaw(bomb.getLocation().getYaw()));
}
}
// cakes
if (warzone.getCakes().size() > 0) {
ConfigurationSection cakesSection = warzoneInfoSection.createSection("cake");
@ -673,7 +728,16 @@ public class WarzoneYmlMapper {
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
}
}
// capture point blocks
for (CapturePoint cp : warzone.getCapturePoints()) {
try {
ZoneVolumeMapper.saveStructure(cp.getVolume(), connection);
} catch (SQLException e) {
War.war.getLogger().log(Level.WARNING, "Failed to save warzone structures volume", e);
}
}
// bomb blocks
for (Bomb bomb : warzone.getBombs()) {
try {

View File

@ -0,0 +1,169 @@
package com.tommytony.war.structure;
import com.tommytony.war.Warzone;
import com.tommytony.war.config.TeamKind;
import com.tommytony.war.volume.Volume;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockState;
import org.bukkit.util.Vector;
/**
* Capture points
*
* @author Connor Monahan
*/
public class CapturePoint {
private static int[][][] structure = {
{
{1, 1, 1},
{1, 2, 1},
{1, 1, 1}
},
{
{0, 0, 0},
{0, 3, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 3, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 3, 0},
{0, 0, 0}
},
{
{0, 0, 0},
{0, 3, 0},
{0, 0, 0}
}
};
private final String name;
private Volume volume;
private Location location;
private TeamKind controller, defaultController;
private int strength;
private Warzone warzone;
public CapturePoint(String name, Location location, TeamKind defaultController, int strength, Warzone warzone) {
this.name = name;
this.defaultController = defaultController;
this.controller = defaultController;
this.strength = strength;
this.warzone = warzone;
this.volume = new Volume("cp-" + name, warzone.getWorld());
this.setLocation(location);
}
private Location getOrigin() {
return location.clone().subtract(1, 1, 1).getBlock().getLocation();
}
public void updateBlocks() {
Validate.notNull(location);
// Set origin to back left corner
Location origin = this.getOrigin();
// Build structure
for (int y = 0; y < structure.length; y++) {
for (int z = 0; z < structure[0].length; z++) {
for (int x = 0; x < structure[0][0].length; x++) {
BlockState state = origin.clone().add(x, y, z).getBlock().getState();
switch (structure[y][z][x]) {
case 0:
state.setType(Material.AIR);
break;
case 1:
state.setType(this.warzone.getWarzoneMaterials().getMainBlock().getType());
state.setData(this.warzone.getWarzoneMaterials().getMainBlock().getData());
break;
case 2:
state.setType(this.warzone.getWarzoneMaterials().getLightBlock().getType());
state.setData(this.warzone.getWarzoneMaterials().getLightBlock().getData());
break;
case 3:
state.setType(this.warzone.getWarzoneMaterials().getStandBlock().getType());
state.setData(this.warzone.getWarzoneMaterials().getStandBlock().getData());
break;
default:
throw new IllegalStateException("Invalid structure");
}
state.update(true);
}
}
}
// Add flag block
if (strength > 0 && controller != null) {
// Make flag point direction of player when setting the capture point
Vector dir = new Vector(1 + -Math.round(Math.sin(Math.toRadians(location.getYaw()))), strength,
1 + Math.round(Math.cos(Math.toRadians(location.getYaw()))));
BlockState state = origin.clone().add(dir).getBlock().getState();
state.setType(controller.getMaterial());
state.setData(controller.getBlockData());
state.update(true);
}
}
public String getName() {
return name;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = new Location(location.getWorld(), location.getBlockX(), location.getBlockY(),
location.getBlockZ(), location.getYaw(), 0);
this.volume.setCornerOne(this.getOrigin());
this.volume.setCornerTwo(this.getOrigin().add(structure[0][0].length, structure.length, structure[0].length));
this.volume.saveBlocks();
this.updateBlocks();
}
public TeamKind getDefaultController() {
return defaultController;
}
public TeamKind getController() {
return controller;
}
public void setController(TeamKind controller) {
this.controller = controller;
if (strength > 0) {
this.updateBlocks();
}
}
public int getStrength() {
return strength;
}
public void setStrength(int strength) {
this.strength = strength;
this.updateBlocks();
}
public Volume getVolume() {
return volume;
}
public void setVolume(Volume volume) {
this.volume = volume;
}
public void reset() {
this.controller = defaultController;
if (this.controller != null) {
this.strength = 4;
} else {
this.strength = 0;
}
this.updateBlocks();
}
}

View File

@ -129,6 +129,12 @@ commands:
usage: Creates or moves a monument. Monuments can be capture with wool from your team and give your health. Must be standing in warzone.
Ex -
/setmonument <monument-name>
setcapturepoint:
description: War> Creates or moves a capture point. Capture points build strength and award points.
aliases: [setcp]
usage: Creates or moves a capture point. Capture points build strength and award points. Must be standing in warzone.
Ex -
/setcapturepoint <capture point name>
setteamflag:
description: War> Creates/moves a team flag post for CTF.
usage: Creates/moves a team flag post for CTF. Must be standing in warzone.
@ -174,6 +180,12 @@ commands:
usage: Deletes the monument. Provide a zone name if not standing in warzone or lobby.
Ex -
/deletemonument [zone-name] <monument-name>
deletecapturepoint:
description: War> Deletes the capture point.
aliases: [deletecp]
usage: Deletes the capture point. Provide a zone name if not standing in warzone or lobby.
Ex -
/deletecapturepoint [zone-name] <capture point name>
deletebomb:
description: War> Deletes the bomb.
usage: Deletes the bomb. Provide a zone name if not standing in warzone or lobby.