Add new game states

This commit is contained in:
Laurin
2025-12-04 15:01:10 +01:00
parent ac185e35ce
commit 2c10e3e7fd
10 changed files with 724 additions and 26 deletions

View File

@@ -37,8 +37,8 @@ dependencies {
compileOnly("net.luckperms:api:5.4") compileOnly("net.luckperms:api:5.4")
implementation("club.mcscrims:core:1.4.1") implementation("club.mcscrims:core:1.4.2")
implementation("club.mcscrims:spigot:1.4.1") implementation("club.mcscrims:spigot:1.4.2")
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT") paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT")

View File

@@ -12,6 +12,7 @@ import club.mcscrims.speedhg.game.GameManager
import club.mcscrims.spigot.chat.ChatFormatter import club.mcscrims.spigot.chat.ChatFormatter
import club.mcscrims.spigot.chat.ChatManager import club.mcscrims.spigot.chat.ChatManager
import club.mcscrims.spigot.network.SpigotNetworkManager import club.mcscrims.spigot.network.SpigotNetworkManager
import club.mcscrims.spigot.scheduler.SchedulerManager
import com.mongodb.client.model.Indexes import com.mongodb.client.model.Indexes
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import net.luckperms.api.LuckPerms import net.luckperms.api.LuckPerms
@@ -35,6 +36,7 @@ class SpeedHG : JavaPlugin() {
internal lateinit var statsRepository: StatsRepository internal lateinit var statsRepository: StatsRepository
internal lateinit var networkManager: SpigotNetworkManager internal lateinit var networkManager: SpigotNetworkManager
internal lateinit var schedulerManager: SchedulerManager
internal lateinit var gameManager: GameManager internal lateinit var gameManager: GameManager
@@ -57,7 +59,10 @@ class SpeedHG : JavaPlugin() {
chatManager = ChatManager.withCustomConfig( this, chatFormatter ) chatManager = ChatManager.withCustomConfig( this, chatFormatter )
chatManager.initialize() chatManager.initialize()
schedulerManager = SchedulerManager( this )
gameManager = GameManager( this ) gameManager = GameManager( this )
gameManager.initialize()
setupLuckPerms() setupLuckPerms()
} }

View File

@@ -1,9 +1,13 @@
package club.mcscrims.speedhg.config package club.mcscrims.speedhg.config
import club.mcscrims.core.config.ConfigData
import club.mcscrims.core.config.DurationEntry
import club.mcscrims.core.config.DurationType
import club.mcscrims.core.config.annotations.ConfigClass import club.mcscrims.core.config.annotations.ConfigClass
import club.mcscrims.core.config.annotations.ConfigField import club.mcscrims.core.config.annotations.ConfigField
import club.mcscrims.core.config.annotations.DefaultValue import club.mcscrims.core.config.annotations.DefaultValue
import club.mcscrims.core.network.NetworkConfig import club.mcscrims.core.network.NetworkConfig
import club.mcscrims.speedhg.SpeedHG
@ConfigClass( @ConfigClass(
name = "config", name = "config",
@@ -55,7 +59,7 @@ data class PluginConfig(
val minimumPlayers: Int = 8, val minimumPlayers: Int = 8,
val competitiveGame: Boolean = false, val competitiveGame: Boolean = false,
val competitiveCommands: List<String> = emptyList(), val competitiveCommands: List<String> = emptyList(),
val playerState: Map<String, String> = getPlayerStates(), val playerStates: Map<String, StateConfig> = getPlayerStates(),
val recraftNerf: Map<String, Any> = getRecraftNerf(), val recraftNerf: Map<String, Any> = getRecraftNerf(),
val teams: Map<String, Any> = getTeams(), val teams: Map<String, Any> = getTeams(),
val blockedKits: List<String> = emptyList(), val blockedKits: List<String> = emptyList(),
@@ -63,16 +67,56 @@ data class PluginConfig(
val perks: Map<String, Any> = getPerks() val perks: Map<String, Any> = getPerks()
) )
fun isDurationIncreasing(
entry: DurationEntry
): Boolean
{
return entry.type == DurationType.INCREASING
}
fun getDuration(
playerState: String
): DurationEntry
{
return SpeedHG.instance.pluginConfig.parseDuration( "game.playerStates.$playerState.duration" )
}
data class StateConfig(
val duration: Any,
val scoreboard: String
)
} }
private fun getPlayerStates() = mapOf( private fun getPlayerStates() = mapOf(
"waiting" to "Waiting - %time%", "waiting" to PluginConfig.StateConfig(
"pre_start" to "Waiting - %time%", DurationEntry( DurationType.FIXED, -1 ),
"immunity" to "Playing - %time%", "Waiting - %time%"
"battle" to "Playing - %time%", ),
"feast" to "Playing - %time%", "pre_start" to PluginConfig.StateConfig(
"deathmatch" to "Playing - %time%", DurationEntry( DurationType.FIXED, 300 ),
"end" to "Ending - %time%", "Waiting - %time%"
),
"immunity" to PluginConfig.StateConfig(
DurationEntry( DurationType.FIXED, 90 ),
"Playing - %time%"
),
"battle" to PluginConfig.StateConfig(
DurationEntry( DurationType.INCREASING ),
"Playing - %time%"
),
"feast" to PluginConfig.StateConfig(
DurationEntry( DurationType.FIXED, 300 ),
"Playing - %time%"
),
"deathmatch" to PluginConfig.StateConfig(
DurationEntry( DurationType.INCREASING ),
"Playing - %time%"
),
"end" to PluginConfig.StateConfig(
DurationEntry( DurationType.FIXED, 60 ),
"Ending - %time%"
),
) )
private fun getRecraftNerf() = mapOf( private fun getRecraftNerf() = mapOf(
@@ -101,4 +145,4 @@ private fun getAnnouncementConfiguration() = mapOf(
"enabled" to true, "enabled" to true,
"after" to 10, "after" to 10,
"minimumPlayers" to 6 "minimumPlayers" to 6
) )

View File

@@ -1,13 +1,31 @@
package club.mcscrims.speedhg.game package club.mcscrims.speedhg.game
import org.bukkit.plugin.java.JavaPlugin import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.game.impl.WaitingState
class GameManager( class GameManager(
private val plugin: JavaPlugin private val plugin: SpeedHG
) { ) {
private var currentState: GameState? = null private var currentState: GameState? = null
fun initialize()
{
currentState = WaitingState(
this,
plugin,
plugin.schedulerManager,
plugin.pluginConfig.data.getDuration( "waiting" ).seconds
)
try {
currentState?.onEnter( null )
} catch ( e: Exception ) {
plugin.logger.severe("Error during onEnter for state ${currentState?.name}: ${e.message}")
e.printStackTrace()
}
}
fun transitionTo( fun transitionTo(
nextState: GameState nextState: GameState
) { ) {

View File

@@ -8,7 +8,7 @@ import org.bukkit.entity.Player
import org.bukkit.event.HandlerList import org.bukkit.event.HandlerList
import org.bukkit.event.Listener import org.bukkit.event.Listener
open class GameState( abstract class GameState(
val name: String, val name: String,
protected val gameManager: GameManager, protected val gameManager: GameManager,
protected val plugin: SpeedHG, protected val plugin: SpeedHG,
@@ -31,11 +31,11 @@ open class GameState(
startTicking() startTicking()
} }
open fun onTick() {} abstract fun onTick()
open fun onEndOfDuration() {} abstract fun onEndOfDuration()
open fun onExit( open fun onExit(
next: GameState? next: GameState?
) { ) {
isActive = false isActive = false
@@ -64,7 +64,7 @@ open class GameState(
{ {
remainingSeconds-- remainingSeconds--
if ( remainingSeconds <= 0) if ( remainingSeconds == 0)
try { try {
onEndOfDuration() onEndOfDuration()
} catch ( e: Exception ) { } catch ( e: Exception ) {

View File

@@ -0,0 +1,252 @@
package club.mcscrims.speedhg.game.impl
import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.game.GameManager
import club.mcscrims.speedhg.game.GameState
import club.mcscrims.speedhg.game.impl.PreStartState.AnnouncementType
import club.mcscrims.speedhg.util.DirectionUtil
import club.mcscrims.spigot.scheduler.SchedulerManager
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.event.Event
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.entity.FoodLevelChangeEvent
import org.bukkit.event.inventory.CraftItemEvent
import org.bukkit.event.player.PlayerDropItemEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.potion.PotionEffect
import org.bukkit.potion.PotionEffectType
class ImmunityState(
gameManager: GameManager,
plugin: SpeedHG,
schedulerManager: SchedulerManager,
durationSeconds: Int? = null
) : GameState( "immunity", gameManager, plugin, schedulerManager, durationSeconds ), Listener {
override fun onEnter(
previous: GameState?
) {
super.onEnter( previous )
registerListener( this )
val effects = listOf(
PotionEffect( PotionEffectType.HASTE, durationSeconds?.times( 20 ) ?: 0, 0 ),
PotionEffect( PotionEffectType.SPEED, durationSeconds?.times( 20 ) ?: 0, 0 )
)
val players = Bukkit.getOnlinePlayers()
players.forEach { it.addPotionEffects( effects ) }
for ( player in players )
{
player.inventory.clear()
player.inventory.armorContents = emptyArray()
player.inventory.setItem( 8, ItemStack( Material.COMPASS ))
TODO( "Give kits and perks" )
}
broadcast( "gameStates.immunity.warnings.butterfly" )
TODO( "register kits & perks" )
}
override fun onTick()
{
when( durationSeconds )
{
180 -> announce( AnnouncementType.MINUTES, 3 )
120 -> announce( AnnouncementType.MINUTES, 2 )
60 -> announce( AnnouncementType.MINUTES, 1 )
30 -> announce( AnnouncementType.SECONDS, 30 )
15 -> announce( AnnouncementType.SECONDS, 15 )
10 -> announce( AnnouncementType.SECONDS, 10 )
5 -> announce( AnnouncementType.SECONDS, 5 )
4 -> announce( AnnouncementType.SECONDS, 4 )
3 -> announce( AnnouncementType.SECONDS, 3 )
2 -> announce( AnnouncementType.SECONDS, 2 )
1 -> announce( AnnouncementType.SECONDS, 1 )
0 ->
{
broadcast( "gameStates.immunity.ended" )
gameManager.transitionTo( TODO() )
}
}
}
override fun onEndOfDuration() {}
private fun announce(
type: AnnouncementType,
time: Int
) {
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
broadcast( "gameStates.immunity.ending$arg", "{time}" to time.toString() )
}
@EventHandler
fun onInteractCompass(
event: PlayerInteractEvent
) {
val player = event.player
val action = event.action
if ( action != Action.RIGHT_CLICK_BLOCK &&
action != Action.RIGHT_CLICK_AIR )
return
val item = event.item
?: return
if ( item.type != Material.COMPASS )
return
val nearestPlayer = Bukkit.getOnlinePlayers().stream()
.filter { other -> other != player }
.map { other -> other.location.distance( player.location ) to other }
.filter { pair -> pair.first > 5.0 }
.toList()
.firstOrNull()
?.second
if ( nearestPlayer == null )
{
plugin.chatManager.sendMessage( player, "compass.no_nearby_players" )
return
}
player.compassTarget = nearestPlayer.location
val direction = DirectionUtil.getDirectionToPlayer( player, nearestPlayer )
val actionBar = plugin.chatFormatter.format( "compass.actionBar" )
actionBar.replaceText { it.match( "<direction>" ).replacement( direction ).once() }
plugin.chatManager.sendInteractiveMessage( player, actionBar )
}
@EventHandler
fun onDropItem(
event: PlayerDropItemEvent
) {
val player = event.player
TODO( "Add kit & perk check" )
}
@EventHandler
fun onCraftItem(
event: CraftItemEvent
) {
val player = event.whoClicked
if ( player !is Player )
return
val item = event.recipe.result
if ( item.type == Material.SHIELD )
{
if ( event.isShiftClick )
{
plugin.chatManager.sendMessage( player, "craft.no_siftclick" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
return
}
event.result = Event.Result.DENY
plugin.chatManager.sendMessage( player, "craft.no_shield" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
return
}
if (!item.type.name.contains( "iron", true ))
return
if ( event.isShiftClick )
{
plugin.chatManager.sendMessage( player, "craft.no_siftclick" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
return
}
event.result = Event.Result.DENY
plugin.chatManager.sendMessage( player, "craft.no_iron_before_feast" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onBlockBreak(
event: BlockBreakEvent
) {
val player = event.player
val block = event.block
if ( block.type == Material.DIAMOND_ORE )
{
event.isCancelled = true
block.type = Material.AIR
block.tick()
plugin.chatManager.sendMessage( player, "build.no_diamonds" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
return
}
if ( block.type == Material.IRON_ORE )
{
event.isCancelled = true
plugin.chatManager.sendMessage( player, "build.no_iron_before_feast" )
player.playSound( player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
return
}
}
@EventHandler
fun onInteract(
event: PlayerInteractEvent
) {
val player = event.player
val action = event.action
if ( action != Action.RIGHT_CLICK_BLOCK &&
action != Action.RIGHT_CLICK_AIR )
return
val item = event.item
?: return
TODO( "Check for kit items" )
}
@EventHandler
fun onEntityDamage(
event: EntityDamageEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
@EventHandler
fun onFoodLevelChange(
event: FoodLevelChangeEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
}

View File

@@ -0,0 +1,194 @@
package club.mcscrims.speedhg.game.impl
import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.game.GameManager
import club.mcscrims.speedhg.game.GameState
import club.mcscrims.spigot.scheduler.SchedulerManager
import org.bukkit.Bukkit
import org.bukkit.Location
import org.bukkit.Sound
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.block.LeavesDecayEvent
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.entity.FoodLevelChangeEvent
import org.bukkit.event.player.PlayerAttemptPickupItemEvent
import org.bukkit.event.player.PlayerDropItemEvent
class PreStartState(
gameManager: GameManager,
plugin: SpeedHG,
schedulerManager: SchedulerManager,
durationSeconds: Int? = null
) : GameState( "pre_start", gameManager, plugin, schedulerManager, durationSeconds ), Listener {
private lateinit var previous: GameState
override fun onEnter(
previous: GameState?
) {
super.onEnter( previous )
registerListener( this )
if ( previous != null )
this.previous = previous
}
var isStarting: Boolean = false
override fun onTick()
{
val playerSize = Bukkit.getOnlinePlayers().size
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
{
isStarting = false
transitionToPrevious()
}
else isStarting = true
if ( !isStarting )
return
if ( durationSeconds == 15 )
teleport()
when( durationSeconds )
{
300 -> announce( AnnouncementType.MINUTES, 5 )
240 -> announce( AnnouncementType.MINUTES, 4 )
180 -> announce( AnnouncementType.MINUTES, 3 )
120 -> announce( AnnouncementType.MINUTES, 2 )
60 -> announce( AnnouncementType.MINUTES, 1 )
30 -> announce( AnnouncementType.SECONDS, 30 )
15 -> announce( AnnouncementType.SECONDS, 15 )
10 -> announce( AnnouncementType.SECONDS, 10 )
5 -> announce( AnnouncementType.SECONDS, 5 )
4 -> announce( AnnouncementType.SECONDS, 4 )
3 -> announce( AnnouncementType.SECONDS, 3 )
2 -> announce( AnnouncementType.SECONDS, 2 )
1 -> announce( AnnouncementType.SECONDS, 1 )
0 ->
{
broadcast( "gameStates.preStart.started" )
isStarting = false
gameManager.transitionTo(ImmunityState( gameManager, plugin, schedulerManager, plugin.pluginConfig.data.getDuration( "immunity" ).seconds ))
}
}
}
override fun onExit(
next: GameState?
) {
super.onExit( next )
Bukkit.getOnlinePlayers().forEach { it.inventory.clear() }
}
override fun onEndOfDuration() {}
private fun announce(
type: AnnouncementType,
time: Int
) {
val arg = if ( type == AnnouncementType.MINUTES ) "M" else "S"
broadcast( "gameStates.preStart.starting$arg", "{time}" to time.toString() )
}
private fun teleport()
{
for ( player in Bukkit.getOnlinePlayers() )
{
val world = player.world
val loc = Location( world, 0.0, world.getHighestBlockYAt( 0, 0 ).toDouble(), 0.0 )
player.teleport( loc )
}
}
private fun transitionToPrevious()
{
if ( ::previous.isInitialized )
{
gameManager.transitionTo( previous )
return
}
gameManager.transitionTo(WaitingState( gameManager, plugin, schedulerManager, plugin.pluginConfig.data.getDuration( "waiting" ).seconds ))
}
@EventHandler
fun onLeavesDecay(
event: LeavesDecayEvent
) {
event.isCancelled = true
}
@EventHandler
fun onBlockBreak(
event: BlockBreakEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onBlockPlace(
event: BlockPlaceEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onPlayerPickupItem(
event: PlayerAttemptPickupItemEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
@EventHandler
fun onPlayerDropItem(
event: PlayerDropItemEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onEntityDamage(
event: EntityDamageEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
@EventHandler
fun onFoodLevelChange(
event: FoodLevelChangeEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
internal enum class AnnouncementType {
MINUTES, SECONDS
}
}

View File

@@ -0,0 +1,121 @@
package club.mcscrims.speedhg.game.impl
import club.mcscrims.speedhg.SpeedHG
import club.mcscrims.speedhg.game.GameManager
import club.mcscrims.speedhg.game.GameState
import club.mcscrims.spigot.scheduler.SchedulerManager
import org.bukkit.Bukkit
import org.bukkit.Sound
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.block.BlockPlaceEvent
import org.bukkit.event.block.LeavesDecayEvent
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.entity.FoodLevelChangeEvent
import org.bukkit.event.player.PlayerAttemptPickupItemEvent
import org.bukkit.event.player.PlayerDropItemEvent
class WaitingState(
gameManager: GameManager,
plugin: SpeedHG,
schedulerManager: SchedulerManager,
durationSeconds: Int? = null
) : GameState( "waiting", gameManager, plugin, schedulerManager, durationSeconds ), Listener {
override fun onEnter(
previous: GameState?
) {
super.onEnter( previous )
registerListener( this )
}
private var secondsCounter: Int = 0
override fun onTick()
{
val playerSize = Bukkit.getOnlinePlayers().size
if ( playerSize < plugin.pluginConfig.data.game.minimumPlayers )
if ( secondsCounter == 15 )
{
broadcast( "gameStates.waiting.awaiting_players", "{min_players}" to plugin.pluginConfig.data.game.minimumPlayers.toString() )
secondsCounter = 0
}
else secondsCounter++
else gameManager.transitionTo(PreStartState( gameManager, plugin, schedulerManager, plugin.pluginConfig.data.getDuration( "pre_start" ).seconds ))
}
override fun onEndOfDuration() {}
@EventHandler
fun onLeavesDecay(
event: LeavesDecayEvent
) {
event.isCancelled = true
}
@EventHandler
fun onBlockBreak(
event: BlockBreakEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onBlockPlace(
event: BlockPlaceEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onPlayerPickupItem(
event: PlayerAttemptPickupItemEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
@EventHandler
fun onPlayerDropItem(
event: PlayerDropItemEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
event.player.playSound( event.player, Sound.BLOCK_NOTE_BLOCK_BASS, 1f, 1f )
}
@EventHandler
fun onEntityDamage(
event: EntityDamageEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
@EventHandler
fun onFoodLevelChange(
event: FoodLevelChangeEvent
) {
if ( gameManager.getCurrentState() != this )
return
event.isCancelled = true
}
}

View File

@@ -0,0 +1,50 @@
package club.mcscrims.speedhg.util
import club.mcscrims.speedhg.SpeedHG
import net.kyori.adventure.text.Component
import org.bukkit.entity.Player
import org.bukkit.util.Vector
import kotlin.math.atan2
object DirectionUtil {
private val plugin = SpeedHG.instance
private val directions = arrayOf("north", "northEast", "east", "southEast", "south", "southWest", "west", "northWest")
fun getDirectionToPlayer(
player: Player,
nearestPlayer: Player
): Component
{
val yaw = getDirection( player, nearestPlayer )
var normalizedYaw = yaw % 360
if ( normalizedYaw < 0 )
normalizedYaw += 360
val index = (( normalizedYaw + 22.5 ) / 45 ).toInt() % 8
return plugin.chatFormatter.format( "compass.directions.${directions[ index ]}" )
}
private fun getDirection(
fromPlayer: Player,
toPlayer: Player
): Double
{
val fromLocation = fromPlayer.location
val toLocation = toPlayer.location
val directionVector = Vector( toLocation.x - fromLocation.x, 0.0, toLocation.z - fromLocation.z ).normalize()
val angle = atan2( directionVector.x, directionVector.z )
val yaw = Math.toDegrees( angle )
var adjustedYaw = yaw + 180
if ( adjustedYaw < 0)
adjustedYaw += 360
return adjustedYaw
}
}

View File

@@ -54,14 +54,28 @@ game:
- 'lobby' - 'lobby'
- 'l' - 'l'
playerState: playerStates:
waiting: 'Waiting - %time%' waiting:
preStart: 'Waiting - %time%' scoreboard: 'Waiting - %time%'
immunity: 'Playing - %time%' duration: FIXED:-1
battle: 'Playing - %time%' preStart:
feast: 'Playing - %time%' scoreboard: 'Waiting - %time%'
deathmatch: 'Playing - %time%' duration: FIXED:300
end: 'Ending - %time%' immunity:
scoreboard: 'Playing - %time%'
duration: FIXED:90
battle:
scoreboard: 'Playing - %time%'
duration: INCREASING
feast:
scoreboard: 'Playing - %time%'
duration: FIXED:300
deathmatch:
scoreboard: 'Playing - %time%'
duration: INCREASING
end:
scoreboard: 'Ending - %time%'
duration: FIXED:60
recraftNerf: recraftNerf:
enabled: false enabled: false