fix sex, add player leashing + fix readme
All checks were successful
/ build (push) Successful in 23s

This commit is contained in:
Soph :3 2024-07-10 11:00:05 +03:00
parent cc57c63578
commit 86538da090
Signed by: sophie
GPG key ID: EDA5D222A0C270F2
6 changed files with 258 additions and 19 deletions

View file

@ -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.** 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 3. Fox
You do more damage to mobs (25%). **Your superfood is all types of berry.** 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**
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. 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**
Superfoods are items that when eaten, give you stackable **Speed II** and insane amounts of saturation (9.4 points) and hunger (4 points). 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 & animals**
Cooldowns are stored in game. Animal/cooldowns are stored in a json database. 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?** ## **How to add a new animal?**
1. Create a new class in animals/MyCoolAnimal.java 1. Create a new class in animals/MyCoolAnimal.java

View file

@ -59,6 +59,7 @@ import lv.pi.animalrp.commands.ChatModCommand;
import lv.pi.animalrp.commands.ClearCooldownCommand; import lv.pi.animalrp.commands.ClearCooldownCommand;
import lv.pi.animalrp.commands.SexCommand; import lv.pi.animalrp.commands.SexCommand;
import lv.pi.animalrp.commands.TfCommand; import lv.pi.animalrp.commands.TfCommand;
import lv.pi.animalrp.listeners.LeashPlayers;
import lv.pi.animalrp.listeners.PlayerChat; import lv.pi.animalrp.listeners.PlayerChat;
import lv.pi.animalrp.listeners.PlayerLeave; import lv.pi.animalrp.listeners.PlayerLeave;
import lv.pi.animalrp.util.Cooldown; import lv.pi.animalrp.util.Cooldown;
@ -247,6 +248,7 @@ public class AnimalRP extends JavaPlugin {
pm.registerEvents(new PlayerChat(), this); pm.registerEvents(new PlayerChat(), this);
pm.registerEvents(new PlayerLeave(), this); pm.registerEvents(new PlayerLeave(), this);
pm.registerEvents(new LeashPlayers(), this);
getCommand("tf").setExecutor(new TfCommand()); getCommand("tf").setExecutor(new TfCommand());
getCommand("emote").setExecutor(new EmoteCommand()); 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")); new InteractionCommand(Mood.CUTE, "%s kissed you.. 0////0 %s", "You kissed %s.. 0////0 %s"));
getCommand("bite") getCommand("bite")
.setExecutor(new InteractionCommand(Mood.ANGRY, "%s bit you!! Σ(っ゚Д゚)っ %s", "You bit %s! (○`д´)ノシ %s")); .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, 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")); "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", getCommand("scratch").setExecutor(new InteractionCommand(Mood.ANGRY, "%s SCRATCHES YOU! Ow! %s",

View file

@ -45,7 +45,13 @@ public class SexCommand implements CommandExecutor {
for (Iterator<Entry<UUID, SexModel>> iterator = modelset.iterator(); iterator.hasNext();) { for (Iterator<Entry<UUID, SexModel>> iterator = modelset.iterator(); iterator.hasNext();) {
Entry<UUID, SexModel> value = iterator.next(); Entry<UUID, SexModel> value = iterator.next();
Player plr = Bukkit.getPlayer(value.getKey()); 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(); value.getValue().removeModel();
iterator.remove(); iterator.remove();
} else { } else {
@ -131,8 +137,8 @@ public class SexCommand implements CommandExecutor {
Player player = (Player) arg0; Player player = (Player) arg0;
if (!player.isOp()) { if (!player.hasPermission("animalrp.sex")) {
arg0.sendMessage(AnimalRP.mm.deserialize("<red>You are not an OP!")); arg0.sendMessage(AnimalRP.mm.deserialize("<red>You do not have permission to use this command!"));
return true; return true;
} }
@ -143,6 +149,35 @@ public class SexCommand implements CommandExecutor {
String playerName = arg3[0]; String playerName = arg3[0];
OfflinePlayer of = Bukkit.getOfflinePlayer(playerName); 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) { if (of == null) {
arg0.sendMessage(AnimalRP.mm.deserialize("<red>User has never joined.")); arg0.sendMessage(AnimalRP.mm.deserialize("<red>User has never joined."));
return true; return true;
@ -158,6 +193,16 @@ public class SexCommand implements CommandExecutor {
Location loc = player.getLocation().add(0, -1, 0); Location loc = player.getLocation().add(0, -1, 0);
loc.add(getVector(yaw)); 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); ArmorStand as = (ArmorStand) player.getWorld().spawnEntity(loc, EntityType.ARMOR_STAND);
ItemStack head = new ItemStack(Material.PLAYER_HEAD); ItemStack head = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) head.getItemMeta(); SkullMeta meta = (SkullMeta) head.getItemMeta();
@ -170,12 +215,12 @@ public class SexCommand implements CommandExecutor {
as.setHeadPose(new EulerAngle(0.15, 0, 0)); as.setHeadPose(new EulerAngle(0.15, 0, 0));
as.setInvulnerable(true); as.setInvulnerable(true);
as.addEquipmentLock(EquipmentSlot.HEAD, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.HEAD, LockType.REMOVING_OR_CHANGING);
as.addEquipmentLock(EquipmentSlot.CHEST, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.CHEST, LockType.REMOVING_OR_CHANGING);
as.addEquipmentLock(EquipmentSlot.FEET, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.FEET, LockType.REMOVING_OR_CHANGING);
as.addEquipmentLock(EquipmentSlot.LEGS, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.LEGS, LockType.REMOVING_OR_CHANGING);
as.addEquipmentLock(EquipmentSlot.OFF_HAND, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.OFF_HAND, LockType.REMOVING_OR_CHANGING);
as.addEquipmentLock(EquipmentSlot.HAND, LockType.ADDING); as.addEquipmentLock(EquipmentSlot.HAND, LockType.REMOVING_OR_CHANGING);
Location facing = faceLocation(as, player.getEyeLocation()); Location facing = faceLocation(as, player.getEyeLocation());
as.teleport(facing); as.teleport(facing);
@ -186,6 +231,8 @@ public class SexCommand implements CommandExecutor {
public class SexModel { public class SexModel {
ArmorStand as; ArmorStand as;
Player pl;
Yaw yaw; Yaw yaw;
int sexTicks = 0; int sexTicks = 0;
boolean finished = false; boolean finished = false;
@ -197,6 +244,12 @@ public class SexCommand implements CommandExecutor {
this.playerLocation = playerLocation; 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) { public void tickSex(Player player) {
player.teleport(this.playerLocation); player.teleport(this.playerLocation);
@ -212,9 +265,15 @@ public class SexCommand implements CommandExecutor {
if (this.yaw == Yaw.SOUTH) if (this.yaw == Yaw.SOUTH)
opposite = Yaw.NORTH; opposite = Yaw.NORTH;
this.yaw = opposite; this.yaw = opposite;
Location asl = this.as.getLocation(); if (this.as == null) {
asl.add(SexCommand.getVector(this.yaw, 0.2)); Location pll = this.pl.getLocation();
as.teleport(asl); 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) { if (this.sexTicks == 30) {
@ -230,7 +289,12 @@ public class SexCommand implements CommandExecutor {
} }
public void removeModel() { public void removeModel() {
this.as.remove(); if (this.as == null) {
this.pl.setGravity(true);
this.pl.setInvulnerable(false);
} else {
this.as.remove();
}
} }
} }

View 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);
}
}

View file

@ -89,7 +89,7 @@ public class Emote {
} }
public void drawEmote(Player player, Emotes 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) { for (Location loc : locs) {
Particle.DustOptions dustOptions = new Particle.DustOptions(Color.WHITE, 0.5f); Particle.DustOptions dustOptions = new Particle.DustOptions(Color.WHITE, 0.5f);
player.getWorld().spawnParticle(Particle.DUST, loc, 15, 0, 0, 0, dustOptions); player.getWorld().spawnParticle(Particle.DUST, loc, 15, 0, 0, 0, dustOptions);

View file

@ -34,7 +34,5 @@ commands:
usage: Cuddle a person. usage: Cuddle a person.
emote: emote:
usage: Emote! usage: Emote!
bzz:
usage: Bzz at someone :3
sex: sex:
usage: This command can only be used by Operators. usage: Dude, no.