first commit
This commit is contained in:
commit
aecaab67ac
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
target/
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "automatic",
|
||||||
|
"java.compile.nullAnalysis.mode": "disabled"
|
||||||
|
}
|
132
pom.xml
Normal file
132
pom.xml
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>lv.pi.animalrp</groupId>
|
||||||
|
<artifactId>animalrp</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
|
||||||
|
<name>animalrp</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>papermc</id>
|
||||||
|
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>codemc-releases</id>
|
||||||
|
<url>https://repo.codemc.org/repository/maven-releases/</url>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>sonatype-oss-snapshots1</id>
|
||||||
|
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.papermc.paper</groupId>
|
||||||
|
<artifactId>paper-api</artifactId>
|
||||||
|
<version>1.19.4-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-text-minimessage</artifactId>
|
||||||
|
<version>4.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.kyori</groupId>
|
||||||
|
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||||
|
<version>4.13.0</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
|
||||||
|
<configuration>
|
||||||
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
|
<shadedClassifierName>animalrp</shadedClassifierName>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>specialsource-maven-plugin</artifactId>
|
||||||
|
<version>1.2.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>remap</goal>
|
||||||
|
</goals>
|
||||||
|
<id>remap-obf</id>
|
||||||
|
<configuration>
|
||||||
|
<srgIn>org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
|
||||||
|
<reverse>true</reverse>
|
||||||
|
<remappedDependencies>org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
|
||||||
|
<remappedArtifactAttached>true</remappedArtifactAttached>
|
||||||
|
<remappedClassifierName>remapped-obf</remappedClassifierName>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>remap</goal>
|
||||||
|
</goals>
|
||||||
|
<id>remap-spigot</id>
|
||||||
|
<configuration>
|
||||||
|
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
|
||||||
|
<srgIn>org.spigotmc:minecraft-server:1.19.4-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
|
||||||
|
<remappedDependencies>org.spigotmc:spigot:1.19.4-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
58
readme.md
Normal file
58
readme.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# **AnimalRPs plugin**
|
||||||
|
|
||||||
|
## **Animal listing**
|
||||||
|
1. Bee
|
||||||
|
Doubleclicking shift you will float (levitation 5 for 1 second), allowing for better movement up hills as example. **Your superfood is the honeybottle.**
|
||||||
|
2. Cat
|
||||||
|
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.**
|
||||||
|
|
||||||
|
## **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.
|
||||||
|
|
||||||
|
## **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.
|
||||||
|
|
||||||
|
## **How to add a new animal?**
|
||||||
|
|
||||||
|
1. Create a new class in animals/MyCoolAnimal.java
|
||||||
|
2. Use this template
|
||||||
|
```
|
||||||
|
public class MyCoolAnimal extends Animal {
|
||||||
|
TextDestroyer destroyer = new TextDestroyer(new String[]{
|
||||||
|
"I'm Cool!"
|
||||||
|
}, new String[][]{
|
||||||
|
{"g", "z"}
|
||||||
|
});
|
||||||
|
|
||||||
|
public MyCoolAnimal() {
|
||||||
|
super("coolanimal", "awsome!", "#00ff00");
|
||||||
|
this.moodSounds.put(Mood.HAPPY, Sound.ENTITY_FOX_EAT);
|
||||||
|
this.moodSounds.put(Mood.CUTE, Sound.ENTITY_FOX_SLEEP);
|
||||||
|
this.moodSounds.put(Mood.SAD, Sound.ENTITY_FOX_SNIFF);
|
||||||
|
this.moodSounds.put(Mood.STRESSED, Sound.ENTITY_FOX_AGGRO);
|
||||||
|
this.moodSounds.put(Mood.ANGRY, Sound.ENTITY_FOX_BITE);
|
||||||
|
|
||||||
|
this.superfoods.add(Material.POTATO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatTransformations(String message) {
|
||||||
|
return this.destroyer.destroy(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location movementTransformations(Location location) {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. Change the info in the TextDestroyer initialization
|
||||||
|
4. Change the info in the super() call, it is written as "name", "catchphrase", "color".
|
||||||
|
5. Change the moodSounds and implement all sounds for the moods.
|
||||||
|
6. Add superfoods (foods that the animal likes)
|
168
src/main/java/lv/pi/animalrp/AnimalRP.java
Normal file
168
src/main/java/lv/pi/animalrp/AnimalRP.java
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠙⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⢺⣿⣿⡆⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⣾⢡⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿⣷⡦⠀⠀⠀⠀⢰⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠃⣠⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣆⠀⠀⠀⣾⣿⣿⣿⣷⠄⠀⠰⠤⣀⠀⠀⣴⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠃⢺⣿⣿⣿⣿⡄⠀⠀⣿⣿⢿⣿⣿⣦⣦⣦⣶⣼⣭⣼⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⣿⣿⣷⡆⠂⣿⣿⣞⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢙⣿⣿⣿⣿⣷⠸⣿⣿⣿⣿⣿⣿⠟⠻⣿⣿⣿⣿⡿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⢿⣿⣿⣿⣿⡄⣿⣿⣿⣿⣿⣿⡀⢀⣿⣿⣿⣿⠀⢸⣿⣿⠅⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢐⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⡀⣠⣾⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡔⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⢁⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠠⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⣀⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⣻⣿⣿⣿⣿⣿⡟⠋⠙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠙⢿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⠿⢿⡿⠛⠋⠁⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣅⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⣿⣿⣿⣿⡟⠃⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢻⣿⣿⣿⣿⣿⣤⡀⠀⠀⠀
|
||||||
|
⠀⠜⢠⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣦⠄⣠⠀
|
||||||
|
⠠⢸⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿
|
||||||
|
⠀⠛⣿⣿⣿⡿⠏⠀⠀⠀⠀⠀⠀⢳⣾⣿⣿⣿⣿⣿⣿⡶⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿
|
||||||
|
⠀⢨⠀⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⡿⡿⠿⠛⠙⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⠏⠉⠻⠿⠟⠁
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
*/
|
||||||
|
|
||||||
|
package lv.pi.animalrp;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.animals.Animal;
|
||||||
|
import lv.pi.animalrp.animals.Bee;
|
||||||
|
import lv.pi.animalrp.animals.Cat;
|
||||||
|
import lv.pi.animalrp.animals.Fox;
|
||||||
|
import lv.pi.animalrp.commands.EmoteCommand;
|
||||||
|
import lv.pi.animalrp.commands.InteractionCommand;
|
||||||
|
import lv.pi.animalrp.commands.TfCommand;
|
||||||
|
import lv.pi.animalrp.listeners.AntiElytra;
|
||||||
|
import lv.pi.animalrp.listeners.PlayerChat;
|
||||||
|
import lv.pi.animalrp.util.Cooldown;
|
||||||
|
import lv.pi.animalrp.util.Emote;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|
||||||
|
public class AnimalRP extends JavaPlugin {
|
||||||
|
public static HashMap<UUID, Animal> users = new HashMap<UUID, Animal>();
|
||||||
|
public static HashMap<UUID, Cooldown> cooldowns = new HashMap<UUID, Cooldown>();
|
||||||
|
public static HashMap<String, Animal> animals = new HashMap<String, Animal>();
|
||||||
|
public static Emote emotes;
|
||||||
|
|
||||||
|
public static Boolean configEnabled = true;
|
||||||
|
private Gson gson;
|
||||||
|
public static MiniMessage mm = MiniMessage.miniMessage();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
File folder = getDataFolder();
|
||||||
|
HashMap<String, String> usersReformatted = new HashMap<String, String>();
|
||||||
|
|
||||||
|
for (Entry<UUID,Animal> ee : users.entrySet()) {
|
||||||
|
usersReformatted.put(ee.getKey().toString(), ee.getValue().name);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path filePath = folder.toPath().resolve("database.json");
|
||||||
|
|
||||||
|
if(!Files.exists(filePath)) Files.createFile(filePath);
|
||||||
|
|
||||||
|
Files.write(filePath, gson.toJson(usersReformatted).getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path filePath = folder.toPath().resolve("cooldowns.json");
|
||||||
|
|
||||||
|
if(!Files.exists(filePath)) Files.createFile(filePath);
|
||||||
|
JsonObject jsobj = new JsonObject();
|
||||||
|
AnimalRP.cooldowns.forEach((a, b) -> {
|
||||||
|
jsobj.add(a.toString(), b.toJson());
|
||||||
|
});
|
||||||
|
Files.write(filePath, gson.toJson(jsobj).getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
PluginManager pm = getServer().getPluginManager();
|
||||||
|
AnimalRP.emotes = new Emote();
|
||||||
|
|
||||||
|
this.gson = new Gson();
|
||||||
|
|
||||||
|
animals.put("cat", new Cat());
|
||||||
|
animals.put("fox", new Fox());
|
||||||
|
animals.put("bee", new Bee());
|
||||||
|
|
||||||
|
animals.forEach((z,b) -> {
|
||||||
|
pm.registerEvents(b, this);
|
||||||
|
});
|
||||||
|
|
||||||
|
Path folder = getDataFolder().toPath();
|
||||||
|
|
||||||
|
if(!Files.exists(folder)) {
|
||||||
|
try {
|
||||||
|
Files.createDirectory(folder);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(folder.resolve("database.json").toFile().exists()) {
|
||||||
|
try {
|
||||||
|
JsonObject z = JsonParser.parseString(Files.readString(folder.resolve("database.json"))).getAsJsonObject();
|
||||||
|
|
||||||
|
for (Entry<String,JsonElement> entry : z.entrySet()) {
|
||||||
|
AnimalRP.users.put(UUID.fromString(entry.getKey()), AnimalRP.animals.get(entry.getValue().getAsString()));
|
||||||
|
}
|
||||||
|
} catch (JsonSyntaxException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(folder.resolve("cooldowns.json").toFile().exists()) {
|
||||||
|
try {
|
||||||
|
JsonObject z = JsonParser.parseString(Files.readString(folder.resolve("cooldowns.json"))).getAsJsonObject();
|
||||||
|
|
||||||
|
for (Entry<String,JsonElement> entry : z.entrySet()) {
|
||||||
|
AnimalRP.cooldowns.put(UUID.fromString(entry.getKey()), Cooldown.fromJson(entry.getValue().getAsJsonObject()));
|
||||||
|
}
|
||||||
|
} catch (JsonSyntaxException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.registerEvents(new PlayerChat(), this);
|
||||||
|
pm.registerEvents(new AntiElytra(), this);
|
||||||
|
|
||||||
|
getCommand("tf").setExecutor(new TfCommand());
|
||||||
|
getCommand("emote").setExecutor(new EmoteCommand());
|
||||||
|
|
||||||
|
getCommand("headpats").setExecutor(new InteractionCommand(Mood.HAPPY, "%s petted you! %s", "You petted %s! %s"));
|
||||||
|
getCommand("kiss").setExecutor(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("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", "You channel your inner evil, and scratch %s! %s"));
|
||||||
|
getCommand("hug").setExecutor(new InteractionCommand(Mood.HAPPY, "%s hugs you! How heartwarming. %s", "You hug %s! How heartwarming. %s")); // Simo__28 SUCKS
|
||||||
|
getCommand("cuddle").setExecutor(new InteractionCommand(Mood.CUTE, "%s cuddles with you. %s", "You and %s start cuddling. How cute! %s")); // Simo__28 SUCKS
|
||||||
|
}
|
||||||
|
}
|
57
src/main/java/lv/pi/animalrp/animals/Animal.java
Normal file
57
src/main/java/lv/pi/animalrp/animals/Animal.java
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package lv.pi.animalrp.animals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerItemConsumeEvent;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
public abstract class Animal implements Listener {
|
||||||
|
public String name;
|
||||||
|
public String catchphrase;
|
||||||
|
public String color;
|
||||||
|
public HashMap<Mood, Sound> moodSounds = new HashMap<Mood, Sound>();
|
||||||
|
public ArrayList<Material> superfoods = new ArrayList<Material>();
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEat(PlayerItemConsumeEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
Animal animal = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
if(animal == null) return;
|
||||||
|
if(animal.name != this.name) return;
|
||||||
|
|
||||||
|
if(event.getItem() != null) {
|
||||||
|
if(this.superfoods.contains(event.getItem().getType())) {
|
||||||
|
player.setFoodLevel(player.getFoodLevel() + 4);
|
||||||
|
player.setSaturation(player.getSaturation() + 9.4f);
|
||||||
|
PotionEffect eff = player.getPotionEffect(PotionEffectType.SPEED);
|
||||||
|
Integer duration = 20*4;
|
||||||
|
|
||||||
|
if(eff != null) { // This stacks!
|
||||||
|
duration += eff.getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, duration, 1, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Animal(String name, String catchphrase, String color) {
|
||||||
|
this.name = name; this.catchphrase = catchphrase; this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String chatTransformations(String message);
|
||||||
|
public abstract Location movementTransformations(Location location);
|
||||||
|
}
|
102
src/main/java/lv/pi/animalrp/animals/Bee.java
Normal file
102
src/main/java/lv/pi/animalrp/animals/Bee.java
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package lv.pi.animalrp.animals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.block.BlockFace;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
import lv.pi.animalrp.util.TextDestroyer;
|
||||||
|
|
||||||
|
class Cooldown {
|
||||||
|
Integer duration;
|
||||||
|
Long executionTime;
|
||||||
|
public Cooldown(Integer duration, Long executionTime) {
|
||||||
|
this.duration = duration;
|
||||||
|
this.executionTime = executionTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired() {
|
||||||
|
return this.executionTime-(System.currentTimeMillis()-this.duration) <= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Bee extends Animal {
|
||||||
|
TextDestroyer destroyer = new TextDestroyer(new String[]{
|
||||||
|
">_<", "*buzz*",
|
||||||
|
";3", ":3", "εწз", " ≧◠◡◠≦ ", "*stings you*", "*humms*",
|
||||||
|
"*i'm a bee*"
|
||||||
|
}, new String[][]{
|
||||||
|
{"e", "ee"},
|
||||||
|
{"b", "bzz"},
|
||||||
|
{"h", "hh"},
|
||||||
|
{"ie", "ee"},
|
||||||
|
{"be", "bee"},
|
||||||
|
{"E", "EE"},
|
||||||
|
{"B", "BZZ"},
|
||||||
|
{"H", "HH"},
|
||||||
|
{"IE", "EE"},
|
||||||
|
{"BE", "BEE"}
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayList<UUID> sneakers = new ArrayList<UUID>();
|
||||||
|
|
||||||
|
public Bee() {
|
||||||
|
super("bee", "Buzz...", "#FFFF00");
|
||||||
|
this.moodSounds.put(Mood.HAPPY, Sound.ENTITY_BEE_LOOP);
|
||||||
|
this.moodSounds.put(Mood.CUTE, Sound.ENTITY_BEE_LOOP);
|
||||||
|
this.moodSounds.put(Mood.SAD, Sound.ENTITY_BEE_HURT);
|
||||||
|
this.moodSounds.put(Mood.STRESSED, Sound.ENTITY_BEE_STING);
|
||||||
|
this.moodSounds.put(Mood.ANGRY, Sound.ENTITY_BEE_LOOP_AGGRESSIVE);
|
||||||
|
|
||||||
|
this.superfoods.add(Material.HONEY_BOTTLE);
|
||||||
|
this.superfoods.add(Material.CHORUS_FLOWER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onSneak(PlayerToggleSneakEvent event) {
|
||||||
|
Animal animal = AnimalRP.users.get(event.getPlayer().getUniqueId());
|
||||||
|
if(animal == null) return;
|
||||||
|
if(animal.name != this.name) return;
|
||||||
|
|
||||||
|
if (event.isSneaking() && event.getPlayer().getLocation().getBlock().getRelative(BlockFace.DOWN).getType() != Material.AIR) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (!sneakers.contains(player.getUniqueId())) {
|
||||||
|
sneakers.add(player.getUniqueId());
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if(sneakers.contains(player.getUniqueId())) sneakers.remove(player.getUniqueId());
|
||||||
|
}
|
||||||
|
}.runTaskLater(AnimalRP.getProvidingPlugin(Animal.class), 20);
|
||||||
|
} else {
|
||||||
|
sneakers.remove(player.getUniqueId());
|
||||||
|
player.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 20*1, 5, true));
|
||||||
|
player.getWorld().playSound(player.getLocation(), this.moodSounds.get(Mood.HAPPY), 1F, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatTransformations(String message) {
|
||||||
|
return destroyer.destroy(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location movementTransformations(Location location) {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
68
src/main/java/lv/pi/animalrp/animals/Cat.java
Normal file
68
src/main/java/lv/pi/animalrp/animals/Cat.java
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package lv.pi.animalrp.animals;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
import lv.pi.animalrp.util.TextDestroyer;
|
||||||
|
|
||||||
|
public class Cat extends Animal {
|
||||||
|
TextDestroyer destroyer = new TextDestroyer(new String[]{
|
||||||
|
">_<", ":3", "ʕʘ‿ʘʔ", ":D", "._.",
|
||||||
|
";3", "xD", "ㅇㅅㅇ",
|
||||||
|
">_>", "ÙωÙ", "UwU", "OwO", ":P",
|
||||||
|
"(◠‿◠✿)", "^_^", ";_;",
|
||||||
|
"x3", "(• o •)", "<_<"
|
||||||
|
}, new String[][]{
|
||||||
|
{"l", "w"},
|
||||||
|
{"r", "w"},
|
||||||
|
{"th", "d"},
|
||||||
|
{"L", "W"},
|
||||||
|
{"R", "W"},
|
||||||
|
{"TH", "D"}
|
||||||
|
});
|
||||||
|
|
||||||
|
public Cat() {
|
||||||
|
super("cat", "Nya~", "#F2BDCD");
|
||||||
|
this.moodSounds.put(Mood.HAPPY, Sound.ENTITY_CAT_PURR);
|
||||||
|
this.moodSounds.put(Mood.CUTE, Sound.ENTITY_CAT_PURREOW);
|
||||||
|
this.moodSounds.put(Mood.SAD, Sound.ENTITY_CAT_AMBIENT);
|
||||||
|
this.moodSounds.put(Mood.STRESSED, Sound.ENTITY_CAT_STRAY_AMBIENT);
|
||||||
|
this.moodSounds.put(Mood.ANGRY, Sound.ENTITY_CAT_HISS);
|
||||||
|
|
||||||
|
this.superfoods.add(Material.COOKED_COD);
|
||||||
|
this.superfoods.add(Material.COD);
|
||||||
|
this.superfoods.add(Material.COOKED_SALMON);
|
||||||
|
this.superfoods.add(Material.SALMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onDamage(EntityDamageEvent event) {
|
||||||
|
if(!(event.getEntity() instanceof Player)) return;
|
||||||
|
|
||||||
|
Player player = (Player)event.getEntity();
|
||||||
|
Animal animal = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
if(animal == null) return;
|
||||||
|
if(animal.name != this.name) return;
|
||||||
|
if(event.getCause() == DamageCause.FALL) {
|
||||||
|
event.setDamage(event.getDamage() - 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatTransformations(String message) {
|
||||||
|
return destroyer.destroy(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location movementTransformations(Location location) {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
src/main/java/lv/pi/animalrp/animals/Fox.java
Normal file
72
src/main/java/lv/pi/animalrp/animals/Fox.java
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package lv.pi.animalrp.animals;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
import lv.pi.animalrp.util.TextDestroyer;
|
||||||
|
|
||||||
|
public class Fox extends Animal {
|
||||||
|
TextDestroyer destroyer = new TextDestroyer(new String[]{
|
||||||
|
"yap",
|
||||||
|
"*yap yap*",
|
||||||
|
"*beeps*",
|
||||||
|
"*barks*",
|
||||||
|
"*screeches*",
|
||||||
|
":3"
|
||||||
|
}, new String[][]{
|
||||||
|
{"you", "u"},
|
||||||
|
{"o", "yo"},
|
||||||
|
{"i", "yi"},
|
||||||
|
{"!", " !"},
|
||||||
|
{"?", " ?"}
|
||||||
|
});
|
||||||
|
Random rand = new Random();
|
||||||
|
|
||||||
|
public Fox() {
|
||||||
|
super("fox", "Yap!", "#FF8000");
|
||||||
|
this.moodSounds.put(Mood.HAPPY, Sound.ENTITY_FOX_SNIFF);
|
||||||
|
this.moodSounds.put(Mood.CUTE, Sound.ENTITY_FOX_SLEEP);
|
||||||
|
this.moodSounds.put(Mood.SAD, Sound.ENTITY_FOX_SNIFF);
|
||||||
|
this.moodSounds.put(Mood.STRESSED, Sound.ENTITY_FOX_AGGRO);
|
||||||
|
this.moodSounds.put(Mood.ANGRY, Sound.ENTITY_FOX_BITE);
|
||||||
|
|
||||||
|
this.superfoods.add(Material.SWEET_BERRIES);
|
||||||
|
this.superfoods.add(Material.GLOW_BERRIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onDamage(EntityDamageByEntityEvent event) {
|
||||||
|
if(event.getDamager() instanceof Player) {
|
||||||
|
Player player = (Player)event.getDamager();
|
||||||
|
Animal animal = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
|
||||||
|
if(animal == null) return;
|
||||||
|
if(animal.name != this.name) return;
|
||||||
|
|
||||||
|
if(event.getCause() == DamageCause.ENTITY_ATTACK && event.getEntity().getType() != EntityType.PLAYER) {
|
||||||
|
event.setDamage(event.getDamage()*1.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String chatTransformations(String message) {
|
||||||
|
return this.destroyer.destroy(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location movementTransformations(Location location) {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/main/java/lv/pi/animalrp/commands/EmoteCommand.java
Normal file
59
src/main/java/lv/pi/animalrp/commands/EmoteCommand.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package lv.pi.animalrp.commands;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.util.Emote;
|
||||||
|
import lv.pi.animalrp.util.Emote.Emotes;
|
||||||
|
|
||||||
|
public class EmoteCommand implements CommandExecutor {
|
||||||
|
private void options(Player player) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<red>You have <green>" + String.join(", ", Emote.emotes.keySet().stream().map(Emote.Emotes::name).map(String::toLowerCase).collect(Collectors.toSet())) + "</green> as options."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender arg0, @NotNull Command arg1, @NotNull String arg2, @NotNull String[] arg3) {
|
||||||
|
if(!(arg0 instanceof Player)) {
|
||||||
|
arg0.sendMessage(AnimalRP.mm.deserialize("<gray>I'm sorry console. :(</gray>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player)arg0;
|
||||||
|
|
||||||
|
if(arg3.length == 0) {
|
||||||
|
options(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String emoteString = arg3[0];
|
||||||
|
Emote.Emotes emote;
|
||||||
|
|
||||||
|
try {
|
||||||
|
emote = Emotes.valueOf(emoteString.toUpperCase());
|
||||||
|
} catch(Exception e) {
|
||||||
|
emote = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(emote == null) {
|
||||||
|
options(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(AnimalRP.emotes.isPlayerEmoting(player.getUniqueId())) {
|
||||||
|
arg0.sendMessage(AnimalRP.mm.deserialize("<red>Stopped emoting."));
|
||||||
|
AnimalRP.emotes.stopEmote(player.getUniqueId());
|
||||||
|
} else {
|
||||||
|
arg0.sendMessage(AnimalRP.mm.deserialize("<red>Emoting!"));
|
||||||
|
AnimalRP.emotes.playEmote(player.getUniqueId(), emote);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package lv.pi.animalrp.commands;
|
||||||
|
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.animals.Animal;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
|
||||||
|
public class InteractionCommand implements CommandExecutor {
|
||||||
|
String toThem;
|
||||||
|
String toYou;
|
||||||
|
Mood mood;
|
||||||
|
|
||||||
|
public InteractionCommand(Mood mood, String toThem, String toYou) {
|
||||||
|
this.toThem = toThem;
|
||||||
|
this.toYou = toYou;
|
||||||
|
this.mood = mood;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if(!(sender instanceof Player)) {
|
||||||
|
sender.sendMessage(AnimalRP.mm.deserialize("<gray>I'm sorry console. :(</gray>"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player)sender;
|
||||||
|
|
||||||
|
Animal aplayer = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
|
||||||
|
if(aplayer == null) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>Only animals can interact with other animals :("));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(args.length == 0) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>Include a user!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player splayer = Bukkit.getPlayer(args[0]);
|
||||||
|
|
||||||
|
if(splayer == null) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>I can't find this player :("));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(splayer.getName() == player.getName()) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>You can't "+command+" yourself."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Animal asplayer = AnimalRP.users.get(splayer.getUniqueId());
|
||||||
|
|
||||||
|
if(asplayer == null) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>"+splayer.getName() + " is not an animal! :("));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
splayer.sendMessage(AnimalRP.mm.deserialize(String.format(this.toThem, "<light_purple>"+player.getName()+"</light_purple>", "<italic><gray>"+aplayer.catchphrase+"</italic>")));
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize(String.format(this.toYou, "<light_purple>"+splayer.getName()+"</light_purple>", "<italic><gray>"+asplayer.catchphrase+"</italic>")));
|
||||||
|
player.getWorld().playSound(splayer.getLocation(), asplayer.moodSounds.get(this.mood), 1F, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
92
src/main/java/lv/pi/animalrp/commands/TfCommand.java
Normal file
92
src/main/java/lv/pi/animalrp/commands/TfCommand.java
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package lv.pi.animalrp.commands;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandExecutor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
import lv.pi.animalrp.animals.Animal;
|
||||||
|
import lv.pi.animalrp.util.Cooldown;
|
||||||
|
|
||||||
|
public class TfCommand implements CommandExecutor {
|
||||||
|
public void options(Player player) {
|
||||||
|
ArrayList<String> parts = new ArrayList<String>();
|
||||||
|
|
||||||
|
for (Entry<String,Animal> entry : AnimalRP.animals.entrySet()) {
|
||||||
|
parts.add("<"+entry.getValue().color+">"+entry.getKey()+"</"+entry.getValue().color+">");
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<green>Looking around you, you have <dark_green>\"" + String.join(", ", parts) + "\"<green> as options."));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
if(!(sender instanceof Player)) {
|
||||||
|
sender.sendMessage(AnimalRP.mm.deserialize("<gray>I'm sorry, but you have to be a player to become an animal. :("));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = (Player)sender;
|
||||||
|
|
||||||
|
if(args.length == 0) {
|
||||||
|
if(AnimalRP.users.get(player.getUniqueId()) != null) {
|
||||||
|
Animal previous = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<green>You start splitting apart, dropping your <blue>" + previous.name+"-like<green> appearence.."));
|
||||||
|
AnimalRP.users.remove(player.getUniqueId());
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
options(player); return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String tf = args[0];
|
||||||
|
|
||||||
|
Animal animal = AnimalRP.animals.get(tf);
|
||||||
|
|
||||||
|
if(animal == null) {
|
||||||
|
options(player); return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cooldown cldn = AnimalRP.cooldowns.get(player.getUniqueId());
|
||||||
|
|
||||||
|
if(cldn != null) {
|
||||||
|
if(cldn.isExpired()) {
|
||||||
|
cldn = null;
|
||||||
|
} else {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<red>You are still on cooldown. Time left: " + sdf.format(new Date(cldn.getTime()))));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(AnimalRP.users.get(player.getUniqueId()) != null) {
|
||||||
|
Animal previous = AnimalRP.users.get(player.getUniqueId());
|
||||||
|
if(previous.name == animal.name) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<gray>You're <blue>" + previous.name + "</blue> already! " + animal.catchphrase));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<green>You slowly transform, from <blue>" + previous.name + "<green> to.. <blue>" + animal.name + ". "+ animal.catchphrase));
|
||||||
|
} else {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<green>You slowly transform, to.. <blue>" + animal.name + "<green>. "+ animal.catchphrase));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cldn == null) {
|
||||||
|
cldn = new Cooldown();
|
||||||
|
cldn.length = 21600000;
|
||||||
|
cldn.timeCreated = System.currentTimeMillis();
|
||||||
|
cldn.type = "tf-command";
|
||||||
|
AnimalRP.cooldowns.put(player.getUniqueId(), cldn);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimalRP.users.put(player.getUniqueId(), animal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
86
src/main/java/lv/pi/animalrp/listeners/AntiElytra.java
Normal file
86
src/main/java/lv/pi/animalrp/listeners/AntiElytra.java
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package lv.pi.animalrp.listeners;
|
||||||
|
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.entity.EntityToggleGlideEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
|
||||||
|
public class AntiElytra implements Listener {
|
||||||
|
|
||||||
|
public AntiElytra() {
|
||||||
|
JavaPlugin plugin = AnimalRP.getProvidingPlugin(AnimalRP.class);
|
||||||
|
|
||||||
|
new BukkitRunnable(){
|
||||||
|
public void run(){
|
||||||
|
for(Player p : plugin.getServer().getOnlinePlayers())
|
||||||
|
dequipElytra(p);
|
||||||
|
}
|
||||||
|
}.runTaskTimer(plugin, 20 * 5, 20 * 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void message(Player player) {
|
||||||
|
player.sendMessage(AnimalRP.mm.deserialize("<red>Elytras are not allowed to be worn. You <green>can still trade with them <red>as they might have a use in the future."));
|
||||||
|
}
|
||||||
|
@EventHandler
|
||||||
|
public void onGlide(EntityToggleGlideEvent event) {
|
||||||
|
if (event.getEntity().getType().equals(EntityType.PLAYER))
|
||||||
|
dequipElytra((Player) event.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int firstEmptyFromBack(PlayerInventory inv) {
|
||||||
|
int z = -1;
|
||||||
|
|
||||||
|
for(int i = 35; i >= 9; i--) {
|
||||||
|
if(inv.getItem(i) == null) {
|
||||||
|
z = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dequipElytra(Player player) {
|
||||||
|
PlayerInventory i = player.getInventory();
|
||||||
|
if (!( (i.getChestplate() != null) && i.getChestplate().getType().equals(Material.ELYTRA))) return;
|
||||||
|
if(player.getGameMode() == GameMode.CREATIVE) return;
|
||||||
|
|
||||||
|
ItemStack elytra = i.getChestplate();
|
||||||
|
i.setChestplate(null);
|
||||||
|
message(player);
|
||||||
|
|
||||||
|
// inventory full?
|
||||||
|
if (firstEmptyFromBack(i) != -1) {
|
||||||
|
i.setItem(firstEmptyFromBack(i), elytra);
|
||||||
|
player.updateInventory();
|
||||||
|
} else {
|
||||||
|
Location l = i.getLocation();
|
||||||
|
l.getWorld().dropItemNaturally(l, elytra);
|
||||||
|
player.updateInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onInteract(PlayerInteractEvent event) {
|
||||||
|
Action a = event.getAction();
|
||||||
|
if(a == Action.PHYSICAL || a == Action.LEFT_CLICK_AIR || a == Action.LEFT_CLICK_BLOCK) return;
|
||||||
|
|
||||||
|
if(event.getItem() == null) return;
|
||||||
|
if(event.getItem().getType() != Material.ELYTRA) return;
|
||||||
|
if(event.getPlayer().getGameMode() == GameMode.CREATIVE) return;
|
||||||
|
message(event.getPlayer());
|
||||||
|
dequipElytra(event.getPlayer());
|
||||||
|
}
|
||||||
|
}
|
56
src/main/java/lv/pi/animalrp/listeners/PlayerChat.java
Normal file
56
src/main/java/lv/pi/animalrp/listeners/PlayerChat.java
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package lv.pi.animalrp.listeners;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import io.papermc.paper.chat.ChatRenderer;
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent;
|
||||||
|
import lv.pi.animalrp.animals.Animal;
|
||||||
|
import lv.pi.animalrp.util.Mood;
|
||||||
|
import net.kyori.adventure.audience.Audience;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
|
||||||
|
class CustomChatRenderer implements ChatRenderer {
|
||||||
|
Animal animal;
|
||||||
|
|
||||||
|
public CustomChatRenderer(Animal animal) {
|
||||||
|
this.animal = animal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message,
|
||||||
|
@NotNull Audience viewer) {
|
||||||
|
return Component
|
||||||
|
.text("<")
|
||||||
|
.append(sourceDisplayName.color(TextColor.fromHexString(animal.color)))
|
||||||
|
.append(Component.text(">"))
|
||||||
|
.appendSpace()
|
||||||
|
.append(AnimalRP.mm.deserialize(animal.chatTransformations(AnimalRP.mm.serialize(message))));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public class PlayerChat implements Listener {
|
||||||
|
Random random = new Random();
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onPlayerChat(final AsyncChatEvent event) {
|
||||||
|
Animal animal = AnimalRP.users.get(event.getPlayer().getUniqueId());
|
||||||
|
|
||||||
|
if(animal != null) {
|
||||||
|
if(random.nextDouble() < 0.08) {
|
||||||
|
event.getPlayer().getWorld().playSound(event.getPlayer().getLocation(), animal.moodSounds.get(Mood.HAPPY), 10F, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.renderer(new CustomChatRenderer(animal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
src/main/java/lv/pi/animalrp/util/Cooldown.java
Normal file
35
src/main/java/lv/pi/animalrp/util/Cooldown.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package lv.pi.animalrp.util;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class Cooldown {
|
||||||
|
public long timeCreated;
|
||||||
|
public Integer length;
|
||||||
|
public String type;
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
return this.timeCreated - (System.currentTimeMillis() - this.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired() {
|
||||||
|
return this.getTime() <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
JsonObject obj = new JsonObject();
|
||||||
|
obj.addProperty("timeCreated", this.timeCreated);
|
||||||
|
obj.addProperty("length", this.length);
|
||||||
|
obj.addProperty("type", this.type);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cooldown fromJson(JsonObject obj) {
|
||||||
|
Cooldown cldn = new Cooldown();
|
||||||
|
cldn.timeCreated = obj.get("timeCreated").getAsLong();
|
||||||
|
cldn.length = obj.get("length").getAsInt();
|
||||||
|
cldn.type = obj.get("type").getAsString();
|
||||||
|
|
||||||
|
return cldn;
|
||||||
|
}
|
||||||
|
}
|
131
src/main/java/lv/pi/animalrp/util/Emote.java
Normal file
131
src/main/java/lv/pi/animalrp/util/Emote.java
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package lv.pi.animalrp.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Color;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Particle;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import lv.pi.animalrp.AnimalRP;
|
||||||
|
|
||||||
|
|
||||||
|
public class Emote {
|
||||||
|
public enum Emotes {
|
||||||
|
HAPPY, UWU, RAWR
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HashMap<Emotes, String[]> emotes = new HashMap<Emotes, String[]>();
|
||||||
|
private HashMap<UUID, Emotes> players = new HashMap<UUID, Emotes>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
emotes.put(Emotes.HAPPY, new String[]{
|
||||||
|
"0010000000100",
|
||||||
|
"0101000001010",
|
||||||
|
"0000000000000",
|
||||||
|
"0000011100000"
|
||||||
|
});
|
||||||
|
emotes.put(Emotes.UWU, new String[]{
|
||||||
|
"0101000001010",
|
||||||
|
"0010000000100",
|
||||||
|
"0000000000000",
|
||||||
|
"0000011100000"
|
||||||
|
});
|
||||||
|
|
||||||
|
emotes.put(Emotes.RAWR, new String[]{
|
||||||
|
"0101000001010",
|
||||||
|
"0010000000100",
|
||||||
|
"0000000000000",
|
||||||
|
"0000011100000"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Emote() {
|
||||||
|
Bukkit.getScheduler().scheduleSyncRepeatingTask(AnimalRP.getProvidingPlugin(AnimalRP.class), new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Set<Entry<UUID, Emotes>> playerset = players.entrySet();
|
||||||
|
|
||||||
|
for (Iterator<Entry<UUID, Emotes>> iterator = playerset.iterator(); iterator.hasNext(); ) {
|
||||||
|
Entry<UUID, Emotes> value = iterator.next();
|
||||||
|
Player plr = Bukkit.getPlayer(value.getKey());
|
||||||
|
if(plr == null) {
|
||||||
|
iterator.remove();
|
||||||
|
} else {
|
||||||
|
drawEmote(plr, value.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 5, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawEmote(Player player, Emotes emote) {
|
||||||
|
List<Location> locs = getEmoteLocs(player.getLocation(), emotes.get(emote), player.getLocation());
|
||||||
|
for (Location loc : locs) {
|
||||||
|
Particle.DustOptions dustOptions = new Particle.DustOptions(Color.WHITE, 0.5f);
|
||||||
|
player.spawnParticle(Particle.REDSTONE, loc, 15, 0, 0, 0, dustOptions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Location> getEmoteLocs(Location loc, String[] ttEmote, Location rotationLoc) {
|
||||||
|
List<List<Location>> locations = new ArrayList<>();
|
||||||
|
int y = 0;
|
||||||
|
int distance = 10;
|
||||||
|
for (String s : ttEmote) {
|
||||||
|
List<Integer> emoteTextLine = textToEmote(s);
|
||||||
|
List<Location> addLocs = new ArrayList<>();
|
||||||
|
for (int x = 0; x < emoteTextLine.size(); x++) {
|
||||||
|
float y2 = (float)y/((float)distance/2);
|
||||||
|
float side = (((float)emoteTextLine.get(x)/distance)-((float)ttEmote[0].length())/2/distance);
|
||||||
|
Vector rotation = rotationLoc.getDirection().normalize().setY(0);
|
||||||
|
Vector rot = rotation.crossProduct(new Vector(0, side, 0));
|
||||||
|
Location addLoc = loc.clone().add(rot);
|
||||||
|
addLoc.setY(loc.getY()+((float)ttEmote.length/distance-y2+2.25));
|
||||||
|
addLocs.add(addLoc);
|
||||||
|
}
|
||||||
|
locations.add(addLocs);
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Location> locs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (List<Location> listLocs : locations) {
|
||||||
|
locs.addAll(listLocs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return locs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Integer> textToEmote(String textToEmote) {
|
||||||
|
List<Integer> locs = new ArrayList<>();
|
||||||
|
for (int i=0; i<textToEmote.length(); i++) {
|
||||||
|
char l = textToEmote.charAt(i);
|
||||||
|
String letter = String.valueOf(l);
|
||||||
|
if (letter.equals("1")) {
|
||||||
|
locs.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return locs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playEmote(UUID uuid, Emotes emote) {
|
||||||
|
this.players.put(uuid, emote);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopEmote(UUID uuid) {
|
||||||
|
this.players.remove(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlayerEmoting(UUID uuid) {
|
||||||
|
return this.players.containsKey(uuid);
|
||||||
|
}
|
||||||
|
}
|
5
src/main/java/lv/pi/animalrp/util/Mood.java
Normal file
5
src/main/java/lv/pi/animalrp/util/Mood.java
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package lv.pi.animalrp.util;
|
||||||
|
|
||||||
|
public enum Mood {
|
||||||
|
HAPPY,SAD,STRESSED,ANGRY,CUTE
|
||||||
|
}
|
43
src/main/java/lv/pi/animalrp/util/TextDestroyer.java
Normal file
43
src/main/java/lv/pi/animalrp/util/TextDestroyer.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
package lv.pi.animalrp.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class TextDestroyer {
|
||||||
|
String[] expressions;
|
||||||
|
String[][] replaces;
|
||||||
|
|
||||||
|
public TextDestroyer(String[] expressions, String[][] replaces) {
|
||||||
|
this.expressions = expressions;
|
||||||
|
this.replaces = replaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String destroy(String message) {
|
||||||
|
final String[] words = message.split(" ");
|
||||||
|
final List<String> out = new ArrayList<>();
|
||||||
|
|
||||||
|
Random y = new Random();
|
||||||
|
|
||||||
|
for (String word : words) {
|
||||||
|
if(y.nextBoolean()){
|
||||||
|
out.add(word);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if(word.startsWith("[") && word.endsWith("]")) {
|
||||||
|
out.add(word);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String[] replacing: this.replaces) {
|
||||||
|
word = word.replace(replacing[0], replacing[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.add(word);
|
||||||
|
|
||||||
|
if(y.nextDouble() < 0.12) out.add(this.expressions[y.nextInt(this.expressions.length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.join(" ", out);
|
||||||
|
}
|
||||||
|
}
|
26
src/main/resources/plugin.yml
Normal file
26
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
name: animalrp
|
||||||
|
main: lv.pi.animalrp.AnimalRP
|
||||||
|
version: 1.0.0
|
||||||
|
api-version: 1.19
|
||||||
|
commands:
|
||||||
|
tf:
|
||||||
|
usage: Become the animal of your dreams!
|
||||||
|
headpats:
|
||||||
|
aliases: [pats, pet]
|
||||||
|
usage: Pet someone! :3
|
||||||
|
kiss:
|
||||||
|
usage: Kiss someone! :3
|
||||||
|
bite:
|
||||||
|
aliases: lovebite
|
||||||
|
usage: Bite someone! (cutely)
|
||||||
|
purr:
|
||||||
|
aliases: [mrrow, meow]
|
||||||
|
usage: Purr to someone! :3
|
||||||
|
scratch:
|
||||||
|
usage: Scratch someone! Ow!
|
||||||
|
hug:
|
||||||
|
usage: Hug a person.
|
||||||
|
cuddle:
|
||||||
|
usage: Cuddle a person.
|
||||||
|
emote:
|
||||||
|
usage: Emote!
|
Loading…
Reference in a new issue