mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
New game mode: LoopWanted (Cycle Hunt Order) (#631)
* Add new Gamemode and fix SettingMenu button order issue * back path
This commit is contained in:
1 parent
746c0f1e5d
commit
dd50ae4cae
22 files changed
+605
-15
No files matched your search
@@ -504,6 +504,9 @@ public enum CustomRoles
|
||||
// Snowdown
|
||||
SnowdownPlayer,
|
||||
|
||||
// LoopWanted
|
||||
LoopHunter,
|
||||
|
||||
// GM
|
||||
GM,
|
||||
|
||||
|
||||
@@ -504,6 +504,9 @@ public enum CustomRoles
|
||||
// Snowdown
|
||||
SnowdownPlayer,
|
||||
|
||||
// LoopWanted
|
||||
LoopHunter,
|
||||
|
||||
// GM
|
||||
GM,
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AmongUsPath>D:\SteamLibrary\steamapps\common\Among Us</AmongUsPath>
|
||||
<AmongUsPath>D:\SteamLibrary\steamapps\common\Among Us</AmongUsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="local.props" Condition="Exists('local.props')" />
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -0,0 +1,442 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using static EHR.Translator;
|
||||
|
||||
namespace EHR.Gamemodes;
|
||||
|
||||
internal static class LoopWanted
|
||||
{
|
||||
private static Dictionary<byte, byte> TargetMap = [];
|
||||
private static Dictionary<byte, long> LowerVisionList = [];
|
||||
private static bool CarnivalMode;
|
||||
private static float DefaultSpeed;
|
||||
|
||||
private static OptionItem BaseKillCooldown;
|
||||
private static OptionItem PunishmentMode;
|
||||
private static OptionItem LowerVisionMultiplier;
|
||||
private static OptionItem CarnivalPlayerCount;
|
||||
private static OptionItem CarnivalKillCooldown;
|
||||
private static OptionItem CarnivalSpeedMultiplier;
|
||||
private static OptionItem ShowTargetArrow;
|
||||
|
||||
private static readonly string[] PunishmentModeOptions = ["LoopWanted.PunishSuicide", "LoopWanted.PunishLowerVision"];
|
||||
|
||||
public static void SetupCustomOption()
|
||||
{
|
||||
var id = 69_226_001;
|
||||
Color color = new Color32(255, 180, 50, byte.MaxValue);
|
||||
const CustomGameMode gameMode = CustomGameMode.LoopWanted;
|
||||
const TabGroup tab = TabGroup.GameSettings;
|
||||
|
||||
BaseKillCooldown = new FloatOptionItem(id++, "LoopWanted.BaseKillCooldown", new(2.5f, 60f, 2.5f), 15f, tab)
|
||||
.SetHeader(true)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
|
||||
PunishmentMode = new StringOptionItem(id++, "LoopWanted.PunishmentMode", PunishmentModeOptions, 0, tab)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.RegisterUpdateValueEvent((_, _, currentValue) =>
|
||||
{
|
||||
LowerVisionMultiplier.SetHidden(currentValue != 1);
|
||||
})
|
||||
.SetRunEventOnLoad(true);
|
||||
|
||||
LowerVisionMultiplier = new FloatOptionItem(id++, "LoopWanted.LowerVisionMultiplier", new(0f, 10f, 0.5f), 0.5f, tab)
|
||||
.SetParent(PunishmentMode)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.SetValueFormat(OptionFormat.Multiplier);
|
||||
|
||||
CarnivalPlayerCount = new IntegerOptionItem(id++, "LoopWanted.CarnivalPlayerCount", new(1, 127, 1), 3, tab)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.SetValueFormat(OptionFormat.Players);
|
||||
|
||||
CarnivalKillCooldown = new FloatOptionItem(id++, "LoopWanted.CarnivalKillCooldown", new(2.5f, 60f, 2.5f), 5f, tab)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.SetValueFormat(OptionFormat.Seconds);
|
||||
|
||||
CarnivalSpeedMultiplier = new FloatOptionItem(id++, "LoopWanted.CarnivalSpeedMultiplier", new(0.25f, 10f, 0.25f), 2.0f, tab)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color)
|
||||
.SetValueFormat(OptionFormat.Multiplier);
|
||||
|
||||
ShowTargetArrow = new BooleanOptionItem(id++, "LoopWanted.ShowTargetArrow", false, tab)
|
||||
.SetGameMode(gameMode)
|
||||
.SetColor(color);
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (Options.CurrentGameMode != CustomGameMode.LoopWanted) return;
|
||||
|
||||
TargetMap = [];
|
||||
LowerVisionList = [];
|
||||
CarnivalMode = false;
|
||||
|
||||
DefaultSpeed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
|
||||
Utils.SendRPC(CustomRPC.LoopWantedSync, 1, false);
|
||||
}
|
||||
|
||||
public static void OnGameStart()
|
||||
{
|
||||
if (Options.CurrentGameMode != CustomGameMode.LoopWanted) return;
|
||||
AssignTargets();
|
||||
}
|
||||
|
||||
private static void AssignTargets()
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
TargetMap = [];
|
||||
TargetArrow.Init();
|
||||
|
||||
var allPlayers = Main.EnumerateAlivePlayerControls();
|
||||
if (Main.GM.Value)
|
||||
allPlayers = allPlayers.Without(PlayerControl.LocalPlayer);
|
||||
allPlayers = allPlayers.ExceptBy(ChatCommands.Spectators, x => x.PlayerId).ToArray();
|
||||
|
||||
List<byte> playerIds = allPlayers.Select(x => x.PlayerId).Shuffle().ToList();
|
||||
|
||||
if (playerIds.Count < 2)
|
||||
{
|
||||
Logger.Warn("Not enough players for LoopWanted", "LoopWanted");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < playerIds.Count; i++)
|
||||
{
|
||||
byte targetId = playerIds[(i + 1) % playerIds.Count];
|
||||
byte hunterId = playerIds[i];
|
||||
if (hunterId == targetId) continue; // should never happen, but guard
|
||||
if (TargetMap.ContainsValue(targetId))
|
||||
TargetMap.Remove(TargetMap.First(kv => kv.Value == targetId).Key);
|
||||
TargetMap[hunterId] = targetId;
|
||||
if (ShowTargetArrow.GetBool()) TargetArrow.Add(hunterId, targetId);
|
||||
Logger.Info($"{hunterId.ColoredPlayerName()} 2 targets 2 {targetId.ColoredPlayerName()}", "LoopWanted");
|
||||
}
|
||||
|
||||
SyncTargetMapRPC();
|
||||
CarnivalMode = false;
|
||||
}
|
||||
|
||||
public static byte GetTarget(byte playerId)
|
||||
{
|
||||
return TargetMap.TryGetValue(playerId, out byte target) ? target : byte.MaxValue;
|
||||
}
|
||||
|
||||
public static bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return false;
|
||||
|
||||
byte killerId = killer.PlayerId;
|
||||
byte targetId = target.PlayerId;
|
||||
|
||||
byte expectedTarget = GetTarget(killerId);
|
||||
|
||||
if (expectedTarget == targetId)
|
||||
{
|
||||
Logger.Info($"{killer.GetRealName()} correctly killed their target {target.GetRealName()}", "LoopWanted");
|
||||
|
||||
byte nextTarget = GetTarget(targetId);
|
||||
|
||||
TargetArrow.RemoveAllTarget(targetId);
|
||||
RemoveTargetArrowsTo(targetId);
|
||||
|
||||
if (nextTarget != byte.MaxValue && nextTarget != killerId)
|
||||
{
|
||||
if (TargetMap.ContainsValue(nextTarget))
|
||||
TargetMap.Remove(TargetMap.First(kv => kv.Value == nextTarget).Key);
|
||||
TargetMap[killerId] = nextTarget;
|
||||
if (ShowTargetArrow.GetBool()) TargetArrow.Add(killerId, nextTarget);
|
||||
Logger.Info($"{killer.GetRealName()}'s new target is {nextTarget.ColoredPlayerName()}", "LoopWanted");
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetMap.Remove(killerId);
|
||||
TargetArrow.RemoveAllTarget(killerId);
|
||||
}
|
||||
|
||||
TargetMap.Remove(targetId);
|
||||
|
||||
killer.SyncSettings();
|
||||
|
||||
CheckCarnivalMode();
|
||||
Utils.NotifyRoles(SpecifySeer: killer);
|
||||
|
||||
SyncTargetMapRPC();
|
||||
Utils.SendRPC(CustomRPC.LoopWantedSync, 1, CarnivalMode);
|
||||
|
||||
killer.Kill(target);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info($"{killer.GetRealName()} killed wrong target {target.GetRealName()} (expected: {expectedTarget.ColoredPlayerName()})", "LoopWanted");
|
||||
int punishment = PunishmentMode.GetInt();
|
||||
if (punishment == 0)
|
||||
{
|
||||
killer.Kill(target);
|
||||
ApplyPunishment(killer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyPunishment(killer);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveTargetArrowsTo(byte targetId)
|
||||
{
|
||||
foreach (var kvp in TargetMap)
|
||||
{
|
||||
if (kvp.Value == targetId)
|
||||
TargetArrow.RemoveAllTarget(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyPunishment(PlayerControl killer)
|
||||
{
|
||||
int punishment = PunishmentMode.GetInt();
|
||||
|
||||
switch (punishment)
|
||||
{
|
||||
case 0:
|
||||
Logger.Info($"{killer.GetRealName()} is committing suicide for wrong kill", "LoopWanted");
|
||||
killer.Notify(GetString("LoopWanted.WrongKillSuicide"), 5f);
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (!killer || !killer.IsAlive() || GameStates.IsEnded) return;
|
||||
killer.Suicide(PlayerState.DeathReason.Kill);
|
||||
HandleDeadPlayer(killer.PlayerId);
|
||||
}, 0.5f, "LoopWanted Suicide Punishment");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
float visionMultiplier = LowerVisionMultiplier.GetFloat();
|
||||
LowerVisionList[killer.PlayerId] = Utils.TimeStamp;
|
||||
killer.MarkDirtySettings();
|
||||
killer.Notify(string.Format(GetString("LoopWanted.WrongKillLowerVision"), visionMultiplier), 5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void HandleDeadPlayer(byte deadPlayerId)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (!TargetMap.ContainsKey(deadPlayerId)) return;
|
||||
|
||||
byte hunterId = byte.MaxValue;
|
||||
foreach (var kvp in TargetMap)
|
||||
{
|
||||
if (kvp.Value == deadPlayerId && kvp.Key != deadPlayerId)
|
||||
{
|
||||
hunterId = kvp.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte nextTarget = GetTarget(deadPlayerId);
|
||||
|
||||
TargetArrow.RemoveAllTarget(deadPlayerId);
|
||||
TargetMap.Remove(deadPlayerId);
|
||||
LowerVisionList.Remove(deadPlayerId);
|
||||
|
||||
if (hunterId != byte.MaxValue && nextTarget != byte.MaxValue && nextTarget != hunterId)
|
||||
{
|
||||
TargetArrow.RemoveAllTarget(hunterId);
|
||||
if (TargetMap.ContainsValue(nextTarget))
|
||||
TargetMap.Remove(TargetMap.First(kv => kv.Value == nextTarget).Key);
|
||||
TargetMap[hunterId] = nextTarget;
|
||||
if (ShowTargetArrow.GetBool()) TargetArrow.Add(hunterId, nextTarget);
|
||||
|
||||
PlayerControl hunter = Utils.GetPlayerById(hunterId);
|
||||
if (hunter) Utils.NotifyRoles(SpecifySeer: hunter);
|
||||
}
|
||||
else if (hunterId != byte.MaxValue)
|
||||
{
|
||||
TargetMap.Remove(hunterId);
|
||||
TargetArrow.RemoveAllTarget(hunterId);
|
||||
}
|
||||
|
||||
CheckCarnivalMode();
|
||||
SyncTargetMapRPC();
|
||||
}
|
||||
|
||||
private static void CheckCarnivalMode()
|
||||
{
|
||||
int aliveCount = Main.EnumerateAlivePlayerControls().Count(x => !ChatCommands.Spectators.Contains(x.PlayerId));
|
||||
int threshold = CarnivalPlayerCount.GetInt();
|
||||
|
||||
if (!CarnivalMode && aliveCount <= threshold && aliveCount > 1)
|
||||
{
|
||||
CarnivalMode = true;
|
||||
Utils.SendRPC(CustomRPC.LoopWantedSync, 1, true);
|
||||
|
||||
foreach (PlayerControl pc in Main.EnumerateAlivePlayerControls())
|
||||
{
|
||||
if (ChatCommands.Spectators.Contains(pc.PlayerId)) continue;
|
||||
|
||||
Main.AllPlayerSpeed[pc.PlayerId] = DefaultSpeed * CarnivalSpeedMultiplier.GetFloat();
|
||||
Main.AllPlayerKillCooldown[pc.PlayerId] = CarnivalKillCooldown.GetFloat();
|
||||
pc.SyncSettings();
|
||||
pc.MarkDirtySettings();
|
||||
pc.Notify(GetString("LoopWanted.CarnivalModeActivated"), 5f);
|
||||
}
|
||||
|
||||
SoundManager.Instance.PlaySound(HudManager.Instance.LobbyTimerExtensionUI.lobbyTimerPopUpSound, false);
|
||||
Utils.FlashColor(new(1f, 0.5f, 0f, 0.4f), 1.4f);
|
||||
Logger.Info($"Carnival Mode activated! {aliveCount} players remaining.", "LoopWanted");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckForGameEnd(out GameOverReason reason)
|
||||
{
|
||||
reason = GameOverReason.ImpostorsByKill;
|
||||
|
||||
if (!Main.IntroDestroyed || GameStates.IsEnded) return false;
|
||||
|
||||
var alivePlayers = Main.EnumerateAlivePlayerControls()
|
||||
.Where(x => !ChatCommands.Spectators.Contains(x.PlayerId)).ToArray();
|
||||
|
||||
if (alivePlayers.Length <= 1)
|
||||
{
|
||||
if (alivePlayers.Length == 1)
|
||||
{
|
||||
PlayerControl winner = alivePlayers[0];
|
||||
CustomWinnerHolder.WinnerIds = [winner.PlayerId];
|
||||
Logger.Info($"LoopWanted Winner: {winner.GetRealName()}", "LoopWanted");
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomWinnerHolder.WinnerIds = [];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false)
|
||||
{
|
||||
if (seer.PlayerId != target.PlayerId || GameStates.IsMeeting) return string.Empty;
|
||||
|
||||
byte targetId = GetTarget(seer.PlayerId);
|
||||
if (targetId == byte.MaxValue) return string.Empty;
|
||||
|
||||
string targetName = Main.AllPlayerNames.GetValueOrDefault(targetId, GetString("Unknown"));
|
||||
string arrow = ShowTargetArrow.GetBool() ? TargetArrow.GetArrows(seer, targetId) : string.Empty;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append($"<color=#ffb432>{(hud ? GetString("LoopWanted.CurrentTarget") : GetString("Target"))}:</color> <b>{targetName.RemoveHtmlTags().Replace("\r\n", string.Empty)}</b> {arrow}");
|
||||
|
||||
if (CarnivalMode)
|
||||
sb.Append($"\n<color=#ff6600>{GetString("LoopWanted.CarnivalModeHUD")}</color>");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void SyncTargetMapRPC()
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
var writer = Utils.CreateRPC(CustomRPC.LoopWantedSync);
|
||||
writer.Write(2);
|
||||
writer.Write(TargetMap.Count);
|
||||
foreach (var kvp in TargetMap)
|
||||
{
|
||||
writer.Write(kvp.Key);
|
||||
writer.Write(kvp.Value);
|
||||
}
|
||||
Utils.EndRPC(writer);
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
CarnivalMode = reader.ReadBoolean();
|
||||
break;
|
||||
case 2:
|
||||
TargetMap = [];
|
||||
int count = reader.ReadInt32();
|
||||
for (int i = 0; i < count; i++)
|
||||
TargetMap[reader.ReadByte()] = reader.ReadByte();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyGameOptions(IGameOptions opt, byte playerId)
|
||||
{
|
||||
AURoleOptions.PhantomCooldown = 0.1f;
|
||||
|
||||
try { AURoleOptions.GuardianAngelCooldown = 900f; }
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
if (LowerVisionList.ContainsKey(playerId))
|
||||
{
|
||||
opt.SetVision(false);
|
||||
opt.SetFloat(FloatOptionNames.CrewLightMod, LowerVisionMultiplier.GetFloat());
|
||||
opt.SetFloat(FloatOptionNames.ImpostorLightMod, LowerVisionMultiplier.GetFloat());
|
||||
}
|
||||
else
|
||||
{
|
||||
opt.SetVision(true);
|
||||
opt.SetFloat(FloatOptionNames.CrewLightMod, 1.3f);
|
||||
opt.SetFloat(FloatOptionNames.ImpostorLightMod, 1.3f);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FixedUpdatePatch
|
||||
{
|
||||
private static long LastFixedUpdate;
|
||||
|
||||
public static void Postfix()
|
||||
{
|
||||
if (!Main.IntroDestroyed || !GameStates.IsInTask || ExileController.Instance ||
|
||||
Options.CurrentGameMode != CustomGameMode.LoopWanted || !AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (IntroCutsceneDestroyPatch.IntroDestroyTS + 10 > now || LastFixedUpdate == now) return;
|
||||
LastFixedUpdate = now;
|
||||
|
||||
var deadPlayersInMap = new List<byte>();
|
||||
foreach (var kvp in TargetMap)
|
||||
{
|
||||
byte id = kvp.Key;
|
||||
if (id.GetPlayer()?.IsAlive() == true) continue;
|
||||
if (Main.PlayerStates.TryGetValue(id, out var state) && state.IsDead)
|
||||
deadPlayersInMap.Add(id);
|
||||
}
|
||||
foreach (byte deadId in deadPlayersInMap)
|
||||
HandleDeadPlayer(deadId);
|
||||
|
||||
var orphaned = new List<byte>();
|
||||
foreach (var kvp in TargetMap)
|
||||
{
|
||||
byte targetId = kvp.Value;
|
||||
var targetPlayer = targetId.GetPlayer();
|
||||
var state = Main.PlayerStates.GetValueOrDefault(targetId);
|
||||
if (targetPlayer && !targetPlayer.IsAlive() || (state != null && state.IsDead))
|
||||
orphaned.Add(kvp.Key);
|
||||
}
|
||||
foreach (byte hunterId in orphaned)
|
||||
HandleDeadPlayer(TargetMap[hunterId]);
|
||||
|
||||
CheckCarnivalMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,8 @@ public class Main : BasePlugin
|
||||
[CustomGameMode.Speedrun] = [],
|
||||
[CustomGameMode.CaptureTheFlag] = [],
|
||||
[CustomGameMode.NaturalDisasters] = [],
|
||||
[CustomGameMode.Snowdown] = []
|
||||
[CustomGameMode.Snowdown] = [],
|
||||
[CustomGameMode.LoopWanted] = []
|
||||
};
|
||||
|
||||
public static Dictionary<CustomGameMode, Color> GameModeColors = [];
|
||||
@@ -972,7 +973,8 @@ public class Main : BasePlugin
|
||||
[CustomGameMode.BedWars] = Utils.GetRoleColor(CustomRoles.BedWarsPlayer),
|
||||
[CustomGameMode.Deathrace] = Utils.GetRoleColor(CustomRoles.Racer),
|
||||
[CustomGameMode.Mingle] = Utils.GetRoleColor(CustomRoles.MinglePlayer),
|
||||
[CustomGameMode.Snowdown] = Utils.GetRoleColor(CustomRoles.SnowdownPlayer)
|
||||
[CustomGameMode.Snowdown] = Utils.GetRoleColor(CustomRoles.SnowdownPlayer),
|
||||
[CustomGameMode.LoopWanted] = Utils.GetRoleColor(CustomRoles.LoopHunter)
|
||||
};
|
||||
|
||||
IL2CPPChainloader.Instance.Finished += () =>
|
||||
|
||||
@@ -36,7 +36,8 @@ internal static class CustomRoleSelector
|
||||
{ CustomGameMode.BedWars, CustomRoles.BedWarsPlayer },
|
||||
{ CustomGameMode.Deathrace, CustomRoles.Racer },
|
||||
{ CustomGameMode.Mingle, CustomRoles.MinglePlayer },
|
||||
{ CustomGameMode.Snowdown, CustomRoles.SnowdownPlayer }
|
||||
{ CustomGameMode.Snowdown, CustomRoles.SnowdownPlayer },
|
||||
{ CustomGameMode.LoopWanted, CustomRoles.LoopHunter }
|
||||
};
|
||||
|
||||
public static void SelectCustomRoles()
|
||||
|
||||
@@ -74,7 +74,8 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.BedWarsPlayer or
|
||||
CustomRoles.Racer or
|
||||
CustomRoles.MinglePlayer or
|
||||
CustomRoles.SnowdownPlayer;
|
||||
CustomRoles.SnowdownPlayer or
|
||||
CustomRoles.LoopHunter;
|
||||
}
|
||||
|
||||
public RoleBase GetRoleClass()
|
||||
@@ -434,6 +435,8 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.TMGPlayer => CustomRoles.Crewmate,
|
||||
// Mingle
|
||||
CustomRoles.MinglePlayer => CustomRoles.Crewmate,
|
||||
// LoopWanted
|
||||
CustomRoles.LoopHunter => CustomRoles.Impostor,
|
||||
|
||||
_ => role.IsImpostor() ? CustomRoles.Impostor : CustomRoles.Crewmate
|
||||
};
|
||||
@@ -486,6 +489,8 @@ internal static class CustomRolesHelper
|
||||
CustomRoles.Racer => RoleTypes.Phantom,
|
||||
// Snowdown
|
||||
CustomRoles.SnowdownPlayer => RoleTypes.Phantom,
|
||||
// LoopWanted
|
||||
CustomRoles.LoopHunter => RoleTypes.Impostor,
|
||||
// Standard
|
||||
CustomRoles.Sheriff => UsePets && Sheriff.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
|
||||
CustomRoles.Crusader => UsePets && Crusader.UsePet.GetBool() ? RoleTypes.GuardianAngel : RoleTypes.Impostor,
|
||||
|
||||
@@ -373,7 +373,7 @@ internal static class ExtendedPlayerControl
|
||||
RoleTypes newRoleType = state.MainRole.GetRoleTypes();
|
||||
CustomGameMode gameMode = Options.CurrentGameMode;
|
||||
|
||||
if (gameMode is CustomGameMode.SoloPVP or CustomGameMode.FFA or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones or CustomGameMode.BedWars or CustomGameMode.Snowdown)
|
||||
if (gameMode is CustomGameMode.SoloPVP or CustomGameMode.FFA or CustomGameMode.CaptureTheFlag or CustomGameMode.KingOfTheZones or CustomGameMode.BedWars or CustomGameMode.Snowdown or CustomGameMode.LoopWanted)
|
||||
hasValue |= sender.RpcSetRole(player, newRoleType, player.OwnerId);
|
||||
|
||||
player.ResetKillCooldown();
|
||||
@@ -1338,6 +1338,7 @@ internal static class ExtendedPlayerControl
|
||||
case CustomGameMode.BedWars:
|
||||
case CustomGameMode.Deathrace:
|
||||
case CustomGameMode.Snowdown:
|
||||
case CustomGameMode.LoopWanted:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1398,6 +1399,7 @@ internal static class ExtendedPlayerControl
|
||||
CustomGameMode.TheMindGame => false,
|
||||
CustomGameMode.Mingle => false,
|
||||
CustomGameMode.Snowdown => true,
|
||||
CustomGameMode.LoopWanted => false,
|
||||
CustomGameMode.Deathrace => Deathrace.CanUseVent(player, player.GetClosestVent().Id),
|
||||
|
||||
CustomGameMode.Standard when CopyCat.PlayerIdList.Contains(player.PlayerId) => true,
|
||||
@@ -1783,6 +1785,7 @@ internal static class ExtendedPlayerControl
|
||||
CustomRoles.BedWarsPlayer => 1f,
|
||||
CustomRoles.Racer => 3f,
|
||||
CustomRoles.SnowdownPlayer => 10f,
|
||||
CustomRoles.LoopHunter => Main.AllPlayerKillCooldown[player.PlayerId],
|
||||
_ when player.Is(CustomRoles.Underdog) => Main.AllAlivePlayerControlsCount <= Underdog.UnderdogMaximumPlayersNeededToKill.GetInt() ? Underdog.UnderdogKillCooldownWithLessPlayersAlive.GetInt() : Underdog.UnderdogKillCooldownWithMorePlayersAlive.GetInt(),
|
||||
_ => Main.AllPlayerKillCooldown[player.PlayerId]
|
||||
};
|
||||
|
||||
@@ -162,6 +162,9 @@ public static class FixedUpdateCaller
|
||||
case CustomGameMode.Snowdown:
|
||||
Snowdown.FixedUpdatePatch.Postfix(pc);
|
||||
break;
|
||||
case CustomGameMode.LoopWanted:
|
||||
LoopWanted.FixedUpdatePatch.Postfix();
|
||||
break;
|
||||
}
|
||||
|
||||
CheckInvalidMovementPatch.Postfix(pc);
|
||||
|
||||
@@ -389,6 +389,11 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
Snowdown.ApplyGameOptions();
|
||||
goto case CustomGameMode.RoomRush;
|
||||
}
|
||||
case CustomGameMode.LoopWanted:
|
||||
{
|
||||
LoopWanted.ApplyGameOptions(opt, player.PlayerId);
|
||||
break;
|
||||
}
|
||||
case CustomGameMode.NaturalDisasters:
|
||||
{
|
||||
SetMaxVision();
|
||||
|
||||
@@ -43,6 +43,7 @@ public static class NameColorManager
|
||||
color = FreeForAll.TeamColors.GetValueOrDefault(team, "#00ffff");
|
||||
return true;
|
||||
case CustomGameMode.Snowdown:
|
||||
case CustomGameMode.LoopWanted:
|
||||
case CustomGameMode.Mingle:
|
||||
case CustomGameMode.RoomRush:
|
||||
case CustomGameMode.NaturalDisasters:
|
||||
|
||||
@@ -35,6 +35,7 @@ public enum CustomGameMode
|
||||
Deathrace = 0x0F,
|
||||
Mingle = 0x10,
|
||||
Snowdown = 0x11,
|
||||
LoopWanted = 0x12,
|
||||
All = int.MaxValue
|
||||
}
|
||||
|
||||
@@ -89,7 +90,8 @@ public static class Options
|
||||
"BedWars",
|
||||
"Deathrace",
|
||||
"Mingle",
|
||||
"Snowdown"
|
||||
"Snowdown",
|
||||
"LoopWanted"
|
||||
];
|
||||
|
||||
private static Dictionary<CustomRoles, int> roleCounts;
|
||||
@@ -928,6 +930,7 @@ public static class Options
|
||||
14 => CustomGameMode.Deathrace,
|
||||
15 => CustomGameMode.Mingle,
|
||||
16 => CustomGameMode.Snowdown,
|
||||
17 => CustomGameMode.LoopWanted,
|
||||
_ => CustomGameMode.Standard
|
||||
};
|
||||
|
||||
@@ -1854,6 +1857,8 @@ public static class Options
|
||||
Mingle.SetupCustomOption();
|
||||
// Snowdown
|
||||
Snowdown.SetupCustomOption();
|
||||
// LoopWanted
|
||||
LoopWanted.SetupCustomOption();
|
||||
|
||||
yield return null;
|
||||
|
||||
|
||||
+7
-1
@@ -179,7 +179,8 @@ public enum CustomRPC
|
||||
NaturalDisastersSync,
|
||||
TMGSync,
|
||||
BedWarsSync,
|
||||
DeathraceSync
|
||||
DeathraceSync,
|
||||
LoopWantedSync
|
||||
|
||||
// The total number of RPCs must not exceed 255
|
||||
// Because HandleRpc accepts Rpc in byte (max 255) system, and it will be impossible to use int
|
||||
@@ -1274,6 +1275,11 @@ internal static class RPCHandlerPatch
|
||||
|
||||
break;
|
||||
}
|
||||
case CustomRPC.LoopWantedSync:
|
||||
{
|
||||
LoopWanted.ReceiveRPC(reader);
|
||||
break;
|
||||
}
|
||||
case CustomRPC.InspectorCommand:
|
||||
{
|
||||
Inspector.ReceiveRPC(reader);
|
||||
|
||||
+12
-2
@@ -850,6 +850,7 @@ public static class Utils
|
||||
case CustomGameMode.Deathrace:
|
||||
case CustomGameMode.Mingle:
|
||||
case CustomGameMode.Snowdown:
|
||||
case CustomGameMode.LoopWanted:
|
||||
return false;
|
||||
case CustomGameMode.HideAndSeek:
|
||||
return CustomHnS.HasTasks(p);
|
||||
@@ -1517,6 +1518,7 @@ public static class Utils
|
||||
|
||||
break;
|
||||
case CustomGameMode.Snowdown:
|
||||
case CustomGameMode.LoopWanted:
|
||||
case CustomGameMode.Mingle:
|
||||
case CustomGameMode.Deathrace:
|
||||
case CustomGameMode.BedWars:
|
||||
@@ -2545,6 +2547,7 @@ public static class Utils
|
||||
CustomGameMode.Deathrace => CustomRoles.Racer.ColoredTextByRole($"{modeText}\r\n") + name,
|
||||
CustomGameMode.Mingle => CustomRoles.MinglePlayer.ColoredTextByRole($"{modeText}\r\n") + name,
|
||||
CustomGameMode.Snowdown => CustomRoles.SnowdownPlayer.ColoredTextByRole($"{modeText}\r\n") + name,
|
||||
CustomGameMode.LoopWanted => name,
|
||||
_ => name
|
||||
};
|
||||
}
|
||||
@@ -3043,6 +3046,9 @@ public static class Utils
|
||||
case CustomGameMode.Snowdown:
|
||||
AdditionalSuffixes.Add(Snowdown.GetSuffix(seer, seer));
|
||||
break;
|
||||
case CustomGameMode.LoopWanted:
|
||||
AdditionalSuffixes.Add(LoopWanted.GetSuffix(seer, seer));
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = AdditionalSuffixes.Count - 1; i >= 0; i--)
|
||||
@@ -3110,7 +3116,7 @@ public static class Utils
|
||||
SelfSuffix.Append($"\n\n<#ffffff>{GetString($"GameModeTutorial.{Options.CurrentGameMode}")}</color>\n");
|
||||
}
|
||||
|
||||
bool noRoleText = GameStates.IsLobby || Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown;
|
||||
bool noRoleText = GameStates.IsLobby || Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown or CustomGameMode.LoopWanted;
|
||||
|
||||
// Combine the seer's job title and SelfTaskText with the seer's player name and SelfMark
|
||||
string selfRoleName = noRoleText ? string.Empty : $"<size={fontSize}>{seer.GetDisplayRoleName()}{selfTaskText}</size>";
|
||||
@@ -3309,7 +3315,7 @@ public static class Utils
|
||||
if (IsRevivingRoleAlive() && Main.DiedThisRound.Contains(seer.PlayerId))
|
||||
targetRoleText = string.Empty;
|
||||
|
||||
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown)
|
||||
if (Options.CurrentGameMode is CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown or CustomGameMode.LoopWanted)
|
||||
targetRoleText = string.Empty;
|
||||
|
||||
if (!GameStates.IsLobby)
|
||||
@@ -3434,6 +3440,9 @@ public static class Utils
|
||||
case CustomGameMode.Snowdown:
|
||||
AdditionalSuffixes.Add(Snowdown.GetSuffix(seer, target));
|
||||
break;
|
||||
case CustomGameMode.LoopWanted when seer == target:
|
||||
AdditionalSuffixes.Add(LoopWanted.GetSuffix(seer, target));
|
||||
break;
|
||||
}
|
||||
|
||||
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrWhiteSpace(target.FriendCode) && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.FFA or CustomGameMode.Speedrun)
|
||||
@@ -3645,6 +3654,7 @@ public static class Utils
|
||||
case CustomGameMode.Deathrace:
|
||||
case CustomGameMode.Mingle:
|
||||
case CustomGameMode.Snowdown:
|
||||
case CustomGameMode.LoopWanted:
|
||||
return local.Is(CustomRoles.GM);
|
||||
|
||||
case CustomGameMode.Standard:
|
||||
|
||||
@@ -606,6 +606,11 @@ internal static class GameEndChecker
|
||||
Predicate = new SnowdownGameEndPredicate();
|
||||
}
|
||||
|
||||
public static void SetPredicateToLoopWanted()
|
||||
{
|
||||
Predicate = new LoopWantedGameEndPredicate();
|
||||
}
|
||||
|
||||
private class NormalGameEndPredicate : GameEndPredicate
|
||||
{
|
||||
public override bool CheckForGameEnd(out GameOverReason reason)
|
||||
@@ -1382,6 +1387,20 @@ internal static class GameEndChecker
|
||||
}
|
||||
}
|
||||
|
||||
private class LoopWantedGameEndPredicate : GameEndPredicate
|
||||
{
|
||||
public override bool CheckForGameEnd(out GameOverReason reason)
|
||||
{
|
||||
reason = GameOverReason.ImpostorsByKill;
|
||||
return WinnerIds.Count <= 0 && CheckGameEndByLivingPlayers(out reason);
|
||||
}
|
||||
|
||||
private static bool CheckGameEndByLivingPlayers(out GameOverReason reason)
|
||||
{
|
||||
return LoopWanted.CheckForGameEnd(out reason);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class GameEndPredicate
|
||||
{
|
||||
/// <summary>Checks the game ending condition and stores the value in CustomWinnerHolder. </summary>
|
||||
|
||||
@@ -1216,7 +1216,8 @@ public static class GameSettingMenuPatch
|
||||
gms.Remove(CustomGameMode.Deathrace);
|
||||
}
|
||||
|
||||
const int totalCols = 3;
|
||||
const int totalCols = 2;
|
||||
int itemsPerCol = Mathf.CeilToInt(gms.Count / (float)totalCols);
|
||||
|
||||
GMButtons.Clear();
|
||||
|
||||
@@ -1231,8 +1232,8 @@ public static class GameSettingMenuPatch
|
||||
gmButton.transform.SetParent(gameSettingsLabel.transform, false);
|
||||
gmButton.SetActive(true);
|
||||
}
|
||||
gmButton.transform.localPosition = new Vector3((((index / 8) - ((totalCols - 1) / 2f)) * 1.4f) + 0.86f, gameSettingsLabelPos.y - 1.9f - (0.22f * (index % 8)), -1f);
|
||||
gmButton.transform.localScale = new(0.4f, 0.3f, 1f);
|
||||
gmButton.transform.localPosition = new Vector3((((index / itemsPerCol) - ((totalCols - 1) / 2f)) * 1.4f) + 0.16f, gameSettingsLabelPos.y - 1.9f - (0.17f * (index % itemsPerCol)), -1f);
|
||||
gmButton.transform.localScale = new(0.35f, 0.22f, 1f);
|
||||
var gmButtonTmp = gmButton.transform.Find("FontPlacer/Text_TMP").GetComponent<TextMeshPro>();
|
||||
gmButtonTmp.alignment = TextAlignmentOptions.Center;
|
||||
gmButtonTmp.DestroyTranslator();
|
||||
|
||||
@@ -310,6 +310,16 @@ internal static class SetUpRoleTextPatch
|
||||
__instance.RoleBlurbText.text = GetString("SnowdownPlayerInfo");
|
||||
break;
|
||||
}
|
||||
case CustomGameMode.LoopWanted:
|
||||
{
|
||||
Color color = Utils.GetRoleColor(CustomRoles.LoopHunter);
|
||||
__instance.YouAreText.transform.gameObject.SetActive(false);
|
||||
__instance.RoleText.text = GetString("LoopHunter");
|
||||
__instance.RoleText.color = color;
|
||||
__instance.RoleBlurbText.color = color;
|
||||
__instance.RoleBlurbText.text = GetString("LoopHunterInfo");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
CustomRoles role = lp.GetCustomRole();
|
||||
@@ -1017,6 +1027,15 @@ internal static class BeginCrewmatePatch
|
||||
__instance.ImpostorText.text = GetString("SnowdownPlayerInfo");
|
||||
break;
|
||||
}
|
||||
case CustomGameMode.LoopWanted:
|
||||
{
|
||||
__instance.TeamTitle.text = GetString("LoopHunter");
|
||||
__instance.TeamTitle.color = __instance.BackgroundBar.material.color = Utils.GetRoleColor(CustomRoles.LoopHunter);
|
||||
PlayerControl.LocalPlayer.Data.Role.IntroSound = GetIntroSound(RoleTypes.Impostor);
|
||||
__instance.ImpostorText.gameObject.SetActive(true);
|
||||
__instance.ImpostorText.text = GetString("LoopHunterInfo");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1362,6 +1381,9 @@ internal static class IntroCutsceneDestroyPatch
|
||||
case CustomGameMode.Snowdown:
|
||||
Snowdown.GameStart();
|
||||
break;
|
||||
case CustomGameMode.LoopWanted:
|
||||
LoopWanted.OnGameStart();
|
||||
break;
|
||||
}
|
||||
|
||||
if (AFKDetector.ActivateOnStart.GetBool()) LateTask.New(() => aapc.Do(AFKDetector.RecordPosition), 1f, log: false);
|
||||
|
||||
@@ -316,6 +316,7 @@ internal static class ChangeRoleSettings
|
||||
HotPotato.Init();
|
||||
CustomHnS.Init();
|
||||
Speedrun.Init();
|
||||
LoopWanted.Init();
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
@@ -951,6 +952,9 @@ internal static class StartGameHostPatch
|
||||
case CustomGameMode.Snowdown:
|
||||
Snowdown.Init();
|
||||
goto default;
|
||||
case CustomGameMode.LoopWanted:
|
||||
LoopWanted.OnGameStart();
|
||||
goto default;
|
||||
default:
|
||||
if (Options.IntegrateNaturalDisasters.GetBool()) goto case CustomGameMode.NaturalDisasters;
|
||||
break;
|
||||
@@ -1023,6 +1027,9 @@ internal static class StartGameHostPatch
|
||||
case CustomGameMode.Snowdown:
|
||||
GameEndChecker.SetPredicateToSnowdown();
|
||||
break;
|
||||
case CustomGameMode.LoopWanted:
|
||||
GameEndChecker.SetPredicateToLoopWanted();
|
||||
break;
|
||||
}
|
||||
|
||||
// Add players with unclassified roles to the list of players who require ResetCam.
|
||||
|
||||
@@ -67,7 +67,7 @@ internal static class EndGamePatch
|
||||
long secondsIn = new DateTimeOffset(date.ToUniversalTime()).ToUnixTimeSeconds() - IntroCutsceneDestroyPatch.IntroDestroyTS;
|
||||
byte killerId = value.GetRealKiller();
|
||||
bool gmIsFm = Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.StopAndGo;
|
||||
bool gmIsFmhh = gmIsFm || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown;
|
||||
bool gmIsFmhh = gmIsFm || Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.HideAndSeek or CustomGameMode.Speedrun or CustomGameMode.CaptureTheFlag or CustomGameMode.NaturalDisasters or CustomGameMode.RoomRush or CustomGameMode.KingOfTheZones or CustomGameMode.Quiz or CustomGameMode.TheMindGame or CustomGameMode.BedWars or CustomGameMode.Deathrace or CustomGameMode.Mingle or CustomGameMode.Snowdown or CustomGameMode.LoopWanted;
|
||||
sb.Append($"\n{secondsIn / 60:00}:{secondsIn % 60:00} {Main.AllPlayerNames[key]} ({(gmIsFmhh ? string.Empty : Utils.GetDisplayRoleName(key, pure: true))}{(gmIsFm ? string.Empty : Utils.GetSubRolesText(key, summary: true))}) [{Utils.GetVitalText(key)}]");
|
||||
if (killerId != byte.MaxValue && killerId != key) sb.Append($"\n\t⇐ {Main.AllPlayerNames[killerId]} ({(gmIsFmhh ? string.Empty : Utils.GetDisplayRoleName(killerId, pure: true))}{(gmIsFm ? string.Empty : Utils.GetSubRolesText(killerId, summary: true))})");
|
||||
}
|
||||
@@ -601,6 +601,7 @@ internal static class SetEverythingUpPatch
|
||||
case CustomGameMode.Deathrace:
|
||||
case CustomGameMode.BedWars:
|
||||
case CustomGameMode.Quiz:
|
||||
case CustomGameMode.LoopWanted:
|
||||
{
|
||||
foreach (byte id in cloneRoles.Where(EndGamePatch.SummaryText.ContainsKey))
|
||||
sb.Append('\n').Append(EndGamePatch.SummaryText[id]);
|
||||
|
||||
@@ -258,8 +258,11 @@ internal static class CheckMurderPatch
|
||||
case CustomGameMode.Snowdown:
|
||||
Snowdown.OnCheckMurder(killer, target);
|
||||
return false;
|
||||
case CustomGameMode.LoopWanted:
|
||||
LoopWanted.OnCheckMurder(killer, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
PlagueBearer.CheckAndSpreadInfection(killer, target);
|
||||
PlagueBearer.CheckAndSpreadInfection(target, killer);
|
||||
|
||||
@@ -2128,6 +2131,9 @@ internal static class FixedUpdatePatch
|
||||
case CustomGameMode.Snowdown:
|
||||
AdditionalSuffixes.Add(Snowdown.GetSuffix(seer, target));
|
||||
break;
|
||||
case CustomGameMode.LoopWanted when self:
|
||||
AdditionalSuffixes.Add(LoopWanted.GetSuffix(seer, target, false));
|
||||
break;
|
||||
}
|
||||
|
||||
if (MeetingStates.FirstMeeting && Main.ShieldPlayer == target.FriendCode && !string.IsNullOrWhiteSpace(target.FriendCode) && !self && Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.SoloPVP or CustomGameMode.FFA)
|
||||
@@ -2309,6 +2315,7 @@ internal static class EnterVentPatch
|
||||
case CustomGameMode.TheMindGame:
|
||||
case CustomGameMode.Quiz:
|
||||
case CustomGameMode.SoloPVP when !SoloPVP.CanVent:
|
||||
case CustomGameMode.LoopWanted:
|
||||
pc.MyPhysics?.RpcBootFromVent(__instance.Id);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4112,6 +4112,9 @@
|
||||
"SnowdownPlayer": "SNOWDOWN",
|
||||
"SnowdownPlayerInfo": "THROW SNOWBALLS AT PLAYERS",
|
||||
"SnowdownPlayerInfoLong": "THROW SNOWBALLS AT PLAYERS",
|
||||
"LoopHunter": "LOOP HUNTER",
|
||||
"LoopHunterInfo": "KILL YOUR ASSIGNED TARGET AND SURVIVE",
|
||||
"LoopHunterInfoLong": "KILL YOUR ASSIGNED TARGET AND SURVIVE",
|
||||
"TMGPlayer": "THE MIND GAME",
|
||||
"TMGPlayerInfo": "THINK WITH OTHERS' BRAINS TO WIN",
|
||||
"TMGPlayerInfoLong": "THINK WITH OTHERS' BRAINS TO WIN",
|
||||
@@ -8188,6 +8191,25 @@
|
||||
"Snowdown.SnowballGainFrequencyOption": "Initial Snowball Gaining Frequency",
|
||||
"Snowdown.SnowballThrowSpeedOption": "Snowball Throwing Speed",
|
||||
"SnowdownButtonText": "THROW",
|
||||
// LoopWanted - Cycle Hunt Order
|
||||
"LoopWanted": "LOOP WANTED",
|
||||
"ModeLoopWanted": "Gamemode: Loop Wanted",
|
||||
"ModeDescribe.LoopWanted": "In the Loop Wanted gamemode, every player has an assigned assassination target marked with an arrow. You can ONLY kill your designated target. Killing the wrong target results in a punishment (suicide / increased cooldown / lower vision). When you kill your target, you inherit their target. When only a few players remain, Carnival Mode activates — everyone gets a speed boost and reduced kill cooldown. Last player alive wins!",
|
||||
"GameModeTutorial.LoopWanted": "<size=90%>The current game mode is <#ffb432>Loop Wanted</color>.</size>\\n<size=80%>Each player has a target marked with an arrow.\\nYou can ONLY kill your target.\\nKilling the wrong target will punish you.\\nYour target transfers when you kill correctly.\\nCarnival mode activates when few remain!</size>",
|
||||
"LoopWanted.BaseKillCooldown": "Base Kill Cooldown",
|
||||
"LoopWanted.PunishmentMode": "Wrong Kill Punishment",
|
||||
"LoopWanted.PunishSuicide": "Suicide",
|
||||
"LoopWanted.PunishLowerVision": "Lower Vision",
|
||||
"LoopWanted.LowerVisionMultiplier": "Lowered Vision Multiplier",
|
||||
"LoopWanted.CarnivalPlayerCount": "Players to Trigger Carnival Mode",
|
||||
"LoopWanted.CarnivalKillCooldown": "Carnival Mode Kill Cooldown",
|
||||
"LoopWanted.CarnivalSpeedMultiplier": "Carnival Mode Speed Multiplier",
|
||||
"LoopWanted.ShowTargetArrow": "Show Target Arrow",
|
||||
"LoopWanted.CurrentTarget": "Current Target",
|
||||
"LoopWanted.CarnivalModeActivated": "<color=#ff6600>Carnival Mode! Speed up and kill faster!</color>",
|
||||
"LoopWanted.CarnivalModeHUD": "CARNIVAL",
|
||||
"LoopWanted.WrongKillSuicide": "<color=#ff0000>Wrong target! You committed suicide.</color>",
|
||||
"LoopWanted.WrongKillLowerVision": "<color=#ff0000>Wrong target! Your vision has been reduced.</color>",
|
||||
// SoloPVP
|
||||
"SoloPVP": "SOLO PVP",
|
||||
"ModeSoloPVP": "Gamemode: Solo PVP",
|
||||
|
||||
@@ -4111,6 +4111,9 @@
|
||||
"SnowdownPlayer": "大雪纷飞",
|
||||
"SnowdownPlayerInfo": "吃我一记雪球",
|
||||
"SnowdownPlayerInfoLong": "吃我一记雪球",
|
||||
"LoopHunter": "循环追猎者",
|
||||
"LoopHunterInfo": "追杀你的指定目标并活到最后",
|
||||
"LoopHunterInfoLong": "追杀你的指定目标并活到最后",
|
||||
"TMGPlayer": "心理游戏",
|
||||
"TMGPlayerInfo": "THINK WITH OTHERS' BRAINS TO WIN",
|
||||
"TMGPlayerInfoLong": "THINK WITH OTHERS' BRAINS TO WIN",
|
||||
@@ -8187,6 +8190,25 @@
|
||||
"Snowdown.SnowballGainFrequencyOption": "初始雪球获取频率",
|
||||
"Snowdown.SnowballThrowSpeedOption": "丢雪球的速度",
|
||||
"SnowdownButtonText": "丢",
|
||||
// LoopWanted - 循环追捕令
|
||||
"LoopWanted": "循环追捕令",
|
||||
"ModeLoopWanted": "游戏模式:循环追捕令",
|
||||
"ModeDescribe.LoopWanted": "在循环追捕令游戏模式中,每个玩家都有一个带有箭头的追杀目标。你只能击杀你被指定的目标。击杀错误目标会受到惩罚(自杀 / 冷却增加 / 视野降低)。当你击杀目标后,目标的追杀对象将转移到你身上。当剩余人数足够少时,将进入狂欢状态——全员加速且击杀冷却减少。活到最后的人获胜!",
|
||||
"GameModeTutorial.LoopWanted": "<size=90%>当前游戏模式为:<#ffb432>循环追捕令</color>。</size>\\n<size=80%>每个玩家都有一个带箭头的追杀目标。\\n你只能击杀你所指定目标!\\n击杀错误目标会受到惩罚。\\n击杀正确目标后目标转移。\\n剩余人数过少时将进入狂欢状态!</size>",
|
||||
"LoopWanted.BaseKillCooldown": "基础击杀冷却",
|
||||
"LoopWanted.PunishmentMode": "击杀错误后的惩罚",
|
||||
"LoopWanted.PunishSuicide": "自杀",
|
||||
"LoopWanted.PunishLowerVision": "视野降低",
|
||||
"LoopWanted.LowerVisionMultiplier": "降低视野倍率",
|
||||
"LoopWanted.CarnivalPlayerCount": "进入狂欢模式的人数",
|
||||
"LoopWanted.CarnivalKillCooldown": "狂欢状态击杀冷却",
|
||||
"LoopWanted.CarnivalSpeedMultiplier": "狂欢状态下加速倍率",
|
||||
"LoopWanted.ShowTargetArrow": "显示目标箭头",
|
||||
"LoopWanted.CurrentTarget": "当前目标",
|
||||
"LoopWanted.CarnivalModeActivated": "<color=#ff6600>进入狂欢状态!全速前进,击杀加速!</color>",
|
||||
"LoopWanted.CarnivalModeHUD": "狂欢中",
|
||||
"LoopWanted.WrongKillSuicide": "<color=#ff0000>目标是错误的!你自杀了。</color>",
|
||||
"LoopWanted.WrongKillLowerVision": "<color=#ff0000>目标是错误的!你的视野降低了。</color>",
|
||||
// SoloPVP
|
||||
"SoloPVP": "角逐竞技",
|
||||
"ModeSoloPVP": "游戏模式:角逐竞技",
|
||||
|
||||
Reference in new issue
Block a user