/**
* BetonQuest - advanced quests for Bukkit
* Copyright (C) 2016 Jakub "Co0sh" Sapalski
*
* 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 3 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package pl.betoncraft.betonquest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import pl.betoncraft.betonquest.config.Config;
import pl.betoncraft.betonquest.config.ConfigPackage;
import pl.betoncraft.betonquest.database.PlayerData;
import pl.betoncraft.betonquest.utils.Debug;
import pl.betoncraft.betonquest.utils.LocationData;
import pl.betoncraft.betonquest.utils.PlayerConverter;
/**
* Handler for global locations.
*
* @author Jakub Sapalski
*/
public class GlobalLocations extends BukkitRunnable {
private List<GlobalLocation> locations = new ArrayList<GlobalLocation>();
private final List<GlobalLocation> finalLocations;
private static GlobalLocations instance;
/**
* Creates new instance of global locations handler.
*/
public GlobalLocations() {
instance = this;
// get list of global locations and make it final
for (ConfigPackage pack : Config.getPackages().values()) {
String rawGlobalLocations = pack.getString("main.global_locations");
if (rawGlobalLocations == null || rawGlobalLocations.equals("")) {
continue;
}
String[] parts = rawGlobalLocations.split(",");
for (String objective : parts) {
try {
ObjectiveID objectiveID = new ObjectiveID(pack, objective);
GlobalLocation gL = new GlobalLocation(objectiveID);
locations.add(gL);
} catch (ObjectNotFoundException | InstructionParseException e) {
Debug.error("Error while parsing global location objective '" + objective + "': " + e.getMessage());
}
}
}
finalLocations = locations;
}
/**
* Stops active global locations timer
*/
public static void stop() {
instance.cancel();
}
@Override
public void run() {
// do nothing if there is no defined locations
if (finalLocations == null) {
this.cancel();
return;
}
// loop all online players
Collection<? extends Player> players = Bukkit.getOnlinePlayers();
for (Player player : players) {
String playerID = PlayerConverter.getID(player);
// for each player loop all available locations
locations: for (GlobalLocation location : finalLocations) {
// if location is not set, stop everything, there is an error in config
if (location.getLocation() == null) {
continue locations;
}
// if player is inside location, do stuff
Location loc;
double distance;
try {
loc = location.getLocation().getLocation(playerID);
distance = location.getRange().getDouble(playerID);
} catch (QuestRuntimeException e) {
Debug.error("Error while parsing location in global location '" + location.getObjectiveID()
+ "': " + e.getMessage());
continue;
}
if (player.getLocation().getWorld().equals(loc.getWorld())
&& player.getLocation().distanceSquared(loc) <= distance*distance) {
// check if player has already triggered this location
PlayerData playerData = BetonQuest.getInstance().getPlayerData(playerID);
if (playerData.hasTag(location.getTag())) {
continue locations;
}
// check all conditions
if (location.getConditions() != null) {
for (ConditionID condition : location.getConditions()) {
if (!BetonQuest.condition(playerID, condition)) {
// if some conditions are not met, skip to next location
continue locations;
}
}
}
// set the tag, player has triggered this location
playerData.addTag(location.getTag());
// fire all events for the location
for (EventID event : location.getEvents()) {
BetonQuest.event(playerID, event);
}
}
}
}
}
/**
* Represents single global location.
*
* @author Co0sh
*/
private class GlobalLocation {
private ObjectiveID objectiveID;
private LocationData location;
private VariableNumber range;
private ConditionID[] conditions;
private EventID[] events;
private String tag;
/**
* Creates new global location using objective event's ID.
*
* @param event
* ID of the event
* @throws InstructionParseException
*/
public GlobalLocation(ObjectiveID objectiveID) throws InstructionParseException {
this.objectiveID = objectiveID;
Debug.info("Creating new GlobalLocation from " + objectiveID + " event.");
Instruction instruction = objectiveID.generateInstruction();
// check amount of arguments in event's instruction
location = instruction.getLocation();
range = instruction.getVarNum();
// extract all conditions and events
String[] tempConditions1 = instruction.getArray(instruction.getOptional("condition")),
tempConditions2 = instruction.getArray(instruction.getOptional("conditions"));
int length = tempConditions1.length + tempConditions2.length;
conditions = new ConditionID[length];
for (int i = 0; i < length; i++) {
String condition = (i >= tempConditions1.length) ? tempConditions2[i - tempConditions1.length] : tempConditions1[i];
try {
conditions[i] = new ConditionID(instruction.getPackage(), condition);
} catch (ObjectNotFoundException e) {
throw new InstructionParseException("Error while parsing event conditions: " + e.getMessage());
}
}
String[] tempEvents1 = instruction.getArray(instruction.getOptional("event")),
tempEvents2 = instruction.getArray(instruction.getOptional("events"));
length = tempEvents1.length + tempEvents2.length;
events = new EventID[length];
for (int i = 0; i < length; i++) {
String event = (i >= tempEvents1.length) ? tempEvents2[i - tempEvents1.length] : tempEvents1[i];
try {
events[i] = new EventID(instruction.getPackage(), event);
} catch (ObjectNotFoundException e) {
throw new InstructionParseException("Error while parsing objective events: " + e.getMessage());
}
}
tag = objectiveID.getPackage().getName() + ".global_" + objectiveID;
}
/**
* @return the objectiveID of this global location
*/
public ObjectiveID getObjectiveID() {
return objectiveID;
}
/**
* @return the location
*/
public LocationData getLocation() {
return location;
}
/**
* @return the range variable
*/
public VariableNumber getRange() {
return range;
}
/**
* @return the conditions
*/
public ConditionID[] getConditions() {
return conditions;
}
/**
* @return the events
*/
public EventID[] getEvents() {
return events;
}
/**
* @return the tag required to pass this global location
*/
public String getTag() {
return tag;
}
}
}