fix sex, add player leashing + fix readme
All checks were successful
/ build (push) Successful in 23s
All checks were successful
/ build (push) Successful in 23s
This commit is contained in:
parent
cc57c63578
commit
86538da090
11
readme.md
11
readme.md
|
@ -7,16 +7,27 @@ Doubleclicking shift you will float (levitation 5 for 1 second), allowing for be
|
|||
You take significantly less damage when falling (5 hearts). You can still die, don't count on your cat-powers catching you every time. **Your superfood is all types of eatable fish.**
|
||||
3. Fox
|
||||
You do more damage to mobs (25%). **Your superfood is all types of berry.**
|
||||
4. Dog
|
||||
You get speed 2 when doing damage. **Your superfood are uncooked meats.**
|
||||
|
||||
## **Chat**
|
||||
Chat while you are a animal is very different. When you speak, your words will become furry-ified and every time you talk you'll have animal sounds come out of you. You can disable this via /chatmodoff, and turn it back on via /chatmodon.
|
||||
|
||||
If you do not want to see these chat changes, run /chatmodclientoff. This will disable them for you, and you only.
|
||||
|
||||
## **Superfoods**
|
||||
Superfoods are items that when eaten, give you stackable **Speed II** and insane amounts of saturation (9.4 points) and hunger (4 points).
|
||||
|
||||
## **Cooldowns & animals**
|
||||
Cooldowns are stored in game. Animal/cooldowns are stored in a json database.
|
||||
|
||||
## **Player leashing**
|
||||
There is player leashing. This is in code, pretty hard. What I'm doing is spawning a invizible zombie (leashing it), and then constantly launching the player towards that zombie. Seems to work pretty well.
|
||||
That is a concept that was NOT introduced by me, it's a combination of two different projects (one very very NSFW roleplay plugin, and one player prison plugin). Both the players have to be animals, and they also have to have the `animalrp.leash` permission (both the leasher and the leashee).
|
||||
|
||||
## **MINECRAFT SEX PLUGIN??**
|
||||
Yup. I'm not even joking. This plugin has a /sex command, and it's only available with the permission `animalrp.sex`. It works suprisingly well.
|
||||
|
||||
## **How to add a new animal?**
|
||||
|
||||
1. Create a new class in animals/MyCoolAnimal.java
|
||||
|
|
|
@ -59,6 +59,7 @@ import lv.pi.animalrp.commands.ChatModCommand;
|
|||
import lv.pi.animalrp.commands.ClearCooldownCommand;
|
||||
import lv.pi.animalrp.commands.SexCommand;
|
||||
import lv.pi.animalrp.commands.TfCommand;
|
||||
import lv.pi.animalrp.listeners.LeashPlayers;
|
||||
import lv.pi.animalrp.listeners.PlayerChat;
|
||||
import lv.pi.animalrp.listeners.PlayerLeave;
|
||||
import lv.pi.animalrp.util.Cooldown;
|
||||
|
@ -247,6 +248,7 @@ public class AnimalRP extends JavaPlugin {
|
|||
|
||||
pm.registerEvents(new PlayerChat(), this);
|
||||
pm.registerEvents(new PlayerLeave(), this);
|
||||
pm.registerEvents(new LeashPlayers(), this);
|
||||
|
||||
getCommand("tf").setExecutor(new TfCommand());
|
||||
getCommand("emote").setExecutor(new EmoteCommand());
|
||||
|
@ -268,8 +270,6 @@ public class AnimalRP extends JavaPlugin {
|
|||
new InteractionCommand(Mood.CUTE, "%s kissed you.. 0////0 %s", "You kissed %s.. 0////0 %s"));
|
||||
getCommand("bite")
|
||||
.setExecutor(new InteractionCommand(Mood.ANGRY, "%s bit you!! Σ(っ゚Д゚)っ %s", "You bit %s! (○`д´)ノシ %s"));
|
||||
getCommand("bzz")
|
||||
.setExecutor(new InteractionCommand(Mood.ANGRY, "%s bzzs at you!! :3 %s", "You bzzed at %s :3 %s"));
|
||||
getCommand("purr").setExecutor(new InteractionCommand(Mood.CUTE,
|
||||
"You hear the soft sound of %s purring on you... %s", "You jump on %s, and start purring. %s"));
|
||||
getCommand("scratch").setExecutor(new InteractionCommand(Mood.ANGRY, "%s SCRATCHES YOU! Ow! %s",
|
||||
|
|
|
@ -45,7 +45,13 @@ public class SexCommand implements CommandExecutor {
|
|||
for (Iterator<Entry<UUID, SexModel>> iterator = modelset.iterator(); iterator.hasNext();) {
|
||||
Entry<UUID, SexModel> value = iterator.next();
|
||||
Player plr = Bukkit.getPlayer(value.getKey());
|
||||
if (plr == null || value.getValue().finished) {
|
||||
Boolean sexing = true;
|
||||
|
||||
if(value.getValue().pl != null) {
|
||||
sexing = value.getValue().pl.isOnline();
|
||||
}
|
||||
|
||||
if (plr == null || value.getValue().finished || !sexing) {
|
||||
value.getValue().removeModel();
|
||||
iterator.remove();
|
||||
} else {
|
||||
|
@ -131,8 +137,8 @@ public class SexCommand implements CommandExecutor {
|
|||
|
||||
Player player = (Player) arg0;
|
||||
|
||||
if (!player.isOp()) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>You are not an OP!"));
|
||||
if (!player.hasPermission("animalrp.sex")) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>You do not have permission to use this command!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -143,6 +149,35 @@ public class SexCommand implements CommandExecutor {
|
|||
|
||||
String playerName = arg3[0];
|
||||
OfflinePlayer of = Bukkit.getOfflinePlayer(playerName);
|
||||
Player gg = Bukkit.getPlayerExact(playerName);
|
||||
if(gg != null) {
|
||||
if(gg.getUniqueId().equals(player.getUniqueId())) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>You cannot add your own name!"));
|
||||
return false;
|
||||
}
|
||||
Boolean sexingSomeone = SexCommand.models.containsKey(gg.getUniqueId());
|
||||
if(sexingSomeone) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>The player is already busy with someone else!"));
|
||||
return false;
|
||||
}
|
||||
Boolean alreadyInProgress = false;
|
||||
Set<Entry<UUID, SexModel>> modelset = models.entrySet();
|
||||
|
||||
for (Iterator<Entry<UUID, SexModel>> iterator = modelset.iterator(); iterator.hasNext();) {
|
||||
Entry<UUID, SexModel> value = iterator.next();
|
||||
|
||||
if(value.getValue().pl != null) {
|
||||
if(value.getValue().pl.getUniqueId().equals(gg.getUniqueId())) {
|
||||
alreadyInProgress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(alreadyInProgress) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>The player you're mentioning is already in progress!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (of == null) {
|
||||
arg0.sendMessage(AnimalRP.mm.deserialize("<red>User has never joined."));
|
||||
return true;
|
||||
|
@ -158,6 +193,16 @@ public class SexCommand implements CommandExecutor {
|
|||
Location loc = player.getLocation().add(0, -1, 0);
|
||||
loc.add(getVector(yaw));
|
||||
|
||||
if (gg != null) {
|
||||
gg.setGravity(false);
|
||||
gg.setInvulnerable(true);
|
||||
gg.teleport(loc);
|
||||
Location facing = faceLocation(gg, player.getEyeLocation());
|
||||
gg.teleport(facing);
|
||||
SexCommand.models.put(player.getUniqueId(), new SexModel(gg, yaw, player.getLocation()));
|
||||
return true;
|
||||
}
|
||||
|
||||
ArmorStand as = (ArmorStand) player.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND);
|
||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||
SkullMeta meta = (SkullMeta) head.getItemMeta();
|
||||
|
@ -170,12 +215,12 @@ public class SexCommand implements CommandExecutor {
|
|||
as.setHeadPose(new EulerAngle(0.15, 0, 0));
|
||||
as.setInvulnerable(true);
|
||||
|
||||
as.addEquipmentLock(EquipmentSlot.HEAD, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.CHEST, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.FEET, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.LEGS, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.OFF_HAND, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.HAND, LockType.ADDING);
|
||||
as.addEquipmentLock(EquipmentSlot.HEAD, LockType.REMOVING_OR_CHANGING);
|
||||
as.addEquipmentLock(EquipmentSlot.CHEST, LockType.REMOVING_OR_CHANGING);
|
||||
as.addEquipmentLock(EquipmentSlot.FEET, LockType.REMOVING_OR_CHANGING);
|
||||
as.addEquipmentLock(EquipmentSlot.LEGS, LockType.REMOVING_OR_CHANGING);
|
||||
as.addEquipmentLock(EquipmentSlot.OFF_HAND, LockType.REMOVING_OR_CHANGING);
|
||||
as.addEquipmentLock(EquipmentSlot.HAND, LockType.REMOVING_OR_CHANGING);
|
||||
|
||||
Location facing = faceLocation(as, player.getEyeLocation());
|
||||
as.teleport(facing);
|
||||
|
@ -186,6 +231,8 @@ public class SexCommand implements CommandExecutor {
|
|||
|
||||
public class SexModel {
|
||||
ArmorStand as;
|
||||
Player pl;
|
||||
|
||||
Yaw yaw;
|
||||
int sexTicks = 0;
|
||||
boolean finished = false;
|
||||
|
@ -197,6 +244,12 @@ public class SexCommand implements CommandExecutor {
|
|||
this.playerLocation = playerLocation;
|
||||
}
|
||||
|
||||
public SexModel(Player pl, Yaw yaw, Location playerLocation) {
|
||||
this.pl = pl;
|
||||
this.yaw = yaw;
|
||||
this.playerLocation = playerLocation;
|
||||
}
|
||||
|
||||
public void tickSex(Player player) {
|
||||
player.teleport(this.playerLocation);
|
||||
|
||||
|
@ -212,10 +265,16 @@ public class SexCommand implements CommandExecutor {
|
|||
if (this.yaw == Yaw.SOUTH)
|
||||
opposite = Yaw.NORTH;
|
||||
this.yaw = opposite;
|
||||
if (this.as == null) {
|
||||
Location pll = this.pl.getLocation();
|
||||
pll.add(SexCommand.getVector(this.yaw, 0.2));
|
||||
pl.teleport(pll);
|
||||
} else {
|
||||
Location asl = this.as.getLocation();
|
||||
asl.add(SexCommand.getVector(this.yaw, 0.2));
|
||||
as.teleport(asl);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sexTicks == 30) {
|
||||
player.sendMessage(AnimalRP.mm.deserialize("<#FFC0CB>I'm about to.."));
|
||||
|
@ -230,8 +289,13 @@ public class SexCommand implements CommandExecutor {
|
|||
}
|
||||
|
||||
public void removeModel() {
|
||||
if (this.as == null) {
|
||||
this.pl.setGravity(true);
|
||||
this.pl.setInvulnerable(false);
|
||||
} else {
|
||||
this.as.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
166
src/main/java/lv/pi/animalrp/listeners/LeashPlayers.java
Normal file
166
src/main/java/lv/pi/animalrp/listeners/LeashPlayers.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
|
||||
package lv.pi.animalrp.listeners;
|
||||
|
||||
// Code from:
|
||||
// (warning, NSFW) https://github.com/ApherFox/MC-leash-players-plugin/blob/master/main/Pair.java
|
||||
// https://github.com/WMGameLive/LeashPlayers/blob/master/src/main/java/wm/vdr/leashplayers/Listeners.java
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Zombie;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityCombustEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityUnleashEvent;
|
||||
import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import lv.pi.animalrp.AnimalRP;
|
||||
import lv.pi.animalrp.animals.Animal;
|
||||
import lv.pi.animalrp.util.Mood;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LeashPlayers implements Listener {
|
||||
List<Player> leashed = new ArrayList<>();
|
||||
List<LivingEntity> entityList = new ArrayList<>();
|
||||
List<Entity> distanceUnleash = new ArrayList<>();
|
||||
|
||||
@EventHandler
|
||||
public void onUnleash(EntityUnleashEvent e) {
|
||||
if (e.getReason() == UnleashReason.PLAYER_UNLEASH)
|
||||
return;
|
||||
distanceUnleash.add(e.getEntity());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLeash(PlayerInteractAtEntityEvent e) {
|
||||
if (!(e.getRightClicked() instanceof Player))
|
||||
return;
|
||||
|
||||
if (!e.getHand().equals(EquipmentSlot.HAND))
|
||||
return;
|
||||
|
||||
Player player = e.getPlayer();
|
||||
Player target = (Player) e.getRightClicked();
|
||||
|
||||
if (!player.getInventory().getItemInMainHand().getType().equals(Material.LEAD))
|
||||
return;
|
||||
|
||||
if (!player.isOp()) {
|
||||
if (!player.hasPermission("animalrp.leash")) {
|
||||
player.sendMessage(AnimalRP.mm.deserialize("<red>You do not have permission to leash a player."));
|
||||
return;
|
||||
}
|
||||
if (!target.hasPermission("animalrp.leash")) {
|
||||
player.sendMessage(AnimalRP.mm.deserialize("<red>This player does not have permission to be leashed."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (leashed.contains(target)) {
|
||||
leashed.remove(target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (AnimalRP.users.get(player.getUniqueId()) == null) {
|
||||
player.sendMessage(AnimalRP.mm.deserialize("<gray>You aren't a animal, you can't leash others!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (AnimalRP.users.get(target.getUniqueId()) != null) {
|
||||
Animal targetAnimal = AnimalRP.users.get(target.getUniqueId());
|
||||
Animal playerAnimal = AnimalRP.users.get(player.getUniqueId());
|
||||
|
||||
player.sendMessage(
|
||||
AnimalRP.mm.deserialize(
|
||||
String.format("You just leashed <%s>%s<reset>!", targetAnimal.color, target.getName())));
|
||||
target.sendMessage(
|
||||
AnimalRP.mm.deserialize(String.format("You just got leashed by <%s>%s<reset>! (^▽^)",
|
||||
playerAnimal.color, player.getName())));
|
||||
|
||||
player.getWorld().playSound(player.getLocation(), playerAnimal.moodSounds.get(Mood.HAPPY), 1F, 1);
|
||||
target.getWorld().playSound(target.getLocation(), targetAnimal.moodSounds.get(Mood.CUTE), 1F, 1);
|
||||
} else {
|
||||
player.sendMessage(AnimalRP.mm.deserialize("<gray>This person isn't a animal."));
|
||||
return;
|
||||
}
|
||||
LivingEntity zomb = target.getWorld().spawn(target.getLocation(), Zombie.class, zombie -> {
|
||||
zombie.getEquipment().setItemInMainHand(null);
|
||||
zombie.getEquipment().setHelmet(null);
|
||||
zombie.getEquipment().setChestplate(null);
|
||||
zombie.getEquipment().setLeggings(null);
|
||||
zombie.getEquipment().setBoots(null);
|
||||
zombie.setCanPickupItems(false);
|
||||
zombie.setAdult();
|
||||
if (zombie.getVehicle() != null)
|
||||
zombie.getVehicle().remove();
|
||||
zombie.setSilent(true);
|
||||
zombie.setInvisible(true);
|
||||
zombie.setCollidable(false);
|
||||
zombie.setInvulnerable(true);
|
||||
zombie.addPotionEffect(new PotionEffect(PotionEffectType.SLOWNESS, Integer.MAX_VALUE, 255, false, false));
|
||||
zombie.setLeashHolder(player);
|
||||
});
|
||||
|
||||
target.setAllowFlight(true);
|
||||
leashed.add(target);
|
||||
entityList.add(zomb);
|
||||
|
||||
player.getInventory().getItemInMainHand().setAmount(player.getInventory().getItemInMainHand().getAmount() - 1);
|
||||
|
||||
new BukkitRunnable() {
|
||||
public void run() {
|
||||
if (!target.isOnline() || !zomb.isValid() || !zomb.isLeashed() || !leashed.contains(target)) {
|
||||
leashed.remove(target);
|
||||
entityList.remove(zomb);
|
||||
zomb.remove();
|
||||
target.setAllowFlight(false);
|
||||
if (!distanceUnleash.contains(zomb))
|
||||
target.getWorld().dropItemNaturally(target.getLocation(), new ItemStack(Material.LEAD));
|
||||
else
|
||||
distanceUnleash.remove(zomb);
|
||||
cancel();
|
||||
}
|
||||
double distance = zomb.getLocation().distance(target.getLocation());
|
||||
if (distance > 10.0D) {
|
||||
target.teleport(zomb.getLocation().setDirection(target.getLocation().getDirection()));
|
||||
} else if (distance > 3.0D) {
|
||||
double x = zomb.getLocation().getX() - target.getLocation().getX();
|
||||
double y = zomb.getLocation().getY() - target.getLocation().getY();
|
||||
double z = zomb.getLocation().getZ() - target.getLocation().getZ();
|
||||
Vector vector = new Vector(x, y, z);
|
||||
|
||||
target.setVelocity(vector.multiply(0.1D));
|
||||
} else {
|
||||
target.teleport(zomb.getLocation().setDirection(target.getLocation().getDirection()));
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(AnimalRP.getProvidingPlugin(AnimalRP.class), 0, 15);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onFlame(EntityCombustEvent e) {
|
||||
if (!(e.getEntity() instanceof LivingEntity))
|
||||
return;
|
||||
if (entityList.contains((LivingEntity) e.getEntity()))
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDamage(EntityDamageByEntityEvent e) {
|
||||
if (!(e.getDamager() instanceof LivingEntity))
|
||||
return;
|
||||
if (entityList.contains((LivingEntity) e.getDamager()))
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
|
@ -89,7 +89,7 @@ public class Emote {
|
|||
}
|
||||
|
||||
public void drawEmote(Player player, Emotes emote) {
|
||||
List<Location> locs = getEmoteLocs(player.getLocation(), emotes.get(emote), player.getLocation());
|
||||
List<Location> locs = getEmoteLocs(player.getLocation().subtract(0, player.isSneaking()?.5:0, 0), emotes.get(emote), player.getLocation());
|
||||
for (Location loc : locs) {
|
||||
Particle.DustOptions dustOptions = new Particle.DustOptions(Color.WHITE, 0.5f);
|
||||
player.getWorld().spawnParticle(Particle.DUST, loc, 15, 0, 0, 0, dustOptions);
|
||||
|
|
|
@ -34,7 +34,5 @@ commands:
|
|||
usage: Cuddle a person.
|
||||
emote:
|
||||
usage: Emote!
|
||||
bzz:
|
||||
usage: Bzz at someone :3
|
||||
sex:
|
||||
usage: This command can only be used by Operators.
|
||||
usage: Dude, no.
|
Loading…
Reference in a new issue