Numerous COTW tweaks

This commit is contained in:
nossr50
2019-07-01 23:50:30 -07:00
parent a66940b2b8
commit 53d6065185
17 changed files with 553 additions and 203 deletions

View File

@ -198,41 +198,41 @@ public class Config extends AutoUpdateConfigLoader {
reason.add("Cannot use the same item for Repair and Salvage anvils!");
}
if (getTamingCOTWMaterial(EntityType.WOLF) == null) {
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!");
}
if (getTamingCOTWMaterial(EntityType.OCELOT) == null) {
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!");
}
if (getTamingCOTWMaterial(EntityType.HORSE) == null) {
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!");
}
if (getTamingCOTWCost(EntityType.WOLF) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!");
}
if (getTamingCOTWCost(EntityType.OCELOT) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!");
}
if (getTamingCOTWCost(EntityType.HORSE) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!");
}
if (getTamingCOTWAmount(EntityType.WOLF) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!");
}
if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!");
}
if (getTamingCOTWAmount(EntityType.HORSE) <= 0) {
reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!");
}
// if (getTamingCOTWMaterial(EntityType.WOLF) == null) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!");
// }
//
// if (getTamingCOTWMaterial(EntityType.OCELOT) == null) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!");
// }
//
// if (getTamingCOTWMaterial(EntityType.HORSE) == null) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!");
// }
//
// if (getTamingCOTWCost(EntityType.WOLF) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!");
// }
//
// if (getTamingCOTWCost(EntityType.OCELOT) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!");
// }
//
// if (getTamingCOTWCost(EntityType.HORSE) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!");
// }
//
// if (getTamingCOTWAmount(EntityType.WOLF) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!");
// }
//
// if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!");
// }
//
// if (getTamingCOTWAmount(EntityType.HORSE) <= 0) {
// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!");
// }
return noErrorsInConfig(reason);
}
@ -529,12 +529,17 @@ public class Config extends AutoUpdateConfigLoader {
public int getSwordsGate() { return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10); }
/* Taming */
public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); }
public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); }
public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); }
public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); }
public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); }
public double getTamingCOTWRange() { return config.getDouble("Skills.Taming.Call_Of_The_Wild.Range", 40.0D); }
// public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); }
// public int getTamingCOTWCost(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Amount"); }
// public int getTamingCOTWAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Summon_Amount"); }
// public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); }
// public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); }
public Material getTamingCOTWMaterial(String cotwEntity) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material")); }
public int getTamingCOTWCost(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Amount"); }
public int getTamingCOTWAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Amount"); }
public int getTamingCOTWLength(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Summon_Length"); }
public int getTamingCOTWMaxAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Per_Player_Limit", 1); }
/* Woodcutting */
public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) { return config.getBoolean("Bonus_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material)); }

View File

@ -147,6 +147,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
public boolean isEndermanEndermiteFarmingPrevented() { return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true); }
public boolean isPistonExploitPrevented() { return config.getBoolean("ExploitFix.Pistons", false); }
public boolean allowUnsafeEnchantments() { return config.getBoolean("ExploitFix.UnsafeEnchantments", false); }
public boolean isCOTWBreedingPrevented() { return config.getBoolean("ExploitFix.COTWBreeding", true); }
public boolean isFishingExploitingPrevented() { return config.getBoolean("ExploitFix.Fishing", true); }
public boolean isAcrobaticsExploitingPrevented() { return config.getBoolean("ExploitFix.Acrobatics", true); }

View File

@ -1026,8 +1026,8 @@ public class McMMOPlayer {
*/
public void logout(boolean syncSave) {
Player thisPlayer = getPlayer();
resetAbilityMode();
BleedTimerTask.bleedOut(thisPlayer);
BleedTimerTask.bleedOut(getPlayer());
cleanup();
if (syncSave) {
getProfile().save(true);
@ -1047,4 +1047,15 @@ public class McMMOPlayer {
//Remove user from cache
mcMMO.getDatabaseManager().cleanupUser(thisPlayer.getUniqueId());
}
/**
* Cleanup various things related to this player
* Such as temporary summons..
* Turning off abilities...
* Etc...
*/
public void cleanup() {
resetAbilityMode();
getTamingManager().cleanupAllSummons();
}
}

View File

@ -0,0 +1,26 @@
package com.gmail.nossr50.datatypes.skills.subskills.taming;
import com.gmail.nossr50.util.StringUtils;
import org.bukkit.entity.EntityType;
public enum CallOfTheWildType {
WOLF,
CAT,
HORSE;
//TODO: This is a hacky fix to make the COTW code in 2.1 more bearable, this will be removed upon the rework planned for COTW
public String getConfigEntityTypeEntry() {
switch(this) {
case CAT:
return StringUtils.getPrettyEntityTypeString(EntityType.OCELOT); //Even though cats will be summoned in 1.14, we specify Ocelot here. This will be gone in 2.2
case WOLF:
return StringUtils.getPrettyEntityTypeString(EntityType.WOLF);
case HORSE:
return StringUtils.getPrettyEntityTypeString(EntityType.HORSE);
}
return null;
}
}

View File

@ -0,0 +1,87 @@
package com.gmail.nossr50.datatypes.skills.subskills.taming;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
/**
* Data Container for properties used in summoning an entity via COTW
*/
public class TamingSummon {
private Material itemType;
private int itemAmountRequired;
private int entitiesSummoned;
private int summonLifespan;
private int summonCap;
private CallOfTheWildType callOfTheWildType;
private EntityType entityType;
public TamingSummon(CallOfTheWildType callOfTheWildType, Material itemType, int itemAmountRequired, int entitiesSummoned, int summonLifespan, int summonCap) {
this.callOfTheWildType = callOfTheWildType;
this.itemType = itemType;
this.itemAmountRequired = Math.max(itemAmountRequired, 1);
this.entitiesSummoned = Math.max(entitiesSummoned, 1);
this.summonLifespan = summonLifespan;
this.summonCap = Math.max(summonCap, 1);
initEntityType();
}
private void initEntityType() {
switch(callOfTheWildType) {
case WOLF:
entityType = EntityType.WOLF;
break;
case HORSE:
entityType = EntityType.HORSE;
break;
case CAT:
if(shouldSpawnCatInsteadOfOcelot()) {
//Server is on 1.14 or above
entityType = EntityType.CAT;
} else {
//Server is not on 1.14 or above
entityType = EntityType.OCELOT;
}
}
}
private boolean shouldSpawnCatInsteadOfOcelot() {
try {
Class<?> clazz = Class.forName("org.bukkit.entity.Panda");
//Panda exists which means this is at least 1.14, so we should spawn a cat instead of ocelot
return true;
} catch (ClassNotFoundException e) {
/*e.printStackTrace();*/
return false;
}
}
public EntityType getEntityType() {
return entityType;
}
public Material getItemType() {
return itemType;
}
public int getItemAmountRequired() {
return itemAmountRequired;
}
public int getEntitiesSummoned() {
return entitiesSummoned;
}
public int getSummonLifespan() {
return summonLifespan;
}
public int getSummonCap() {
return summonCap;
}
public CallOfTheWildType getCallOfTheWildType() {
return callOfTheWildType;
}
}

View File

@ -21,6 +21,7 @@ import com.gmail.nossr50.skills.unarmed.UnarmedManager;
import com.gmail.nossr50.util.BlockUtils;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.Permissions;
import com.gmail.nossr50.util.player.NotificationManager;
import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.skills.CombatUtils;
@ -733,6 +734,20 @@ public class EntityListener implements Listener {
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityBreed(EntityBreedEvent event) {
if(ExperienceConfig.getInstance().isCOTWBreedingPrevented()) {
if(event.getFather().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON) || event.getMother().hasMetadata(mcMMO.COTW_TEMPORARY_SUMMON)) {
event.setCancelled(true);
}
if(event.getBreeder() instanceof Player) {
Player player = (Player) event.getBreeder();
NotificationManager.sendPlayerInformationChatOnly(player, "Taming.Summon.COTW.BreedingDisallowed");
}
}
}
/**
* Handle ExplosionPrime events that involve modifying the event.
*

View File

@ -11,6 +11,7 @@ import com.gmail.nossr50.datatypes.party.Party;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
@ -827,13 +828,13 @@ public class PlayerListener implements Listener {
Material type = heldItem.getType();
TamingManager tamingManager = mcMMOPlayer.getTamingManager();
if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.WOLF)) {
if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) {
tamingManager.summonWolf();
}
else if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.OCELOT)) {
else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) {
tamingManager.summonOcelot();
}
else if (type == Config.getInstance().getTamingCOTWMaterial(EntityType.HORSE)) {
else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) {
tamingManager.summonHorse();
}

View File

@ -108,6 +108,7 @@ public class mcMMO extends JavaPlugin {
/* Metadata Values */
public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker";
public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage";
public static final String COTW_TEMPORARY_SUMMON = "mcMMO: COTW Entity";
public final static String entityMetadataKey = "mcMMO: Spawned Entity";
public final static String blockMetadataKey = "mcMMO: Piston Tracking";
public final static String furnaceMetadataKey = "mcMMO: Tracked Furnace";

View File

@ -8,7 +8,8 @@ import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.events.fake.FakeEntityTameEvent;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
import com.gmail.nossr50.datatypes.skills.subskills.taming.TamingSummon;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.runnables.skills.BleedTimerTask;
@ -22,7 +23,10 @@ import com.gmail.nossr50.util.random.RandomChanceUtil;
import com.gmail.nossr50.util.skills.ParticleEffectUtils;
import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillActivationType;
import com.gmail.nossr50.util.sounds.SoundManager;
import com.gmail.nossr50.util.sounds.SoundType;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.*;
import org.bukkit.inventory.ItemStack;
@ -32,11 +36,66 @@ import java.util.HashMap;
import java.util.List;
public class TamingManager extends SkillManager {
//TODO: Temporary static cache, will be changed in 2.2
private static HashMap<Material, CallOfTheWildType> summoningItems;
private static HashMap<CallOfTheWildType, TamingSummon> cotwSummonDataProperties;
private long lastSummonTimeStamp;
private HashMap<CallOfTheWildType, List<TrackedTamingEntity>> playerSummonedEntities;
public TamingManager(McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, PrimarySkillType.TAMING);
init();
}
private static HashMap<EntityType, List<TrackedTamingEntity>> summonedEntities = new HashMap<EntityType, List<TrackedTamingEntity>>();
//TODO: Hacky stuff for 2.1, will be cleaned up in 2.2
private void init() {
//prevents accidentally summoning too many things when holding down left click
lastSummonTimeStamp = 0L;
//Init per-player tracking of summoned entities
initPerPlayerSummonTracking();
//Hacky stuff used as a band-aid
initStaticCaches();
}
private void initPerPlayerSummonTracking() {
playerSummonedEntities = new HashMap<>();
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
playerSummonedEntities.put(callOfTheWildType, new ArrayList<TrackedTamingEntity>());
}
}
private void initStaticCaches() {
//TODO: Temporary static cache, will be changed in 2.2
//This is shared between instances of TamingManager
if(summoningItems == null) {
summoningItems = new HashMap<>();
summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT);
summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF);
summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE);
}
//TODO: Temporary static cache, will be changed in 2.2
//This is shared between instances of TamingManager
if(cotwSummonDataProperties == null) {
cotwSummonDataProperties = new HashMap<>();
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
Material itemSummonMaterial = Config.getInstance().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry());
int itemAmountRequired = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry());
int entitiesSummonedPerCOTW = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry());
int summonLifespanSeconds = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry());
int perPlayerMaxAmount = Config.getInstance().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry());
TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, perPlayerMaxAmount);
cotwSummonDataProperties.put(callOfTheWildType, tamingSummon);
}
}
}
public boolean canUseThickFur() {
return RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_THICK_FUR)
@ -98,7 +157,6 @@ public class TamingManager extends SkillManager {
* @param damage The damage being absorbed by the wolf
*/
public void fastFoodService(Wolf wolf, double damage) {
//static chance (3rd param)
if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.TAMING_FAST_FOOD_SERVICE, getPlayer())) {
return;
}
@ -150,7 +208,7 @@ public class TamingManager extends SkillManager {
return;
}
callOfTheWild(EntityType.OCELOT, Config.getInstance().getTamingCOTWCost(EntityType.OCELOT));
processCallOfTheWild();
}
/**
@ -164,7 +222,7 @@ public class TamingManager extends SkillManager {
return;
}
callOfTheWild(EntityType.WOLF, Config.getInstance().getTamingCOTWCost(EntityType.WOLF));
processCallOfTheWild();
}
/**
@ -178,7 +236,7 @@ public class TamingManager extends SkillManager {
return;
}
callOfTheWild(EntityType.HORSE, Config.getInstance().getTamingCOTWCost(EntityType.HORSE));
processCallOfTheWild();
}
/**
@ -257,151 +315,243 @@ public class TamingManager extends SkillManager {
}
}
private void processCallOfTheWild() {
//Prevent summoning too many things accidentally if a player holds down the button
if(lastSummonTimeStamp + 150 > System.currentTimeMillis()) {
return;
} else {
lastSummonTimeStamp = System.currentTimeMillis();
}
Player player = getPlayer();
ItemStack itemInMainHand = player.getInventory().getItemInMainHand();
//Check if the item the player is currently holding is a COTW item
if(isCOTWItem(itemInMainHand)) {
//Get the summoning type
CallOfTheWildType callOfTheWildType = summoningItems.get(itemInMainHand.getType());
TamingSummon tamingSummon = cotwSummonDataProperties.get(callOfTheWildType);
//Check to see if players have the correct amount of the item required to summon
if(itemInMainHand.getAmount() >= tamingSummon.getItemAmountRequired()) {
//Initial Spawn location
Location spawnLocation = Misc.getLocationOffset(player.getLocation(), 1);
//COTW can summon multiple entities per usage
for (int i = 0; i < tamingSummon.getEntitiesSummoned(); i++) {
if (getAmountCurrentlySummoned(callOfTheWildType) >= tamingSummon.getSummonCap()) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Taming.Summon.COTW.Limit", String.valueOf(tamingSummon.getSummonCap()));
break;
}
spawnLocation = Misc.getLocationOffset(spawnLocation, 1);
spawnCOTWEntity(callOfTheWildType, spawnLocation, tamingSummon.getEntityType());
}
//Remove the items used to summon
int itemAmountAfterPayingCost = itemInMainHand.getAmount() - tamingSummon.getItemAmountRequired();
itemInMainHand.setAmount(itemAmountAfterPayingCost);
player.updateInventory();
//Inform the player about what they have just done
if (tamingSummon.getSummonLifespan() > 0) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.COTW.Success",
StringUtils.getCapitalized(callOfTheWildType.toString()), String.valueOf(tamingSummon.getSummonLifespan()));
} else {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.Complete");
}
//Send Sound
SoundManager.sendSound(player, player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC);
} else {
//Player did not have enough of the item in their main hand
int difference = tamingSummon.getItemAmountRequired() - itemInMainHand.getAmount();
NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.NotEnough", String.valueOf(difference), StringUtils.getPrettyItemString(itemInMainHand.getType()));
}
}
}
private void spawnCOTWEntity(CallOfTheWildType callOfTheWildType, Location spawnLocation, EntityType entityType) {
switch(callOfTheWildType) {
case CAT:
//Entity type is needed for cats because in 1.13 and below we spawn ocelots, in 1.14 and above we spawn cats
spawnCat(spawnLocation, entityType);
break;
case HORSE:
spawnHorse(spawnLocation);
break;
case WOLF:
spawnWolf(spawnLocation);
break;
}
}
private void spawnWolf(Location spawnLocation) {
LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.WOLF);
//This is used to prevent XP gains for damaging this entity
applyMetaDataToCOTWEntity(callOfWildEntity);
setBaseCOTWEntityProperties(callOfWildEntity);
addToTracker(callOfWildEntity, CallOfTheWildType.WOLF);
//Setup wolf stats
callOfWildEntity.setMaxHealth(20.0);
callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.WOLF)));
}
private void spawnCat(Location spawnLocation, EntityType entityType) {
LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, entityType);
//This is used to prevent XP gains for damaging this entity
applyMetaDataToCOTWEntity(callOfWildEntity);
setBaseCOTWEntityProperties(callOfWildEntity);
addToTracker(callOfWildEntity, CallOfTheWildType.CAT);
//Randomize the cat
if(callOfWildEntity instanceof Ocelot) {
int numberOfTypes = Ocelot.Type.values().length;
((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]);
} else if(callOfWildEntity instanceof Cat) {
int numberOfTypes = Cat.Type.values().length;
((Cat) callOfWildEntity).setCatType(Cat.Type.values()[Misc.getRandom().nextInt(numberOfTypes)]);
}
callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(entityType)));
//Particle effect
ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity);
}
private void spawnHorse(Location spawnLocation) {
LivingEntity callOfWildEntity = (LivingEntity) getPlayer().getWorld().spawnEntity(spawnLocation, EntityType.HORSE);
applyMetaDataToCOTWEntity(callOfWildEntity);
setBaseCOTWEntityProperties(callOfWildEntity);
addToTracker(callOfWildEntity, CallOfTheWildType.HORSE);
//Randomize Horse
Horse horse = (Horse) callOfWildEntity;
callOfWildEntity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15));
callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]);
horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]);
horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength())));
//TODO: setSpeed, once available
callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", getPlayer().getName(), StringUtils.getPrettyEntityTypeString(EntityType.HORSE)));
//Particle effect
ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity);
}
private void setBaseCOTWEntityProperties(LivingEntity callOfWildEntity) {
((Tameable) callOfWildEntity).setOwner(getPlayer());
callOfWildEntity.setRemoveWhenFarAway(false);
}
private void applyMetaDataToCOTWEntity(LivingEntity callOfWildEntity) {
//This is used to prevent XP gains for damaging this entity
callOfWildEntity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
//This helps identify the entity as being summoned by COTW
callOfWildEntity.setMetadata(mcMMO.COTW_TEMPORARY_SUMMON, mcMMO.metadataValue);
}
/**
* Handle the Call of the Wild ability.
*
* @param type The type of entity to summon.
* @param summonAmount The amount of material needed to summon the entity
* Whether or not the itemstack is used for COTW
* @param itemStack target ItemStack
* @return true if it is used for any COTW
*/
private void callOfTheWild(EntityType type, int summonAmount) {
Player player = getPlayer();
ItemStack heldItem = player.getInventory().getItemInMainHand();
int heldItemAmount = heldItem.getAmount();
Location location = player.getLocation();
if (heldItemAmount < summonAmount) {
int moreAmount = summonAmount - heldItemAmount;
NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.NotEnough", String.valueOf(moreAmount), StringUtils.getPrettyItemString(heldItem.getType()));
return;
}
if (!rangeCheck(type)) {
return;
}
int amount = Config.getInstance().getTamingCOTWAmount(type);
int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(type);
for (int i = 0; i < amount; i++) {
if (!summonAmountCheck(type)) {
return;
}
location = Misc.getLocationOffset(location, 1);
LivingEntity callOfWildEntity = (LivingEntity) player.getWorld().spawnEntity(location, type);
FakeEntityTameEvent event = new FakeEntityTameEvent(callOfWildEntity, player);
mcMMO.p.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
continue;
}
callOfWildEntity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
((Tameable) callOfWildEntity).setOwner(player);
callOfWildEntity.setRemoveWhenFarAway(false);
addToTracker(callOfWildEntity);
switch (type) {
case OCELOT:
((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[1 + Misc.getRandom().nextInt(3)]);
break;
case WOLF:
callOfWildEntity.setMaxHealth(20.0);
callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
break;
case HORSE:
Horse horse = (Horse) callOfWildEntity;
callOfWildEntity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15));
callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]);
horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]);
horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength())));
//TODO: setSpeed, once available
break;
default:
break;
}
if (Permissions.renamePets(player)) {
callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", player.getName(), StringUtils.getPrettyEntityTypeString(type)));
}
ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity);
}
ItemStack leftovers = new ItemStack(heldItem);
leftovers.setAmount(heldItemAmount - summonAmount);
player.getInventory().setItemInMainHand(heldItemAmount == summonAmount ? null : leftovers);
String lifeSpan = "";
if (tamingCOTWLength > 0) {
lifeSpan = LocaleLoader.getString("Taming.Summon.Lifespan", tamingCOTWLength);
}
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Taming.Summon.Complete", lifeSpan);
player.playSound(location, Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1F, 0.5F);
public boolean isCOTWItem(ItemStack itemStack) {
return summoningItems.containsKey(itemStack.getType());
}
private boolean rangeCheck(EntityType type) {
double range = Config.getInstance().getTamingCOTWRange();
Player player = getPlayer();
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
private int getAmountCurrentlySummoned(CallOfTheWildType callOfTheWildType) {
//The tracker is unreliable so validate its contents first
recalibrateTracker();
if (range == 0) {
return true;
return playerSummonedEntities.get(callOfTheWildType).size();
}
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
private void addToTracker(LivingEntity livingEntity, CallOfTheWildType callOfTheWildType) {
TrackedTamingEntity trackedEntity = new TrackedTamingEntity(livingEntity, callOfTheWildType, this);
playerSummonedEntities.get(callOfTheWildType).add(trackedEntity);
}
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
public List<TrackedTamingEntity> getTrackedEntities(CallOfTheWildType callOfTheWildType) {
return playerSummonedEntities.get(callOfTheWildType);
}
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
public void removeFromTracker(TrackedTamingEntity trackedEntity) {
if(playerSummonedEntities.get(trackedEntity.getCallOfTheWildType()).contains(trackedEntity))
playerSummonedEntities.get(trackedEntity.getCallOfTheWildType()).remove(trackedEntity);
NotificationManager.sendPlayerInformationChatOnly(getPlayer(), "Taming.Summon.COTW.TimeExpired", StringUtils.getPrettyEntityTypeString(trackedEntity.getLivingEntity().getType()));
}
/**
* Builds a new tracked list by determining which tracked things are still valid
*/
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
private void recalibrateTracker() {
for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) {
ArrayList<TrackedTamingEntity> validEntities = getValidTrackedEntities(callOfTheWildType);
playerSummonedEntities.put(callOfTheWildType, validEntities); //Replace the old list with the new list
}
}
for (Entity entity : player.getNearbyEntities(range, range, range)) {
if (entity.getType() == type) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, Taming.getCallOfTheWildFailureMessage(type));
return false;
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
private ArrayList<TrackedTamingEntity> getValidTrackedEntities(CallOfTheWildType callOfTheWildType) {
ArrayList<TrackedTamingEntity> validTrackedEntities = new ArrayList<>();
for(TrackedTamingEntity trackedTamingEntity : getTrackedEntities(callOfTheWildType)) {
LivingEntity livingEntity = trackedTamingEntity.getLivingEntity();
//Remove from existence
if(livingEntity != null && livingEntity.isValid()) {
validTrackedEntities.add(trackedTamingEntity);
}
}
return true;
return validTrackedEntities;
}
private boolean summonAmountCheck(EntityType entityType) {
Player player = getPlayer();
/**
* Remove all tracked entities from existence if they currently exist
* Clear the tracked entity lists afterwards
*/
//TODO: The way this tracker was written is garbo, I should just rewrite it, I'll save that for a future update
public void cleanupAllSummons() {
for(List<TrackedTamingEntity> trackedTamingEntities : playerSummonedEntities.values()) {
for(TrackedTamingEntity trackedTamingEntity : trackedTamingEntities) {
LivingEntity livingEntity = trackedTamingEntity.getLivingEntity();
int maxAmountSummons = Config.getInstance().getTamingCOTWMaxAmount(entityType);
//Remove from existence
if(livingEntity != null && livingEntity.isValid()) {
livingEntity.remove();
}
}
if (maxAmountSummons <= 0) {
return true;
//Clear the list
trackedTamingEntities.clear();
}
List<TrackedTamingEntity> trackedEntities = getTrackedEntities(entityType);
int summonAmount = trackedEntities == null ? 0 : trackedEntities.size();
if (summonAmount >= maxAmountSummons) {
NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Taming.Summon.Fail.TooMany", String.valueOf(maxAmountSummons));
return false;
}
return true;
}
protected static void addToTracker(LivingEntity livingEntity) {
TrackedTamingEntity trackedEntity = new TrackedTamingEntity(livingEntity);
if (!summonedEntities.containsKey(livingEntity.getType())) {
summonedEntities.put(livingEntity.getType(), new ArrayList<TrackedTamingEntity>());
}
summonedEntities.get(livingEntity.getType()).add(trackedEntity);
}
protected static List<TrackedTamingEntity> getTrackedEntities(EntityType entityType) {
return summonedEntities.get(entityType);
}
protected static void removeFromTracker(TrackedTamingEntity trackedEntity) {
summonedEntities.get(trackedEntity.getLivingEntity().getType()).remove(trackedEntity);
}
}

View File

@ -1,6 +1,7 @@
package com.gmail.nossr50.skills.taming;
import com.gmail.nossr50.config.Config;
import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.Misc;
import com.gmail.nossr50.util.skills.CombatUtils;
@ -15,14 +16,18 @@ import java.util.UUID;
public class TrackedTamingEntity extends BukkitRunnable {
private LivingEntity livingEntity;
private final CallOfTheWildType callOfTheWildType;
private UUID id;
private int length;
private final TamingManager tamingManagerRef;
protected TrackedTamingEntity(LivingEntity livingEntity) {
protected TrackedTamingEntity(LivingEntity livingEntity, CallOfTheWildType callOfTheWildType, TamingManager tamingManagerRef) {
this.tamingManagerRef = tamingManagerRef;
this.callOfTheWildType = callOfTheWildType;
this.livingEntity = livingEntity;
this.id = livingEntity.getUniqueId();
int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(livingEntity.getType());
int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry());
if (tamingCOTWLength > 0) {
this.length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR;
@ -36,18 +41,25 @@ public class TrackedTamingEntity extends BukkitRunnable {
Location location = livingEntity.getLocation();
location.getWorld().playSound(location, Sound.BLOCK_FIRE_EXTINGUISH, 0.8F, 0.8F);
ParticleEffectUtils.playCallOfTheWildEffect(livingEntity);
CombatUtils.dealDamage(livingEntity, livingEntity.getMaxHealth(), DamageCause.SUICIDE, livingEntity);
if(tamingManagerRef != null)
tamingManagerRef.removeFromTracker(this);
livingEntity.remove();
}
TamingManager.removeFromTracker(this);
this.cancel();
}
protected LivingEntity getLivingEntity() {
public CallOfTheWildType getCallOfTheWildType() {
return callOfTheWildType;
}
public LivingEntity getLivingEntity() {
return livingEntity;
}
protected UUID getID() {
public UUID getID() {
return id;
}
}

View File

@ -192,7 +192,6 @@ public final class Permissions {
/* TAMING */
public static boolean callOfTheWild(Permissible permissible, EntityType type) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild." + type.toString().toLowerCase()); }
public static boolean renamePets(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.taming.callofthewild.renamepets"); }
/* UNARMED */
public static boolean berserk(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.unarmed.berserk"); }

View File

@ -46,8 +46,9 @@ public final class UserManager {
McMMOPlayer mcMMOPlayer = getPlayer(player);
player.removeMetadata(mcMMO.playerDataKey, mcMMO.p);
if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer))
if(playerDataSet != null && playerDataSet.contains(mcMMOPlayer)) {
playerDataSet.remove(mcMMOPlayer); //Clear sync save tracking
}
}
/**

View File

@ -391,23 +391,19 @@ Skills:
Item_Amount: 10
Summon_Amount: 1
Summon_Length: 240
Summon_Max_Amount: 10
Per_Player_Limit: 2
Ocelot:
Item_Material: COD
Item_Amount: 10
Summon_Amount: 1
Summon_Length: 240
Summon_Max_Amount: 10
Per_Player_Limit: 1
Horse:
Item_Material: APPLE
Item_Amount: 10
Summon_Amount: 1
Summon_Length: 240
Summon_Max_Amount: 10
# Range to check for nearby pets when using Call Of The Wild, 0 will disable the check
Range: 40.0
Per_Player_Limit: 1
Unarmed:
Enabled_For_PVP: true
Enabled_For_PVE: true

View File

@ -25,6 +25,7 @@
EarlyGameBoost:
Enabled: true
ExploitFix:
COTWBreeding: true
UnsafeEnchantments: false
# Prevent many exploits related to fishing
Fishing: true

View File

@ -481,12 +481,13 @@ Taming.Listener.Wolf=[[DARK_GRAY]]Your wolf scurries back to you...
Taming.Listener=Taming:
Taming.SkillName=TAMING
Taming.Summon.Complete=[[GREEN]]Summoning complete
Taming.Summon.COTW.Success=[[GREEN]](Call Of The Wild) [[GRAY]]You have summoned a [[GOLD]]{0}[[GRAY]] and it has a duration of [[GOLD]]{1}[[GRAY]] seconds.
Taming.Summon.Lifespan= (Lifespan: {0}s)
Taming.Summon.Fail.Ocelot=[[RED]]You have too many ocelots nearby to summon any more.
Taming.Summon.Fail.Wolf=[[RED]]You have too many wolves nearby to summon any more.
Taming.Summon.Fail.Horse=[[RED]]You have too many horses nearby to summon any more.
Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0})
Taming.Summon.Name.Format={0}'s {1}
Taming.Summon.COTW.Limit=[[RED]]You can only summon up to {0} for this type of animal. Try again later.
Taming.Summon.COTW.TimeExpired=[[GREEN]](Call Of The Wild) [[GRAY]]Time is up, your temporary summon [[GOLD]]{0}[[GRAY]] departs.
Taming.Summon.COTW.BreedingDisallowed=[[GREEN]](Call Of The Wild) [[RED]]You cannot breed a summoned animal.
Taming.Summon.Name.Format=[[GOLD]](COTW) [[WHITE]]{0}'s {1}
#UNARMED
Unarmed.Ability.Bonus.0=Iron Arm Style
Unarmed.Ability.Bonus.1=+{0} DMG Upgrade