🖍️Main commit
This commit is contained in:
120
.gitignore
vendored
Normal file
120
.gitignore
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
# User-specific stuff
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
.kotlin/
|
||||||
|
.gradle
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Ignore Gradle GUI config
|
||||||
|
gradle-app.setting
|
||||||
|
|
||||||
|
# Cache of project
|
||||||
|
.gradletasknamecache
|
||||||
|
|
||||||
|
**/build/
|
||||||
|
|
||||||
|
# Common working directory
|
||||||
|
run/
|
||||||
|
runs/
|
||||||
|
|
||||||
|
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||||
|
!gradle-wrapper.jar
|
||||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# TCOWW
|
||||||
|
TCOWW is a small paper plugin created for an event on the French Discord server, [The Court of Gaming](https://discord.gg/evCYTnRrpU).
|
||||||
|
The event is a simple game of "Loup-Garou de Thiercelieux" in Minecraft with a role-play dimension.
|
||||||
|
|
||||||
|
Write in kotlin with the paper 1.21.4 api.
|
||||||
69
build.gradle.kts
Normal file
69
build.gradle.kts
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm") version "2.2.0-Beta1"
|
||||||
|
id("com.gradleup.shadow") version "8.3.0"
|
||||||
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
|
id("io.papermc.paperweight.userdev") version "2.0.0-beta.16"
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "fr.azur"
|
||||||
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven("https://repo.papermc.io/repository/maven-public/") {
|
||||||
|
name = "papermc-repo"
|
||||||
|
}
|
||||||
|
maven("https://oss.sonatype.org/content/groups/public/") {
|
||||||
|
name = "sonatype"
|
||||||
|
}
|
||||||
|
maven("https://repo.codemc.org/repository/maven-public/") {
|
||||||
|
name = "codemc"
|
||||||
|
}
|
||||||
|
maven("https://repo.plasmoverse.com/releases")
|
||||||
|
maven("https://repo.plasmoverse.com/snapshots")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
|
|
||||||
|
compileOnly("net.skinsrestorer:skinsrestorer-api:15.6.3")
|
||||||
|
compileOnly("su.plo.voice.api:server:2.1.4")
|
||||||
|
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetJavaVersion = 21
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(targetJavaVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
runServer {
|
||||||
|
downloadPlugins {
|
||||||
|
modrinth("plasmo-voice", "spigot-2.1.4")
|
||||||
|
modrinth("skinsrestorer", "15.6.3")
|
||||||
|
}
|
||||||
|
minecraftVersion("1.21.4")
|
||||||
|
}
|
||||||
|
build {
|
||||||
|
dependsOn("shadowJar")
|
||||||
|
}
|
||||||
|
processResources {
|
||||||
|
val props = mapOf("version" to version)
|
||||||
|
inputs.properties(props)
|
||||||
|
filteringCharset = "UTF-8"
|
||||||
|
filesMatching("paper-plugin.yml") {
|
||||||
|
expand(props)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadowJar {
|
||||||
|
archiveBaseName.set("tcoww")
|
||||||
|
|
||||||
|
minimize()
|
||||||
|
|
||||||
|
// exclude("META-INF/*.kotlin_module")
|
||||||
|
// exclude("META-INF/*.version")
|
||||||
|
}
|
||||||
|
}
|
||||||
0
gradle.properties
Normal file
0
gradle.properties
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
1
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||||
1
settings.gradle.kts
Normal file
1
settings.gradle.kts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "Werewolf Role Play"
|
||||||
51
src/main/kotlin/fr/azur/tcoww/Tcoww.kt
Normal file
51
src/main/kotlin/fr/azur/tcoww/Tcoww.kt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package fr.azur.tcoww
|
||||||
|
|
||||||
|
import fr.azur.tcoww.events.GameEvent
|
||||||
|
import fr.azur.tcoww.events.ToolsEvents
|
||||||
|
import fr.azur.tcoww.plasmovoice.addon.PlasmoAddon
|
||||||
|
import fr.azur.tcoww.roles.*
|
||||||
|
import fr.azur.tcoww.utils.Skin
|
||||||
|
import net.skinsrestorer.api.SkinsRestorer
|
||||||
|
import net.skinsrestorer.api.SkinsRestorerProvider
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import su.plo.voice.api.server.PlasmoVoiceServer
|
||||||
|
|
||||||
|
class Tcoww : JavaPlugin() {
|
||||||
|
private lateinit var skinsRestorer: SkinsRestorer
|
||||||
|
private lateinit var skinManager: Skin
|
||||||
|
val plasmoAddon = PlasmoAddon()
|
||||||
|
|
||||||
|
override fun onEnable() {
|
||||||
|
saveResource("config.yml", false)
|
||||||
|
saveDefaultConfig()
|
||||||
|
|
||||||
|
PlasmoVoiceServer.getAddonsLoader().load(plasmoAddon)
|
||||||
|
|
||||||
|
skinsRestorer = SkinsRestorerProvider.get()
|
||||||
|
skinManager = Skin(this, skinsRestorer)
|
||||||
|
|
||||||
|
server.pluginManager.registerEvents(ToolsEvents(this), this)
|
||||||
|
server.pluginManager.registerEvents(GameEvent(this, skinManager), this)
|
||||||
|
|
||||||
|
registerRoles()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reload(withPlasmoAddon: Boolean) {
|
||||||
|
this.reloadConfig()
|
||||||
|
skinManager.reloadSkin()
|
||||||
|
if (withPlasmoAddon) plasmoAddon.onConfigLoaded()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun registerRoles() {
|
||||||
|
Role.registerRole(Villager())
|
||||||
|
Role.registerRole(Werewolf())
|
||||||
|
Role.registerRole(Child())
|
||||||
|
Role.registerRole(FortuneTeller())
|
||||||
|
Role.registerRole(Hunter())
|
||||||
|
Role.registerRole(Witch())
|
||||||
|
}
|
||||||
|
}
|
||||||
24
src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt
Normal file
24
src/main/kotlin/fr/azur/tcoww/TcowwBootstrap.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package fr.azur.tcoww
|
||||||
|
|
||||||
|
import fr.azur.tcoww.commands.Power
|
||||||
|
import fr.azur.tcoww.commands.GameCommand
|
||||||
|
import fr.azur.tcoww.commands.ReloadCommands
|
||||||
|
import fr.azur.tcoww.commands.TimeGest
|
||||||
|
import fr.azur.tcoww.commands.Tools
|
||||||
|
import fr.azur.tcoww.commands.Vote
|
||||||
|
import io.papermc.paper.plugin.bootstrap.BootstrapContext
|
||||||
|
import io.papermc.paper.plugin.bootstrap.PluginBootstrap
|
||||||
|
import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents
|
||||||
|
|
||||||
|
class TcowwBootstrap : PluginBootstrap {
|
||||||
|
override fun bootstrap(context: BootstrapContext) {
|
||||||
|
context.lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS) { commands ->
|
||||||
|
commands.registrar().register(Tools().root.build())
|
||||||
|
commands.registrar().register(TimeGest().root.build())
|
||||||
|
commands.registrar().register(Power().root.build())
|
||||||
|
commands.registrar().register(GameCommand().root.build())
|
||||||
|
commands.registrar().register(Vote().root.build())
|
||||||
|
commands.registrar().register(ReloadCommands().root.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt
Normal file
67
src/main/kotlin/fr/azur/tcoww/commands/GameCommand.kt
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import fr.azur.tcoww.game.Game
|
||||||
|
import fr.azur.tcoww.roles.Role
|
||||||
|
import fr.azur.tcoww.roles.Villager
|
||||||
|
import fr.azur.tcoww.roles.Werewolf
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import io.papermc.paper.command.brigadier.argument.ArgumentTypes
|
||||||
|
import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
|
||||||
|
|
||||||
|
class GameCommand {
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("game")
|
||||||
|
.requires { sender ->
|
||||||
|
sender.sender.isOp
|
||||||
|
}.then(
|
||||||
|
Commands.literal("start")
|
||||||
|
.then(
|
||||||
|
Commands.argument("players", ArgumentTypes.players()).then(
|
||||||
|
Commands.argument("roles", StringArgumentType.greedyString()).suggests { ctx, builder ->
|
||||||
|
val roleswithoutauto =
|
||||||
|
Role.registerRoles.filter { role -> role.value !is Villager && role.value !is Werewolf }
|
||||||
|
val rolessplit = builder.remaining.split(" ")
|
||||||
|
val startstr = rolessplit.dropLast(1).joinToString(separator = " ")
|
||||||
|
|
||||||
|
roleswithoutauto.forEach { role ->
|
||||||
|
if (role.key.toString().startsWith(rolessplit.last())) {
|
||||||
|
builder.suggest("$startstr${if (startstr.isEmpty()) "" else " "}${role.key}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (builder.remaining != "" && !builder.remaining.endsWith(" ")) {
|
||||||
|
roleswithoutauto.forEach { role ->
|
||||||
|
builder.suggest("${builder.remaining} ${role.key}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.buildFuture()
|
||||||
|
}.executes { ctx ->
|
||||||
|
val plugin = Bukkit.getPluginManager().getPlugin("tcoww")!!
|
||||||
|
val targetResolver = ctx.getArgument("players", PlayerSelectorArgumentResolver::class.java)
|
||||||
|
val targets = targetResolver.resolve(ctx.source)
|
||||||
|
|
||||||
|
val rolesstr = StringArgumentType.getString(ctx, "roles")
|
||||||
|
val rolessplit = rolesstr.split(" ")
|
||||||
|
|
||||||
|
val roles = rolessplit.map { str ->
|
||||||
|
Role.registerRoles[NamespacedKey.fromString(str)]
|
||||||
|
}
|
||||||
|
val correctrole = roles.filterNotNull()
|
||||||
|
|
||||||
|
Game(plugin, ctx.source.location.world, targets, correctrole)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).then(
|
||||||
|
Commands.literal("stop").executes { ctx ->
|
||||||
|
Game.current?.stopGame(true)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
156
src/main/kotlin/fr/azur/tcoww/commands/Power.kt
Normal file
156
src/main/kotlin/fr/azur/tcoww/commands/Power.kt
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import fr.azur.tcoww.game.Game
|
||||||
|
import fr.azur.tcoww.roles.FortuneTeller
|
||||||
|
import fr.azur.tcoww.roles.Role
|
||||||
|
import fr.azur.tcoww.roles.Witch
|
||||||
|
import fr.azur.tcoww.utils.Stockage
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import io.papermc.paper.command.brigadier.argument.ArgumentTypes
|
||||||
|
import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.potion.PotionEffect
|
||||||
|
import org.bukkit.potion.PotionEffectType
|
||||||
|
|
||||||
|
class Power {
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("power")
|
||||||
|
.requires { ctx -> ctx.sender as? Player != null && Role.getRole(ctx.sender as Player)?.hasPowerCommand == true }
|
||||||
|
.then(
|
||||||
|
Commands.literal("kill")
|
||||||
|
.requires { ctx ->
|
||||||
|
val player = ctx.executor as? Player ?: return@requires false
|
||||||
|
val role = Role.getRole(player)
|
||||||
|
(role is Witch && player.hasPowerItem(1))
|
||||||
|
}
|
||||||
|
.then(
|
||||||
|
Commands.argument("target", ArgumentTypes.player())
|
||||||
|
.suggests { _, builder ->
|
||||||
|
Game.current?.playersMutable?.forEach { builder.suggest(it.name) }
|
||||||
|
builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val target = ctx.getTargetPlayer("target") ?: return@executes 0
|
||||||
|
val player = ctx.source.getPlayer() ?: return@executes 0
|
||||||
|
if (Game.current?.playersMutable?.contains(target) == true) {
|
||||||
|
target.addPotionEffect(PotionEffect(PotionEffectType.WITHER, 600, 4))
|
||||||
|
player.removePowerItem(1)
|
||||||
|
}
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
Commands.literal("save")
|
||||||
|
.requires { ctx ->
|
||||||
|
val player = ctx.executor as? Player ?: return@requires false
|
||||||
|
val role = Role.getRole(player)
|
||||||
|
role is Witch && player.hasPowerItem(2)
|
||||||
|
}
|
||||||
|
.then(
|
||||||
|
Commands.argument("target", ArgumentTypes.player())
|
||||||
|
.executes { ctx ->
|
||||||
|
val target = ctx.getTargetPlayer("target") ?: return@executes 0
|
||||||
|
val player = ctx.source.getPlayer() ?: return@executes 0
|
||||||
|
if (Game.current?.playersMutable?.contains(target) == true &&
|
||||||
|
target.persistentDataContainer.get(
|
||||||
|
NamespacedKey("tcoww", "dead"),
|
||||||
|
PersistentDataType.BOOLEAN
|
||||||
|
) == true
|
||||||
|
) {
|
||||||
|
target.persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "dead"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
Stockage.backLocation[target.uniqueId]?.let { target.teleport(it) }
|
||||||
|
target.isInvulnerable = false
|
||||||
|
target.sendMessage(Component.text("Vous avez été résucité.").color(NamedTextColor.AQUA))
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("Vous avez résuciter ").color(NamedTextColor.AQUA)
|
||||||
|
.append(player.displayName())
|
||||||
|
)
|
||||||
|
player.removePowerItem(2)
|
||||||
|
}
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
Commands.literal("view")
|
||||||
|
.requires { ctx ->
|
||||||
|
val player = ctx.executor as? Player ?: return@requires false
|
||||||
|
val role = Role.getRole(player)
|
||||||
|
role is FortuneTeller && player.hasPowerItem(4)
|
||||||
|
}
|
||||||
|
.then(
|
||||||
|
Commands.argument("target", ArgumentTypes.player())
|
||||||
|
.suggests { _, builder ->
|
||||||
|
Game.current?.playersMutable?.forEach { builder.suggest(it.name) }
|
||||||
|
builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val target = ctx.getTargetPlayer("target") ?: return@executes 0
|
||||||
|
val player = ctx.source.getPlayer() ?: return@executes 0
|
||||||
|
val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return@executes 0
|
||||||
|
if (Game.current?.playersMutable?.contains(target) == true) {
|
||||||
|
val item = player.getPowerItem(4) ?: return@executes 0
|
||||||
|
|
||||||
|
val timeGestion = Game.current!!.timeGestion
|
||||||
|
val cooldown =
|
||||||
|
((timeGestion.dayDuration + timeGestion.voteDuration + timeGestion.nightDuration + timeGestion.crepuscularDuration - 30) * 2) * 20
|
||||||
|
|
||||||
|
val cloneditem = item.clone()
|
||||||
|
|
||||||
|
player.inventory.remove(item)
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
player.inventory.addItem(cloneditem)
|
||||||
|
}, cooldown.toLong())
|
||||||
|
|
||||||
|
val targetrole = Role.getRole(target)
|
||||||
|
|
||||||
|
player.sendMessage(
|
||||||
|
target.displayName().append(Component.text(" est "))
|
||||||
|
.append(
|
||||||
|
(targetrole?.displayName ?: Component.text("Inconnu").hoverEvent(
|
||||||
|
HoverEvent.showText(
|
||||||
|
targetrole?.description ?: Component.empty()
|
||||||
|
)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun CommandSourceStack.getPlayer(): Player? = (this.executor ?: this.sender) as? Player
|
||||||
|
|
||||||
|
private fun Player.hasPowerItem(id: Int): Boolean = this.inventory.any {
|
||||||
|
it?.persistentDataContainer?.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == id
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Player.getPowerItem(id: Int) = this.inventory.firstOrNull {
|
||||||
|
it?.persistentDataContainer?.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == id
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Player.removePowerItem(id: Int) {
|
||||||
|
val item = getPowerItem(id) ?: return
|
||||||
|
this.inventory.remove(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun com.mojang.brigadier.context.CommandContext<CommandSourceStack>.getTargetPlayer(name: String): Player? {
|
||||||
|
val resolver = this.getArgument(name, PlayerSelectorArgumentResolver::class.java)
|
||||||
|
return resolver.resolve(this.source).firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt
Normal file
18
src/main/kotlin/fr/azur/tcoww/commands/ReloadCommands.kt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class ReloadCommands {
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("reloadcommands").executes { ctx ->
|
||||||
|
val sender = ctx.source.sender as? Player
|
||||||
|
sender?.updateCommands()
|
||||||
|
sender?.sendMessage(Component.text("Commands rechargés !").color(NamedTextColor.GOLD))
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/main/kotlin/fr/azur/tcoww/commands/TimeGest.kt
Normal file
44
src/main/kotlin/fr/azur/tcoww/commands/TimeGest.kt
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import fr.azur.tcoww.game.TimeGestion
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
|
||||||
|
class TimeGest {
|
||||||
|
var timeGestion: TimeGestion? = null
|
||||||
|
var sheduler: BukkitTask? = null
|
||||||
|
var plugin: Plugin? = null
|
||||||
|
|
||||||
|
private fun kill() {
|
||||||
|
sheduler?.cancel()
|
||||||
|
sheduler = null
|
||||||
|
timeGestion = null
|
||||||
|
}
|
||||||
|
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("timegest")
|
||||||
|
.requires { sender ->
|
||||||
|
sender.sender.isOp
|
||||||
|
}.then(
|
||||||
|
Commands.literal("start").executes { ctx ->
|
||||||
|
if (plugin == null) plugin = Bukkit.getPluginManager().getPlugin("tcoww")!!
|
||||||
|
val executor = ctx.source.executor
|
||||||
|
if (executor == null) throw Error("No executor !")
|
||||||
|
if (timeGestion != null || sheduler != null) kill()
|
||||||
|
timeGestion = TimeGestion(plugin!!, executor.world)
|
||||||
|
sheduler = Bukkit.getScheduler().runTaskTimer(plugin!!, Runnable {
|
||||||
|
timeGestion!!.tick()
|
||||||
|
}, 0L, 1L)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
).then(
|
||||||
|
Commands.literal("kill").executes {
|
||||||
|
kill()
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
146
src/main/kotlin/fr/azur/tcoww/commands/Tools.kt
Normal file
146
src/main/kotlin/fr/azur/tcoww/commands/Tools.kt
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import fr.azur.tcoww.Tcoww
|
||||||
|
import fr.azur.tcoww.items.CustomItems
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Tools {
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("tools")
|
||||||
|
.requires { sender ->
|
||||||
|
sender.sender.isOp
|
||||||
|
}.then(
|
||||||
|
Commands.literal("location")
|
||||||
|
.then(
|
||||||
|
Commands.literal("bed").executes { ctx ->
|
||||||
|
val player = ctx.source.executor as Player
|
||||||
|
player.inventory.addItem(CustomItems.BedLocTool.item)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}.then(
|
||||||
|
Commands.literal("get").executes { ctx ->
|
||||||
|
ctx.source.sender.sendMessage(sendBed())
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
).then(
|
||||||
|
Commands.literal("remove").then(
|
||||||
|
Commands.argument("index", IntegerArgumentType.integer(0))
|
||||||
|
.executes { ctx ->
|
||||||
|
val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return@executes 0
|
||||||
|
val index = IntegerArgumentType.getInteger(ctx, "index")
|
||||||
|
val list = plugin.config.getMapList("bedLocation")
|
||||||
|
|
||||||
|
plugin.config.set("bedLocation", list.minus(list[index]))
|
||||||
|
plugin.saveConfig()
|
||||||
|
|
||||||
|
ctx.source.sender.sendMessage(sendBed())
|
||||||
|
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
))
|
||||||
|
).then(
|
||||||
|
Commands.literal("spawn").executes { ctx ->
|
||||||
|
val player = ctx.source.executor as Player
|
||||||
|
player.inventory.addItem(CustomItems.SpawnLocTool.item)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
).then(
|
||||||
|
Commands.literal("lobby").executes { ctx ->
|
||||||
|
val player = ctx.source.executor as Player
|
||||||
|
player.inventory.addItem(CustomItems.LobbyLocTool.item)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).then(
|
||||||
|
Commands.literal("reload").executes { ctx ->
|
||||||
|
val plugin = Bukkit.getPluginManager().getPlugin("tcoww") as Tcoww
|
||||||
|
plugin.reload(true)
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
).then(
|
||||||
|
Commands.literal("customitem").then(
|
||||||
|
Commands.argument("item", StringArgumentType.greedyString())
|
||||||
|
.suggests { ctx, builder ->
|
||||||
|
CustomItems.entries.forEach {
|
||||||
|
builder.suggest(it.name)
|
||||||
|
}
|
||||||
|
builder.buildFuture()
|
||||||
|
}
|
||||||
|
.executes { ctx ->
|
||||||
|
val itemName = StringArgumentType.getString(ctx, "item")
|
||||||
|
val item = CustomItems.valueOf(itemName).item
|
||||||
|
val exe = ctx.source.executor
|
||||||
|
if (exe is Player) {
|
||||||
|
exe.inventory.addItem(item)
|
||||||
|
}
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun sendBed(): Component {
|
||||||
|
val plugin = Bukkit.getPluginManager().getPlugin("tcoww") ?: return Component.empty()
|
||||||
|
val bedlist = plugin.config.getMapList("bedLocation")
|
||||||
|
val bedLocationComponent = bedlist.map {
|
||||||
|
if (it as? Map<String, Object> != null) {
|
||||||
|
val loc = Location.deserialize(it as Map<String, Object>)
|
||||||
|
Component.text("[${loc.x}, ${loc.y}, ${loc.z}] ")
|
||||||
|
.color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
.append(
|
||||||
|
Component.text("teleport")
|
||||||
|
.clickEvent(
|
||||||
|
ClickEvent.runCommand("/minecraft:tp ${loc.x.toInt()} ${loc.y.toInt()} ${loc.z.toInt()}")
|
||||||
|
)
|
||||||
|
.color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
.decorate(TextDecoration.UNDERLINED)
|
||||||
|
)
|
||||||
|
.appendSpace()
|
||||||
|
.append(
|
||||||
|
Component.text("remove")
|
||||||
|
.clickEvent(
|
||||||
|
ClickEvent.runCommand(
|
||||||
|
"/tcoww:tools location bed remove ${
|
||||||
|
bedlist.indexOf(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
.decorate(TextDecoration.UNDERLINED)
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
} else Component.text("[unkown location] ")
|
||||||
|
.color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
.append(
|
||||||
|
Component.text("remove")
|
||||||
|
.clickEvent(
|
||||||
|
ClickEvent.runCommand(
|
||||||
|
"/tcoww:tools location bed remove ${
|
||||||
|
bedlist.indexOf(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
.decorate(TextDecoration.UNDERLINED)
|
||||||
|
)
|
||||||
|
.appendNewline()
|
||||||
|
}
|
||||||
|
return Component.text("Current bed locations :")
|
||||||
|
.color(NamedTextColor.DARK_PURPLE)
|
||||||
|
.appendNewline()
|
||||||
|
.append(bedLocationComponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/kotlin/fr/azur/tcoww/commands/Vote.kt
Normal file
32
src/main/kotlin/fr/azur/tcoww/commands/Vote.kt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package fr.azur.tcoww.commands
|
||||||
|
|
||||||
|
import com.mojang.brigadier.Command
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder
|
||||||
|
import fr.azur.tcoww.game.Game
|
||||||
|
import fr.azur.tcoww.game.Phase
|
||||||
|
import fr.azur.tcoww.utils.Stockage
|
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack
|
||||||
|
import io.papermc.paper.command.brigadier.Commands
|
||||||
|
import io.papermc.paper.command.brigadier.argument.ArgumentTypes
|
||||||
|
import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Vote {
|
||||||
|
val root: LiteralArgumentBuilder<CommandSourceStack> = Commands.literal("vote").then(
|
||||||
|
Commands.argument("target", ArgumentTypes.player())
|
||||||
|
.requires { ctx ->
|
||||||
|
Game.current?.timeGestion?.phase == Phase.VOTE && Game.current!!.playersMutable.contains(ctx.sender)
|
||||||
|
}.suggests { ctx, builder ->
|
||||||
|
Game.current?.playersMutable?.forEach { player -> builder.suggest(player.name) }
|
||||||
|
builder.buildFuture()
|
||||||
|
}.executes { ctx ->
|
||||||
|
val targetResolver = ctx.getArgument("target", PlayerSelectorArgumentResolver::class.java)
|
||||||
|
val target = targetResolver.resolve(ctx.source).first()
|
||||||
|
val player = (ctx.source.executor ?: ctx.source.sender as Player) as Player
|
||||||
|
if (Game.current?.playersMutable?.contains(target) ?: false) {
|
||||||
|
Stockage.vote[player.uniqueId] = target.uniqueId
|
||||||
|
}
|
||||||
|
Command.SINGLE_SUCCESS
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
432
src/main/kotlin/fr/azur/tcoww/events/GameEvent.kt
Normal file
432
src/main/kotlin/fr/azur/tcoww/events/GameEvent.kt
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
package fr.azur.tcoww.events
|
||||||
|
|
||||||
|
import fr.azur.tcoww.game.Game
|
||||||
|
import fr.azur.tcoww.game.Phase
|
||||||
|
import fr.azur.tcoww.items.CustomItems
|
||||||
|
import fr.azur.tcoww.roles.Child
|
||||||
|
import fr.azur.tcoww.roles.Role
|
||||||
|
import fr.azur.tcoww.roles.Witch
|
||||||
|
import fr.azur.tcoww.utils.BedGestion
|
||||||
|
import fr.azur.tcoww.utils.Skin
|
||||||
|
import fr.azur.tcoww.utils.Stockage
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration
|
||||||
|
import net.kyori.adventure.title.Title
|
||||||
|
import org.bukkit.*
|
||||||
|
import org.bukkit.attribute.Attribute
|
||||||
|
import org.bukkit.attribute.AttributeModifier
|
||||||
|
import org.bukkit.entity.EntityType
|
||||||
|
import org.bukkit.entity.ItemDisplay
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
|
import org.bukkit.event.inventory.InventoryMoveItemEvent
|
||||||
|
import org.bukkit.event.player.*
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.inventory.meta.SkullMeta
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import org.bukkit.potion.PotionEffect
|
||||||
|
import org.bukkit.potion.PotionEffectType
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
|
class GameEvent(val plugin: Plugin, val skinUtils: Skin) : Listener {
|
||||||
|
@EventHandler
|
||||||
|
fun phaseChange(event: TimePhaseChangeEvent) {
|
||||||
|
Game.current?.playersMutable?.forEach { it.updateCommands() }
|
||||||
|
when (event.newPhase) {
|
||||||
|
Phase.DAY -> {
|
||||||
|
event.world.players.forEach { player ->
|
||||||
|
player.sendMessage(Component.text("Le jour se lève.").color(NamedTextColor.GOLD))
|
||||||
|
player.clearActivePotionEffects()
|
||||||
|
player.persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "insomie"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
if (player.role?.lg == true) {
|
||||||
|
player.inventory.forEach {
|
||||||
|
if (it != null && it.persistentDataContainer.get(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER
|
||||||
|
) == 3
|
||||||
|
) {
|
||||||
|
player.inventory.remove(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.isTransformed()) {
|
||||||
|
player.tfHuman()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Phase.VOTE -> {
|
||||||
|
event.world.players.forEach { player ->
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("Le jour se couche, ce soir un vote est organisé.")
|
||||||
|
.color(NamedTextColor.DARK_AQUA)
|
||||||
|
.appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text("Faite /vote <pseudo> pour voter.")
|
||||||
|
.color(NamedTextColor.AQUA)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Phase.NIGHT -> {
|
||||||
|
if (Stockage.vote.isNotEmpty()) {
|
||||||
|
val voteMap = Stockage.vote.values.groupingBy { it }.eachCount()
|
||||||
|
val mostVoted = voteMap.maxByOrNull { it.value }?.key
|
||||||
|
mostVoted?.let { uuid ->
|
||||||
|
Bukkit.getPlayer(uuid)?.let { votedPlayer ->
|
||||||
|
votedPlayer.fireTicks = 1200
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
votedPlayer.health = 0.0
|
||||||
|
}, 60)
|
||||||
|
Game.current?.playersMutable?.forEach {
|
||||||
|
it.sendMessage(
|
||||||
|
Component.text("${votedPlayer.name} a reçu le plus de vote.")
|
||||||
|
.color(NamedTextColor.RED)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stockage.vote.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
Game.current?.wwcankill = true
|
||||||
|
event.world.players.forEach { player ->
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("La lune se léve et les loups sont de sortie. Vous devriez dormir.")
|
||||||
|
.color(NamedTextColor.DARK_PURPLE)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (player.role?.lg ?: false) {
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("Vous pouvez vous transformer.").color(NamedTextColor.DARK_PURPLE)
|
||||||
|
)
|
||||||
|
player.inventory.addItem(CustomItems.WereWolfTransformItem.item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
val openBed = plugin.config.getMapList("bedLocation").mapNotNull {
|
||||||
|
if (it as? Map<String, Object> != null) Location.deserialize(it as Map<String, Object>) else null
|
||||||
|
}.filter { !BedGestion.isOcupied(it.block) }.toMutableList()
|
||||||
|
Game.current?.playersMutable?.forEach { player ->
|
||||||
|
if (!player.isSleeping && !player.persistentDataContainer.getOrDefault(
|
||||||
|
NamespacedKey("tcoww", "dead"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
) && !player.isTransformed()
|
||||||
|
) {
|
||||||
|
val loc = openBed.removeFirst()
|
||||||
|
player.sleep(loc, true)
|
||||||
|
|
||||||
|
val role = player.role
|
||||||
|
if (role is Child || role?.lg == true) {
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text(
|
||||||
|
"Tout le monde est couché. Vous pouvez vous lever.",
|
||||||
|
NamedTextColor.AQUA
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, plugin.config.getLong("playerSleep"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Phase.CREPUSCULAR -> {
|
||||||
|
val current = Game.current ?: return
|
||||||
|
val deadPlayers = current.playersMutable.filter {
|
||||||
|
it.persistentDataContainer.get(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
deadPlayers.forEach { player ->
|
||||||
|
player.gameMode = GameMode.SPECTATOR
|
||||||
|
Stockage.backLocation[player.uniqueId]?.let { player.teleport(it) }
|
||||||
|
player.kill(current)
|
||||||
|
}
|
||||||
|
|
||||||
|
current.playersMutable.removeAll(deadPlayers)
|
||||||
|
if (current.gameEnded()) {
|
||||||
|
current.playersMutable.forEach {
|
||||||
|
if (it.isTransformed()) it.tfHuman()
|
||||||
|
}
|
||||||
|
current.stopGame()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun powerItemDrop(event: PlayerDropItemEvent) {
|
||||||
|
val item = event.itemDrop.itemStack
|
||||||
|
if (event.player.gameMode != GameMode.CREATIVE &&
|
||||||
|
item.itemMeta.persistentDataContainer.has(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER)
|
||||||
|
) {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun powerItemTransfer(event: InventoryMoveItemEvent) {
|
||||||
|
val item = event.item
|
||||||
|
if (event.source != event.destination &&
|
||||||
|
item.itemMeta.persistentDataContainer.has(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER)
|
||||||
|
) {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun sleepLeaveEvent(event: PlayerBedLeaveEvent) {
|
||||||
|
val role = event.player.role
|
||||||
|
if (Game.current?.timeGestion?.phase == Phase.NIGHT &&
|
||||||
|
role !is Child && role?.lg != true &&
|
||||||
|
!event.player.persistentDataContainer.getOrDefault(
|
||||||
|
NamespacedKey("tcoww", "insomie"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun clickEvent(event: PlayerInteractEvent) {
|
||||||
|
val item = event.item ?: return
|
||||||
|
if (item.persistentDataContainer.get(NamespacedKey("tcoww", "power"), PersistentDataType.INTEGER) == 3) {
|
||||||
|
val player = event.player
|
||||||
|
|
||||||
|
player.inventory.remove(item)
|
||||||
|
|
||||||
|
if (player.isTransformed()) {
|
||||||
|
player.tfHuman()
|
||||||
|
} else {
|
||||||
|
player.tfWerewolf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDeath(event: PlayerDeathEvent) {
|
||||||
|
val current = Game.current ?: return
|
||||||
|
val player = event.player
|
||||||
|
if (!current.playersMutable.contains(player)) return
|
||||||
|
|
||||||
|
event.isCancelled = true
|
||||||
|
|
||||||
|
if (current.timeGestion.phase == Phase.NIGHT) {
|
||||||
|
Stockage.backLocation[player.uniqueId] = player.location
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
player.teleport(plugin.config.getLocation("lobbyLocation")!!)
|
||||||
|
player.clearActivePotionEffects()
|
||||||
|
player.fireTicks = 0
|
||||||
|
}, 1)
|
||||||
|
player.isInvulnerable = true
|
||||||
|
player.persistentDataContainer.set(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN, true)
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("Vous étes mort... Mais vous pouvez être encore résucité.").color(
|
||||||
|
NamedTextColor.RED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
current.playersMutable.forEach { p ->
|
||||||
|
if (p.role is Witch && p.inventory.any {
|
||||||
|
it != null && it.persistentDataContainer.get(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER
|
||||||
|
) == 2
|
||||||
|
}) {
|
||||||
|
p.sendMessage(
|
||||||
|
Component.text("Cette nuit, ${player.name} est mort dans d'atroces souffrances. Vous avez le pouvoir de le/la sauver.\n")
|
||||||
|
.color(NamedTextColor.DARK_PURPLE)
|
||||||
|
.append(
|
||||||
|
Component.text("Cliquez ici pour le/la ressusciter.")
|
||||||
|
.color(NamedTextColor.DARK_PURPLE)
|
||||||
|
.decorate(TextDecoration.UNDERLINED)
|
||||||
|
.clickEvent(ClickEvent.suggestCommand("/power save ${player.name}"))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.kill(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onHit(event: EntityDamageByEntityEvent) {
|
||||||
|
val current = Game.current ?: return
|
||||||
|
if (current.timeGestion.phase != Phase.NIGHT) return
|
||||||
|
|
||||||
|
val damager = event.damager
|
||||||
|
val target = event.entity
|
||||||
|
if (damager is Player && target is Player &&
|
||||||
|
current.playersMutable.contains(damager) &&
|
||||||
|
current.playersMutable.contains(target) &&
|
||||||
|
damager.role?.lg == true &&
|
||||||
|
damager.isTransformed() &&
|
||||||
|
target.role?.lg != true &&
|
||||||
|
current.wwcankill
|
||||||
|
) {
|
||||||
|
current.wwcankill = false
|
||||||
|
target.addPotionEffect(PotionEffect(PotionEffectType.WITHER, 1200, 10))
|
||||||
|
target.addPotionEffect(PotionEffect(PotionEffectType.POISON, 1200, 10))
|
||||||
|
target.persistentDataContainer.set(NamespacedKey("tcoww", "insomie"), PersistentDataType.BOOLEAN, true)
|
||||||
|
if (target.isSleeping) target.wakeup(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(
|
||||||
|
priority = EventPriority.MONITOR,
|
||||||
|
ignoreCancelled = true
|
||||||
|
)
|
||||||
|
fun startSleep(event: PlayerBedEnterEvent) {
|
||||||
|
event.player.addPotionEffect(
|
||||||
|
PotionEffect(
|
||||||
|
PotionEffectType.REGENERATION,
|
||||||
|
PotionEffect.INFINITE_DURATION,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
event.player.addPotionEffect(
|
||||||
|
PotionEffect(
|
||||||
|
PotionEffectType.SATURATION,
|
||||||
|
PotionEffect.INFINITE_DURATION,
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(
|
||||||
|
priority = EventPriority.MONITOR,
|
||||||
|
ignoreCancelled = true
|
||||||
|
)
|
||||||
|
fun endSleep(event: PlayerBedLeaveEvent) {
|
||||||
|
event.player.removePotionEffect(PotionEffectType.SATURATION)
|
||||||
|
event.player.removePotionEffect(PotionEffectType.REGENERATION)
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun disconnect(event: PlayerQuitEvent) {
|
||||||
|
val current = Game.current ?: return
|
||||||
|
val player = event.player
|
||||||
|
if (!current.playersMutable.contains(player)) return
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
if (!player.isConnected) {
|
||||||
|
player.kill(current)
|
||||||
|
}
|
||||||
|
}, 2_400)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.kill(current: Game) {
|
||||||
|
if (isTransformed()) tfHuman()
|
||||||
|
val item = ItemStack.of(Material.PLAYER_HEAD)
|
||||||
|
val skullmeta = item.itemMeta as SkullMeta
|
||||||
|
skullmeta.owningPlayer = player
|
||||||
|
item.itemMeta = skullmeta
|
||||||
|
|
||||||
|
val loc = this.location.add(0.0, 1.5, 0.0)
|
||||||
|
val entity = this.world.spawnEntity(loc, EntityType.ITEM_DISPLAY) as ItemDisplay
|
||||||
|
entity.setItemStack(item)
|
||||||
|
Bukkit.getScheduler().runTaskLater(
|
||||||
|
plugin,
|
||||||
|
Runnable {
|
||||||
|
entity.remove()
|
||||||
|
},
|
||||||
|
2400L
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
this.gameMode = GameMode.SPECTATOR
|
||||||
|
this.isInvulnerable = false
|
||||||
|
current.playersMutable.remove(player)
|
||||||
|
|
||||||
|
this.showTitle(
|
||||||
|
Title.title(
|
||||||
|
Component.text("Vous êtes mort.").color(NamedTextColor.DARK_RED),
|
||||||
|
Component.empty(),
|
||||||
|
Title.Times.times(Duration.ZERO, Duration.ofSeconds(2), Duration.ofMillis(500))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (current.gameEnded()) current.stopGame()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.tfWerewolf() {
|
||||||
|
if (isTransformed()) return
|
||||||
|
|
||||||
|
skinUtils.applyWerewolfFur(this)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "wwtranform"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
val speedatr = getAttribute(Attribute.MOVEMENT_SPEED)!!
|
||||||
|
val scaleatr = getAttribute(Attribute.SCALE)!!
|
||||||
|
|
||||||
|
speedatr.addModifier(
|
||||||
|
AttributeModifier(
|
||||||
|
NamespacedKey("tcoww", "wwtranform"),
|
||||||
|
0.1,
|
||||||
|
AttributeModifier.Operation.ADD_NUMBER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
scaleatr.addModifier(
|
||||||
|
AttributeModifier(
|
||||||
|
NamespacedKey("tcoww", "wwtranform"),
|
||||||
|
0.1,
|
||||||
|
AttributeModifier.Operation.ADD_NUMBER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.tfHuman() {
|
||||||
|
if (!isTransformed()) return
|
||||||
|
|
||||||
|
skinUtils.unApplySkin(this)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "wwtranform"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
val speedatr = getAttribute(Attribute.MOVEMENT_SPEED)!!
|
||||||
|
val scaleatr = getAttribute(Attribute.SCALE)!!
|
||||||
|
speedatr.removeModifier(
|
||||||
|
NamespacedKey("tcoww", "wwtranform")
|
||||||
|
)
|
||||||
|
scaleatr.removeModifier(
|
||||||
|
NamespacedKey("tcoww", "wwtranform")
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Player.isTransformed(): Boolean {
|
||||||
|
return persistentDataContainer.getOrDefault(
|
||||||
|
NamespacedKey("tcoww", "wwtranform"),
|
||||||
|
PersistentDataType.BOOLEAN,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val Player.role
|
||||||
|
get() = Role.getRole(this)
|
||||||
|
}
|
||||||
20
src/main/kotlin/fr/azur/tcoww/events/TimePhaseChangeEvent.kt
Normal file
20
src/main/kotlin/fr/azur/tcoww/events/TimePhaseChangeEvent.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package fr.azur.tcoww.events
|
||||||
|
|
||||||
|
import fr.azur.tcoww.game.Phase
|
||||||
|
import org.bukkit.World
|
||||||
|
import org.bukkit.event.Event
|
||||||
|
import org.bukkit.event.HandlerList
|
||||||
|
|
||||||
|
class TimePhaseChangeEvent(
|
||||||
|
val world: World,
|
||||||
|
val newPhase: Phase
|
||||||
|
) : Event() {
|
||||||
|
override fun getHandlers(): HandlerList {
|
||||||
|
return handlerList
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
val handlerList: HandlerList = HandlerList()
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt
Normal file
82
src/main/kotlin/fr/azur/tcoww/events/ToolsEvents.kt
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package fr.azur.tcoww.events
|
||||||
|
|
||||||
|
import fr.azur.tcoww.utils.BedGestion
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
|
class ToolsEvents(val plugin: JavaPlugin) : Listener {
|
||||||
|
@EventHandler
|
||||||
|
fun clickEvent(event: PlayerInteractEvent) {
|
||||||
|
val tool = event.player.inventory.itemInMainHand
|
||||||
|
|
||||||
|
if (!tool.persistentDataContainer.has(NamespacedKey("tcoww", "tools"))) return
|
||||||
|
|
||||||
|
when (tool.persistentDataContainer.get(NamespacedKey("tcoww", "tools"), PersistentDataType.INTEGER)) {
|
||||||
|
1 -> {
|
||||||
|
event.isCancelled = true
|
||||||
|
val interactloc = event.interactionPoint
|
||||||
|
if (interactloc != null) {
|
||||||
|
if (BedGestion.isBed(interactloc.block)) {
|
||||||
|
val list = plugin.config.getMapList("bedLocation")
|
||||||
|
|
||||||
|
val block = BedGestion.getHeadBed(interactloc.block)
|
||||||
|
|
||||||
|
if (!list.contains(block.location.serialize())) {
|
||||||
|
list.add(block.location.serialize())
|
||||||
|
plugin.config.set("bedLocation", list)
|
||||||
|
plugin.saveConfig()
|
||||||
|
event.player.sendMessage(
|
||||||
|
Component.text("Bed location add.").color(NamedTextColor.LIGHT_PURPLE)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
event.player.sendMessage(
|
||||||
|
Component.text("Bed location already exists.").color(NamedTextColor.DARK_RED)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event.player.sendMessage(
|
||||||
|
Component.text("It's not a bed...").color(NamedTextColor.DARK_RED)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
event.isCancelled = true
|
||||||
|
val interactloc = event.interactionPoint
|
||||||
|
if (interactloc != null) {
|
||||||
|
interactloc.x = interactloc.blockX.toDouble()
|
||||||
|
interactloc.y = interactloc.blockY.toDouble() + 1
|
||||||
|
interactloc.z = interactloc.blockZ.toDouble()
|
||||||
|
plugin.config.set("spawnLocation", interactloc)
|
||||||
|
plugin.saveConfig()
|
||||||
|
event.player.sendMessage(Component.text("Spawn location set.").color(NamedTextColor.LIGHT_PURPLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
3 -> {
|
||||||
|
event.isCancelled = true
|
||||||
|
val interactloc = event.interactionPoint
|
||||||
|
if (interactloc != null) {
|
||||||
|
interactloc.x = interactloc.blockX.toDouble()
|
||||||
|
interactloc.y = interactloc.blockY.toDouble() + 1
|
||||||
|
interactloc.z = interactloc.blockZ.toDouble()
|
||||||
|
plugin.config.set("lobbyLocation", interactloc)
|
||||||
|
plugin.saveConfig()
|
||||||
|
event.player.sendMessage(Component.text("Lobby location set.").color(NamedTextColor.LIGHT_PURPLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @EventHandler
|
||||||
|
// fun reloadAfterWorld(worldInitEvent: WorldInitEvent) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
129
src/main/kotlin/fr/azur/tcoww/game/Game.kt
Normal file
129
src/main/kotlin/fr/azur/tcoww/game/Game.kt
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package fr.azur.tcoww.game
|
||||||
|
|
||||||
|
import fr.azur.tcoww.roles.Role
|
||||||
|
import fr.azur.tcoww.roles.Villager
|
||||||
|
import fr.azur.tcoww.roles.Werewolf
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.World
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
|
class Game(var plugin: Plugin, val world: World, val players: Iterable<Player>, var roles: Iterable<Role>) {
|
||||||
|
val werewolfPercentage: Float = plugin.config.getInt("wwcount").toFloat()
|
||||||
|
val timeGestion: TimeGestion
|
||||||
|
val playersMutable = players.toMutableList()
|
||||||
|
val timeGestShedule: BukkitTask
|
||||||
|
var wwcankill = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
players.forEach { player ->
|
||||||
|
player.persistentDataContainer.set(NamespacedKey("tcoww", "dead"), PersistentDataType.BOOLEAN, false)
|
||||||
|
player.persistentDataContainer.set(NamespacedKey("tcoww", "wwtranform"), PersistentDataType.BOOLEAN, false)
|
||||||
|
player.teleport(plugin.config.getLocation("spawnLocation")!!)
|
||||||
|
player.inventory.clear()
|
||||||
|
player.health = 20.0
|
||||||
|
}
|
||||||
|
|
||||||
|
assignRoles()
|
||||||
|
|
||||||
|
timeGestion = TimeGestion(plugin, world)
|
||||||
|
|
||||||
|
timeGestShedule = Bukkit.getScheduler().runTaskTimer(plugin, Runnable {
|
||||||
|
timeGestion.tick()
|
||||||
|
}, 0L, 1L)
|
||||||
|
|
||||||
|
current = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWerewolfInt(): Int {
|
||||||
|
val playerCount = players.count()
|
||||||
|
return ceil(playerCount * (werewolfPercentage / 100f)).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assignRoles() {
|
||||||
|
val playerList = players.shuffled().toMutableList()
|
||||||
|
|
||||||
|
val werewolfCount = getWerewolfInt()
|
||||||
|
val specialRolesCount = roles.count()
|
||||||
|
|
||||||
|
if (werewolfCount + specialRolesCount > playerList.size) {
|
||||||
|
throw IllegalArgumentException("Not enough players for the given number of werewolves and special roles.")
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat(werewolfCount) { i ->
|
||||||
|
Role.setRole(playerList[i], Werewolf())
|
||||||
|
}
|
||||||
|
|
||||||
|
roles.forEachIndexed { idx, role ->
|
||||||
|
Role.setRole(playerList[werewolfCount + idx], role)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in werewolfCount + specialRolesCount until playerList.size) {
|
||||||
|
Role.setRole(playerList[i], Villager())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var current: Game? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun gameEnded(): Boolean {
|
||||||
|
var hasWerewolf = false
|
||||||
|
var hasVillager = false
|
||||||
|
|
||||||
|
for (player in playersMutable) {
|
||||||
|
val isWerewolf = Role.getRole(player)?.lg ?: false
|
||||||
|
if (isWerewolf) hasWerewolf = true else hasVillager = true
|
||||||
|
if (hasWerewolf && hasVillager) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stopGame(withoutResult: Boolean = false) {
|
||||||
|
current ?: return
|
||||||
|
current = null
|
||||||
|
timeGestShedule.cancel()
|
||||||
|
world.time = 18000
|
||||||
|
players.forEach { player ->
|
||||||
|
player.gameMode = GameMode.SPECTATOR
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("La partie est terminée !", NamedTextColor.DARK_GREEN)
|
||||||
|
.appendNewline()
|
||||||
|
.append {
|
||||||
|
if (withoutResult)
|
||||||
|
Component.empty()
|
||||||
|
else {
|
||||||
|
val villageHasWolf = playersMutable.any {
|
||||||
|
Role.getRole(it)?.lg ?: false
|
||||||
|
}
|
||||||
|
if (villageHasWolf) {
|
||||||
|
Component.text(
|
||||||
|
"Les loups-garous ont finalement dévoré le village.",
|
||||||
|
NamedTextColor.DARK_RED
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Component.text(
|
||||||
|
"Les villageois ont finalement sauvé le village.",
|
||||||
|
NamedTextColor.DARK_BLUE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, Runnable {
|
||||||
|
players.forEach { player ->
|
||||||
|
player.teleport(plugin.config.getLocation("lobbyLocation")!!)
|
||||||
|
player.gameMode = GameMode.ADVENTURE
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/main/kotlin/fr/azur/tcoww/game/Phase.kt
Normal file
8
src/main/kotlin/fr/azur/tcoww/game/Phase.kt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package fr.azur.tcoww.game
|
||||||
|
|
||||||
|
enum class Phase {
|
||||||
|
DAY,
|
||||||
|
VOTE,
|
||||||
|
NIGHT,
|
||||||
|
CREPUSCULAR
|
||||||
|
}
|
||||||
81
src/main/kotlin/fr/azur/tcoww/game/TimeGestion.kt
Normal file
81
src/main/kotlin/fr/azur/tcoww/game/TimeGestion.kt
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package fr.azur.tcoww.game
|
||||||
|
|
||||||
|
import fr.azur.tcoww.events.TimePhaseChangeEvent
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.World
|
||||||
|
import org.bukkit.GameRule
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import java.util.Calendar
|
||||||
|
|
||||||
|
class TimeGestion(plugin: Plugin, val world: World) {
|
||||||
|
var calendar: Calendar = Calendar.getInstance()
|
||||||
|
var targetCalendar: Calendar = calendar.clone() as Calendar
|
||||||
|
var difference: Long
|
||||||
|
var differencetick: Int
|
||||||
|
|
||||||
|
val dayDuration: Int = plugin.config.getInt("duration.day")
|
||||||
|
val voteDuration: Int = plugin.config.getInt("duration.vote")
|
||||||
|
val nightDuration: Int = plugin.config.getInt("duration.night")
|
||||||
|
val crepuscularDuration: Int = plugin.config.getInt("duration.crepuscular")
|
||||||
|
|
||||||
|
var phase: Phase = Phase.DAY
|
||||||
|
var tickcorrecter = 0
|
||||||
|
|
||||||
|
init {
|
||||||
|
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false)
|
||||||
|
targetCalendar.add(Calendar.SECOND, dayDuration)
|
||||||
|
difference = targetCalendar.timeInMillis - calendar.timeInMillis
|
||||||
|
differencetick = 12500
|
||||||
|
Bukkit.getPluginManager().callEvent(TimePhaseChangeEvent(world,phase))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changePhase() {
|
||||||
|
calendar = Calendar.getInstance()
|
||||||
|
targetCalendar = calendar.clone() as Calendar
|
||||||
|
|
||||||
|
when (phase) {
|
||||||
|
// vote
|
||||||
|
Phase.DAY -> {
|
||||||
|
phase = Phase.VOTE
|
||||||
|
tickcorrecter = 12_500
|
||||||
|
differencetick = 1_500
|
||||||
|
targetCalendar.add(Calendar.SECOND, voteDuration)
|
||||||
|
}
|
||||||
|
// night
|
||||||
|
Phase.VOTE -> {
|
||||||
|
phase = Phase.NIGHT
|
||||||
|
tickcorrecter = 14_000
|
||||||
|
differencetick = 8_500
|
||||||
|
targetCalendar.add(Calendar.SECOND, nightDuration)
|
||||||
|
}
|
||||||
|
// crepuscular
|
||||||
|
Phase.NIGHT -> {
|
||||||
|
phase = Phase.CREPUSCULAR
|
||||||
|
tickcorrecter = 22_500
|
||||||
|
differencetick = 1_500
|
||||||
|
targetCalendar.add(Calendar.SECOND, crepuscularDuration)
|
||||||
|
}
|
||||||
|
// day
|
||||||
|
Phase.CREPUSCULAR -> {
|
||||||
|
phase = Phase.DAY
|
||||||
|
tickcorrecter = 0
|
||||||
|
differencetick = 12_500
|
||||||
|
targetCalendar.add(Calendar.SECOND, dayDuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Bukkit.getPluginManager().callEvent(TimePhaseChangeEvent(world,phase))
|
||||||
|
|
||||||
|
difference = targetCalendar.timeInMillis - calendar.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tick() {
|
||||||
|
if (System.currentTimeMillis() >= targetCalendar.timeInMillis) {
|
||||||
|
changePhase()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (difference == 0L) return
|
||||||
|
|
||||||
|
val result = tickcorrecter + ((differencetick.toDouble() * (System.currentTimeMillis() - calendar.timeInMillis)) / difference).toInt()
|
||||||
|
world.time = result.coerceIn(0, 23999).toLong()
|
||||||
|
}
|
||||||
|
}
|
||||||
226
src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt
Normal file
226
src/main/kotlin/fr/azur/tcoww/items/CustomItems.kt
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
package fr.azur.tcoww.items
|
||||||
|
|
||||||
|
import fr.azur.tcoww.game.Game
|
||||||
|
import fr.azur.tcoww.roles.Role
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration
|
||||||
|
import org.bukkit.Color
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.enchantments.Enchantment
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.inventory.ItemRarity
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.inventory.meta.CrossbowMeta
|
||||||
|
import org.bukkit.inventory.meta.Damageable
|
||||||
|
import org.bukkit.inventory.meta.PotionMeta
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.potion.PotionEffect
|
||||||
|
import org.bukkit.potion.PotionEffectType
|
||||||
|
|
||||||
|
enum class CustomItems(val cache: Boolean, val supplier: () -> ItemStack) {
|
||||||
|
WereWolfTransformItem(true, {
|
||||||
|
ItemStack.of(Material.BONE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
customName(Component.text("Os de transformation").color(NamedTextColor.DARK_RED))
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
3
|
||||||
|
)
|
||||||
|
lore(
|
||||||
|
listOf(
|
||||||
|
Component.text("Clique pour basculer en forme loup-garou.")
|
||||||
|
.color(NamedTextColor.GOLD)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
GunBullet(true, {
|
||||||
|
ItemStack(Material.TIPPED_ARROW).apply {
|
||||||
|
itemMeta = (itemMeta as PotionMeta).apply {
|
||||||
|
color = Color.ORANGE
|
||||||
|
displayName(Component.text("Balle de fusil.", NamedTextColor.YELLOW))
|
||||||
|
basePotionType = basePotionType.apply {
|
||||||
|
addCustomEffect(PotionEffect(PotionEffectType.INSTANT_DAMAGE, 20, 99), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BlasTechDL44(true, {
|
||||||
|
ItemStack.of(Material.CROSSBOW).apply {
|
||||||
|
itemMeta = (itemMeta as CrossbowMeta).apply {
|
||||||
|
addChargedProjectile(GunBullet.item)
|
||||||
|
displayName(Component.text("BlasTech DL-44", NamedTextColor.GOLD))
|
||||||
|
addEnchant(Enchantment.INFINITY, 1, true)
|
||||||
|
}
|
||||||
|
itemMeta = (itemMeta as Damageable).apply {
|
||||||
|
setMaxDamage(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
CrystalBall(true, {
|
||||||
|
ItemStack.of(Material.GLASS).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
customName(
|
||||||
|
Component.text("Boule de cristal").color(NamedTextColor.AQUA)
|
||||||
|
)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
4
|
||||||
|
)
|
||||||
|
lore(listOf(Component.text("/power view <pseudo> pour l'utiliser.").color(NamedTextColor.GOLD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
DeathPotion(true, {
|
||||||
|
ItemStack.of(Material.POTION).apply {
|
||||||
|
itemMeta = (itemMeta as PotionMeta).apply {
|
||||||
|
customName(
|
||||||
|
Component.text("Potion de poison").color(NamedTextColor.DARK_PURPLE)
|
||||||
|
)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
color = Color.BLACK
|
||||||
|
lore(
|
||||||
|
listOf(
|
||||||
|
Component.text("/power kill <pseudo> pour l'utiliser.").color(NamedTextColor.GOLD)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
HealPotion(true, {
|
||||||
|
ItemStack.of(Material.POTION).apply {
|
||||||
|
itemMeta = (itemMeta as PotionMeta).apply {
|
||||||
|
customName(
|
||||||
|
Component.text("Potion de vie").color(NamedTextColor.DARK_PURPLE)
|
||||||
|
)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "power"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
color = Color.RED
|
||||||
|
lore(listOf(Component.text("/power save <pseudo> pour l'utiliser.").color(NamedTextColor.GOLD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
SpawnLocTool(true, {
|
||||||
|
ItemStack.of(Material.SUGAR_CANE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
setRarity(ItemRarity.EPIC)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "tools"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
lore(listOf(Component.text("Spawn location tool").color(NamedTextColor.GOLD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BedLocTool(true, {
|
||||||
|
ItemStack.of(Material.WOODEN_HOE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
setRarity(ItemRarity.EPIC)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "tools"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
lore(listOf(Component.text("bed location tool").color(NamedTextColor.GOLD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
LobbyLocTool(true, {
|
||||||
|
ItemStack.of(Material.POPPED_CHORUS_FRUIT).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
setRarity(ItemRarity.EPIC)
|
||||||
|
persistentDataContainer.set(
|
||||||
|
NamespacedKey("tcoww", "tools"),
|
||||||
|
PersistentDataType.INTEGER,
|
||||||
|
3
|
||||||
|
)
|
||||||
|
lore(listOf(Component.text("Lobby location tool").color(NamedTextColor.GOLD)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
ListHint(false, {
|
||||||
|
val finalLore = buildList {
|
||||||
|
add(
|
||||||
|
Component.text("C'est une liste de nom.", NamedTextColor.RED)
|
||||||
|
)
|
||||||
|
add(
|
||||||
|
Component.text("Il y a écrit que un de ces 3 citoyens", NamedTextColor.DARK_RED)
|
||||||
|
)
|
||||||
|
add(
|
||||||
|
Component.text("est un loup-garou.", NamedTextColor.DARK_RED)
|
||||||
|
)
|
||||||
|
|
||||||
|
val players = Game.current?.playersMutable?.shuffled().orEmpty()
|
||||||
|
|
||||||
|
val (villagers, werewolves) = players.partition {
|
||||||
|
Role.getRole(it)?.lg == false
|
||||||
|
}
|
||||||
|
|
||||||
|
val lg = werewolves.firstOrNull()
|
||||||
|
val names = mutableListOf<Player>()
|
||||||
|
|
||||||
|
if (lg != null) names.add(lg)
|
||||||
|
names.addAll(villagers.take(2))
|
||||||
|
|
||||||
|
val colors = NamedColors.namedColors.shuffled().toMutableList()
|
||||||
|
|
||||||
|
names.shuffled().forEach {
|
||||||
|
val color = colors.removeFirst()
|
||||||
|
add(Component.text("- ").append(it.displayName()).color(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEmpty()) {
|
||||||
|
add(Component.text("nothing", NamedTextColor.DARK_RED, TextDecoration.OBFUSCATED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemStack(Material.PAPER).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
displayName(Component.text("Liste de nom", NamedTextColor.GOLD))
|
||||||
|
lore(finalLore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private var cachedItem: ItemStack? = null
|
||||||
|
|
||||||
|
val item: ItemStack
|
||||||
|
get() {
|
||||||
|
return if (cache) {
|
||||||
|
cachedItem ?: supplier().also { cachedItem = it }
|
||||||
|
} else {
|
||||||
|
supplier()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data object NamedColors {
|
||||||
|
val namedColors = listOf(
|
||||||
|
NamedTextColor.DARK_RED,
|
||||||
|
NamedTextColor.RED,
|
||||||
|
NamedTextColor.GOLD,
|
||||||
|
NamedTextColor.YELLOW,
|
||||||
|
NamedTextColor.DARK_GREEN,
|
||||||
|
NamedTextColor.GREEN,
|
||||||
|
NamedTextColor.AQUA,
|
||||||
|
NamedTextColor.DARK_AQUA,
|
||||||
|
NamedTextColor.DARK_BLUE,
|
||||||
|
NamedTextColor.BLUE,
|
||||||
|
NamedTextColor.LIGHT_PURPLE,
|
||||||
|
NamedTextColor.DARK_PURPLE
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package fr.azur.tcoww.plasmovoice.addon
|
||||||
|
|
||||||
|
import su.plo.voice.api.addon.AddonInitializer
|
||||||
|
import su.plo.voice.api.addon.InjectPlasmoVoice
|
||||||
|
import su.plo.voice.api.addon.annotation.Addon
|
||||||
|
import su.plo.voice.api.event.EventSubscribe
|
||||||
|
import su.plo.voice.api.server.PlasmoVoiceServer
|
||||||
|
import su.plo.voice.api.server.event.player.PlayerInfoCreateEvent
|
||||||
|
|
||||||
|
|
||||||
|
@Addon(
|
||||||
|
id = "tcoww",
|
||||||
|
name = "The court of werewolf",
|
||||||
|
version = "1.0.0",
|
||||||
|
authors = ["Azur"]
|
||||||
|
)
|
||||||
|
class PlasmoAddon : AddonInitializer {
|
||||||
|
@InjectPlasmoVoice
|
||||||
|
private lateinit var voiceServer: PlasmoVoiceServer
|
||||||
|
|
||||||
|
override fun onAddonInitialize() {
|
||||||
|
onConfigLoaded()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAddonShutdown() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onConfigLoaded() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventSubscribe
|
||||||
|
fun onPlayerInfoCreate(event: PlayerInfoCreateEvent) {
|
||||||
|
event.voicePlayerInfo.playerNick = "..."
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/main/kotlin/fr/azur/tcoww/roles/Child.kt
Normal file
22
src/main/kotlin/fr/azur/tcoww/roles/Child.kt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Child : Role {
|
||||||
|
override fun handle(player: Player) {}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {}
|
||||||
|
|
||||||
|
override var lg = false
|
||||||
|
override var id = NamespacedKey("tcoww", "child")
|
||||||
|
override val displayName = Component.text("Petite Fille")
|
||||||
|
override val hasPowerCommand = false
|
||||||
|
override val description =
|
||||||
|
Component.text("Extrêmement discrette et au coeur du risque.", NamedTextColor.BLUE).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text("Vous n'êtes pas obliger de dormir la nuit, vous pouvez donc observer les loups le soir.", NamedTextColor.BLUE)
|
||||||
|
)
|
||||||
|
}
|
||||||
25
src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt
Normal file
25
src/main/kotlin/fr/azur/tcoww/roles/FortuneTeller.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import fr.azur.tcoww.items.CustomItems
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class FortuneTeller : Role {
|
||||||
|
override fun handle(player: Player) {
|
||||||
|
player.inventory.addItem(CustomItems.CrystalBall.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {}
|
||||||
|
|
||||||
|
override var lg = false
|
||||||
|
override var id = NamespacedKey("tcoww", "fortune_teller")
|
||||||
|
override val displayName = Component.text("Voyante")
|
||||||
|
override val hasPowerCommand = true
|
||||||
|
override val description =
|
||||||
|
Component.text("Vous voyez des choses mais quoi ?.", NamedTextColor.BLUE).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text("Tout les 2 jours vous pouvez regarder le role d'un joueur.", NamedTextColor.BLUE)
|
||||||
|
)
|
||||||
|
}
|
||||||
34
src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt
Normal file
34
src/main/kotlin/fr/azur/tcoww/roles/Hunter.kt
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import fr.azur.tcoww.items.CustomItems
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Hunter : Role {
|
||||||
|
override fun handle(player: Player) {
|
||||||
|
player.inventory.addItem(CustomItems.BlasTechDL44.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override var lg = false
|
||||||
|
override var id = NamespacedKey("tcoww", "hunter")
|
||||||
|
override val displayName = Component.text("Chaseur")
|
||||||
|
override val hasPowerCommand = false
|
||||||
|
override val description =
|
||||||
|
Component.text(
|
||||||
|
"Vous êtes la personne, la plus redouter des animaux (et en particulier des loups).",
|
||||||
|
NamedTextColor.BLUE
|
||||||
|
).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text("Vous possedez un ", NamedTextColor.BLUE)
|
||||||
|
.append(CustomItems.BlasTechDL44.item.displayName())
|
||||||
|
.append(
|
||||||
|
Component.text(" qui permet de one shot n'importe quoi... (Usage Unique.)", NamedTextColor.BLUE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
49
src/main/kotlin/fr/azur/tcoww/roles/Role.kt
Normal file
49
src/main/kotlin/fr/azur/tcoww/roles/Role.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
|
||||||
|
interface Role {
|
||||||
|
fun handle(player: Player)
|
||||||
|
fun onDeath(player: Player)
|
||||||
|
val lg: Boolean
|
||||||
|
val id: NamespacedKey
|
||||||
|
val displayName: Component
|
||||||
|
val hasPowerCommand: Boolean
|
||||||
|
val description: Component
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var registerRoles = hashMapOf<NamespacedKey, Role>()
|
||||||
|
private val rolekey = NamespacedKey("tcoww", "role")
|
||||||
|
fun setRole(player: Player, role: Role) {
|
||||||
|
player.persistentDataContainer.set(
|
||||||
|
rolekey,
|
||||||
|
PersistentDataType.STRING,
|
||||||
|
role.id.toString()
|
||||||
|
)
|
||||||
|
player.sendMessage(
|
||||||
|
Component.text("Votre role est ").append(role.displayName).color(NamedTextColor.DARK_AQUA)
|
||||||
|
)
|
||||||
|
player.sendMessage(role.description.appendNewline().append {
|
||||||
|
if (role.lg)
|
||||||
|
Component.text("Vous gagnez avec les loups-garous.", NamedTextColor.AQUA)
|
||||||
|
else
|
||||||
|
Component.text("Vous gagnez avec les villageois.", NamedTextColor.AQUA)
|
||||||
|
})
|
||||||
|
role.handle(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRole(player: Player): Role? {
|
||||||
|
val rolestr = player.persistentDataContainer.get(rolekey, PersistentDataType.STRING)
|
||||||
|
if (rolestr == null) return null
|
||||||
|
return registerRoles[NamespacedKey.fromString(rolestr)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerRole(role: Role) {
|
||||||
|
registerRoles.put(role.id, role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main/kotlin/fr/azur/tcoww/roles/Villager.kt
Normal file
26
src/main/kotlin/fr/azur/tcoww/roles/Villager.kt
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Villager : Role {
|
||||||
|
override fun handle(player: Player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override var lg: Boolean = false
|
||||||
|
override var id = NamespacedKey("tcoww", "villager")
|
||||||
|
override val displayName = Component.text("Villageois")
|
||||||
|
override val hasPowerCommand = false
|
||||||
|
override val description =
|
||||||
|
Component.text("En tant que villageois, vous n'avez aucun pouvoir.", NamedTextColor.BLUE).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text("Profiter en pour risquer pour trouver des indices ! ^^", NamedTextColor.BLUE)
|
||||||
|
)
|
||||||
|
}
|
||||||
25
src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt
Normal file
25
src/main/kotlin/fr/azur/tcoww/roles/Werewolf.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Werewolf : Role {
|
||||||
|
override fun handle(player: Player) {}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {}
|
||||||
|
|
||||||
|
override var lg = true
|
||||||
|
override var id = NamespacedKey("tcoww", "werewolf")
|
||||||
|
override val displayName = Component.text("Loup-Garou")
|
||||||
|
override val hasPowerCommand = false
|
||||||
|
override val description =
|
||||||
|
Component.text("Pour la faire courte, vous avez faim, très faim.", NamedTextColor.BLUE).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text(
|
||||||
|
"Votre but est de tuer les villageois. Sans vous faire atraper et voter. Toute les nuits, vous pouvez vous tranformer en loup pour manger un villageois.",
|
||||||
|
NamedTextColor.BLUE
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
29
src/main/kotlin/fr/azur/tcoww/roles/Witch.kt
Normal file
29
src/main/kotlin/fr/azur/tcoww/roles/Witch.kt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package fr.azur.tcoww.roles
|
||||||
|
|
||||||
|
import fr.azur.tcoww.items.CustomItems
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class Witch : Role {
|
||||||
|
override fun handle(player: Player) {
|
||||||
|
player.inventory.addItem(CustomItems.DeathPotion.item)
|
||||||
|
player.inventory.addItem(CustomItems.HealPotion.item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDeath(player: Player) {}
|
||||||
|
|
||||||
|
override var lg = false
|
||||||
|
override var id = NamespacedKey("tcoww", "witch")
|
||||||
|
override val displayName = Component.text("Sorcière")
|
||||||
|
override val hasPowerCommand = true
|
||||||
|
override val description =
|
||||||
|
Component.text("Une potion = Une solution.", NamedTextColor.BLUE).appendNewline()
|
||||||
|
.append(
|
||||||
|
Component.text(
|
||||||
|
"Vous possédez deux potions : une pour tuer et une pour ressusciter quelqu'un.",
|
||||||
|
NamedTextColor.BLUE
|
||||||
|
)
|
||||||
|
).appendNewline()
|
||||||
|
}
|
||||||
24
src/main/kotlin/fr/azur/tcoww/utils/BedGestion.kt
Normal file
24
src/main/kotlin/fr/azur/tcoww/utils/BedGestion.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package fr.azur.tcoww.utils
|
||||||
|
|
||||||
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.block.data.type.Bed
|
||||||
|
|
||||||
|
object BedGestion {
|
||||||
|
fun isBed(block: Block): Boolean {
|
||||||
|
return block.blockData is Bed
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHeadBed(block: Block): Block {
|
||||||
|
val bedData = block.blockData as Bed
|
||||||
|
return if (bedData.part == Bed.Part.FOOT) {
|
||||||
|
block.getRelative(bedData.facing)
|
||||||
|
} else {
|
||||||
|
block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isOcupied(block: Block): Boolean {
|
||||||
|
val bedData = block.blockData as Bed
|
||||||
|
return bedData.isOccupied
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/main/kotlin/fr/azur/tcoww/utils/Skin.kt
Normal file
65
src/main/kotlin/fr/azur/tcoww/utils/Skin.kt
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package fr.azur.tcoww.utils
|
||||||
|
|
||||||
|
import net.skinsrestorer.api.SkinsRestorer
|
||||||
|
import net.skinsrestorer.api.property.SkinProperty
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class Skin(private val plugin: Plugin, private val skinsRestorer: SkinsRestorer) {
|
||||||
|
|
||||||
|
var maxSkinId: Int = 0
|
||||||
|
private set
|
||||||
|
|
||||||
|
init {
|
||||||
|
reloadSkin()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reloadSkin() {
|
||||||
|
val skinsValue = plugin.config.getStringList("wwskinsvalue")
|
||||||
|
val skinsSignature = plugin.config.getStringList("wwskinssignature")
|
||||||
|
Stockage.wwPlayerFur.clear()
|
||||||
|
|
||||||
|
maxSkinId = 0
|
||||||
|
skinsValue.zip(skinsSignature).forEachIndexed { index, (value, signature) ->
|
||||||
|
skinsRestorer.skinStorage.setCustomSkinData("tcoww_$index", SkinProperty.of(value, signature))
|
||||||
|
maxSkinId = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun applyWerewolfFur(player: Player) {
|
||||||
|
val skin = skinsRestorer.playerStorage.getSkinIdOfPlayer(player.uniqueId)
|
||||||
|
Stockage.oldPlayerSkin[player.uniqueId] = skin.getOrNull()
|
||||||
|
|
||||||
|
val result = skinsRestorer.skinStorage.findOrCreateSkinData("tcoww_${getWerewolfFur(player.uniqueId)}")
|
||||||
|
|
||||||
|
if (!result.isEmpty) {
|
||||||
|
skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId, result.get().identifier)
|
||||||
|
skinsRestorer.getSkinApplier(Player::class.java).applySkin(player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unApplySkin(player: Player) {
|
||||||
|
val skin = Stockage.oldPlayerSkin[player.uniqueId]
|
||||||
|
if (skin == null) {
|
||||||
|
skinsRestorer.playerStorage.removeSkinIdOfPlayer(player.uniqueId)
|
||||||
|
} else {
|
||||||
|
skinsRestorer.playerStorage.setSkinIdOfPlayer(player.uniqueId,skin)
|
||||||
|
}
|
||||||
|
skinsRestorer.getSkinApplier(Player::class.java).applySkin(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWerewolfFur(playerUUID: UUID): Int {
|
||||||
|
return Stockage.wwPlayerFur[playerUUID]
|
||||||
|
?: randomFur(playerUUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun randomFur(playerUUID: UUID): Int {
|
||||||
|
val id = if (maxSkinId == 0) 0 else Random(playerUUID.mostSignificantBits xor playerUUID.leastSignificantBits).nextInt(maxSkinId)
|
||||||
|
Stockage.wwPlayerFur[playerUUID] = id
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
13
src/main/kotlin/fr/azur/tcoww/utils/Stockage.kt
Normal file
13
src/main/kotlin/fr/azur/tcoww/utils/Stockage.kt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package fr.azur.tcoww.utils
|
||||||
|
|
||||||
|
import net.skinsrestorer.api.property.SkinIdentifier
|
||||||
|
import org.bukkit.Location
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
object Stockage {
|
||||||
|
var backLocation = mutableMapOf<UUID, Location>()
|
||||||
|
var vote = mutableMapOf<UUID, UUID>()
|
||||||
|
var oldPlayerSkin = mutableMapOf<UUID, SkinIdentifier?>()
|
||||||
|
var wwPlayerFur = mutableMapOf<UUID, Int>()
|
||||||
|
}
|
||||||
38
src/main/resources/config.yml
Normal file
38
src/main/resources/config.yml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
spawnLocation:
|
||||||
|
==: org.bukkit.Location
|
||||||
|
world: world
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
pitch: 0.0
|
||||||
|
yaw: 0.0
|
||||||
|
lobbyLocation:
|
||||||
|
==: org.bukkit.Location
|
||||||
|
world: world
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
pitch: 0.0
|
||||||
|
yaw: 0.0
|
||||||
|
duration: # In seconds
|
||||||
|
day: 600
|
||||||
|
vote: 120
|
||||||
|
night: 300
|
||||||
|
crepuscular: 20
|
||||||
|
wwcount: 10
|
||||||
|
# The skin value
|
||||||
|
wwskinsvalue: [
|
||||||
|
"ewogICJ0aW1lc3RhbXAiIDogMTYxNzQ2NzI1ODQxMCwKICAicHJvZmlsZUlkIiA6ICJjMGYzYjI3YTUwMDE0YzVhYjIxZDc5ZGRlMTAxZGZlMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDEzIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y5NmM4OWUwZWYwZmVlZjZkODc4ZDUzYzQ4OWIyMzliNDdlNmViODQyZDJmM2MzZTlhZDdkMjliZmYxYTM0OWUiCiAgICB9CiAgfQp9",
|
||||||
|
"ewogICJ0aW1lc3RhbXAiIDogMTYxNTYxMTkwOTY4MCwKICAicHJvZmlsZUlkIiA6ICIwMGM2Yjk0YTY5YmU0MzY3OTkwOTQxNjFjMjAxOWI3ZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJLQUVWRVJZIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2I0MGRjNTcxZGUwZGQ4ZmQ5NzBjNzNmOTE2NGJjMTQ0Njk1MWFlNDhkNWFiZTQyMzI5MGVlYjFhODc4NDU1ZmUiCiAgICB9CiAgfQp9",
|
||||||
|
"ewogICJ0aW1lc3RhbXAiIDogMTc0Nzk4MDc5ODQyMywKICAicHJvZmlsZUlkIiA6ICI2NWI5NTU1YWQyMGU0NWM5YjFkNmU3MjQwNjU0NTBkNCIsCiAgInByb2ZpbGVOYW1lIiA6ICJKYXZhUHJvZmlsZU5hbWVYIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzJlZTlmNjcxYzFmNjY4Y2IwYWUwNGE5YzhiZWM0OTVlYTVmNzNmNTNmYmY3ZjM5MmNkYjdlMTc1ZmVjZDFjYmUiCiAgICB9CiAgfQp9",
|
||||||
|
"ewogICJ0aW1lc3RhbXAiIDogMTY0Mjc4ODk3NDg1NSwKICAicHJvZmlsZUlkIiA6ICIzYzE0YmVkNDFiOGE0MDIzOGM3MDgzMTA1NzEwMTZmYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJOb2Jpa28iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWZlNzIzMDdjZTEyNmI1Y2I0ZDQ0ZGFlZTcwZDI1ZmQwNDMwOGJjN2M0MzI4OWM3ZDk3MDY4NDY5NWI2MGJhIgogICAgfQogIH0KfQ=="
|
||||||
|
]
|
||||||
|
# The skin signature (see mineskin.org)
|
||||||
|
wwskinssignature: [
|
||||||
|
"uWIu/2R3zImj87H7x//O/04eJ1SwsHvLSxaj1YQuI1vBndUVHhN42Ja7AOJoAieVO8yN1qn/rJj1oK5z5koQ2fZwjNCc0mKTrakCMWGqjaAImDw8RWriUQ3ClPCw6NtCmB1qVUp60kUEpGha/btUSsAEUnVZ0ghM4SXTcS2izbDe/dRfbi5EDr2Uue3sz6+med3hjecZzrKJUX19wP1WwPifEOH2X/smzzGOdqlQtylMZQh3nNeho/GBwbDVXsXsR6LcDgoInDnw63cDV7n4dTs6giGmcx0knhDWH24Z/vrgNSqzbNY9hIgVBNWUqs/1o7/xrbK1HilYBPAiVO0F6+vJOpzdFrpEZVr0M++u+X2Zkt1sfshKZqt0O07KbH8h4xj3J+6iDF5RHHFGmZy0awFGZGIi8wqlffwQfZ+l7nPU1hpMD5DkArxBWJWgnquyCNpQ44OlmTpPRa/gopRpuMwJ1r6vDPhgIavJX6cKQ2lKTYKG2/HB+ZEl/IUtuXxKO7bFe4KOvjJpMwBjOmzqbn2sk3GqbSg8NfNMFA4FjRBvHXOaMsDCqz0MJxLFKvIfYRVWG8XAU6BU82RoS3qGFSOhI6N/DvD7dx1V40q52iWv2j4/S41P5zrtMqQm7wofocptz6sS7GLE1u9rPCBLRIck0wzi3OF7MV2p4wlw6lw=",
|
||||||
|
"kVGwx98YPc6tIZ306TiGI5eoK4v7oEjIvCaOPS03jq4LjBWV12NBTWW67u+HrI2/2m3r8pvAyx1Ddpw4YWyaDbaG0FvLuurWbETqtwvyvVx7R3BZHgw2EnVOYk4+WPmA8xUgzoIbZF/Ch4bSqP7UlZy7/fz4AQwFK/qLMzApOAeV4Kzn4p6+MK2uOkfSjGgwxqAO/+TZj6u01mk1NKNh4ors9RGDG3DBHZKSxTG/PzY5ErKABRXkB/RBMA5IvU5Rzn5cH+Sfkus/7LtYp5u+5i+HcpN/klyBBw4D5di3WzFOAIX78ZiyKzKzWpSN0z6Cb2DZdo1ufeZH9mw8nv+A8VfpGXwphwde+oGBP4l4OffE7YvbnWyVHmlG0L36iI2/FkWQl91GIT15YBHrjeQ9pmvbzCQUMyAHi2jZePTTcT1rDnSzBk7fc9IwfcBRNyqbveTNu9zikfx0W6GnXAbV4qOTIIVEHlpxQ9KW017sqmgiF5l/3ZVwqbEQzglNehYHA55vRfKY0HKbGB54k1oTnM3X7mNXIu6fk8dVgCvT8lVdDm3LWcE6aWF8Yp6QrXNvTNW1yxSRAhigsHrvbajp2Odg18lMTng0oh/4JiYOQAgb6tFdRtQ4nrSVHRBOEvY09IRFzVTTd7n2JaYZ6QcCMOiKOX25fv22rbjSeAZ/Whk=",
|
||||||
|
"wGc2rNbc7+nziEDMKFoBIltHZwx5PQfsfMGyRTfTUdtVi3O4iu0idcpTsTVJ80njIFZvmLpzlwjPu6ULrXJwgQQyGCNdp60jQMl9vGjzgJzs6uqhSCke3EvjOCuAGkv2ScRY5hDGQOnIruxwmgYgDeXHnujt+zTBvW+imxLVaZhXoKVPyqlvm6njWp0XECyAi8DFKbzIdDVp+NsRzIGjKeVoMgWd4xlNazUZGgTsXNCD/+aZOJ1LxA51I8Wgsm888MUXnaGhNI3U4jJNKHAPZMS4++JEuwWzlptJdZIa1jOfwMD6HvIPKEmC5+eDCRFvPIEh84VqErtNTPEUAz7wZAJvO+j+x5A/9VnQmKJhEBxBjlw1Ky+mQcLJnRX/x9jc4EvEd9gWGIUj46y3IF8jWn71eXvinSJ4Op4LQEiv5BfuyMTfY2xwFTlGWjdYF6Xnac+Gz6+E1gjCBSuqKWd56QFDcrqCcvbG50ERhenCUEhUgI33rXNxS/hwz2iClVM26GFJlUtZkZ7/021FjEQNLEYivI1ZkHe9ip8sxx2QVKd5k7Ui/hXkP4xSal3okL4Ar/cThMh0aoWzziYsoAahtoxFWEags7lNOffMoLGmPbgGVRUGHogNu2CES0SNs4AhHVUVERo8OTJHx46XJxXqvLzeEn6zXFD63XXQR8AyXTQ=",
|
||||||
|
"hJ/FhIMQY9G/BqOvGJ0nhuJk/7Y/q/unCpeC7LxGvcYjXzsY/kcInwUzgfjRqNI0oI5ggOAdxIiaGvBRqWCshjxcx6iRyJZBMKwFchM1baHntRl22yxvBA16gpMxbWTihQ0Jtz9m/Dj8clYgyEkMOKFEOya5YiyyqjK+YOl5xWiM1pGAomFixqr7VBLk/NE7e+qYXuFjDl3IZ1OP+tgdgyjkqUZE3OBGQfXP6wvTFjgk/maCPUmzffnbw/yH4JZIa3N/vhK+jzowcV+ymZK/9+10ge8hIZ5LZPdU90xLWd2zPYFjju/vr9TFWUG4YkV8l1vSsG7P8MYjMKFh/YQoTyyjJUZw9YGfnRENZrdegttUxefJywpBgp0xVt5vyAMM9XjTEtwK/A5gef0fD52lKWpwD6xamPBnhb8yRPUnncapGBrQvFhB8uQnkS8BKqtiJyz8XJHg8quzUXjYd+Ywn5p+lzP5zsDXQDYOfcm4FZGYp3oFwJZz1s4YOjP8Abjd+4v0sQIcP+Kj8lBzrADQSvTIJaQZO/emnpkZYoW/ggSJLa+BrRUXK5gNHdZzUI/EDOJggrGn3ezSLd96DyDlosG+lGM/EpuiB504YNzQfrm1scVbk9R4YHNhy+sau04DJcRY0p52qeaVDswMkfjUA6JBvBFT9SqQeB7q9qRwLrk="
|
||||||
|
]
|
||||||
|
# The time in second before teleport no sleeping player
|
||||||
|
playerSleep: 20
|
||||||
16
src/main/resources/paper-plugin.yml
Normal file
16
src/main/resources/paper-plugin.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
name: tcoww
|
||||||
|
version: '1.0-SNAPSHOT'
|
||||||
|
main: fr.azur.tcoww.Tcoww
|
||||||
|
api-version: '1.21'
|
||||||
|
load: POSTWORLD
|
||||||
|
authors: [ Azur84 ]
|
||||||
|
bootstrapper: fr.azur.tcoww.TcowwBootstrap
|
||||||
|
dependencies:
|
||||||
|
server:
|
||||||
|
SkinsRestorer:
|
||||||
|
load: BEFORE
|
||||||
|
required: true
|
||||||
|
join-classpath: true
|
||||||
|
PlasmoVoice:
|
||||||
|
load: BEFORE
|
||||||
|
required: true
|
||||||
Reference in New Issue
Block a user