diff --git a/CPUAffinityEditor/obj/Debug/CPUAffinityEditor.csproj.AssemblyReference.cache b/CPUAffinityEditor/obj/Debug/CPUAffinityEditor.csproj.AssemblyReference.cache index 2c718317..442efad4 100644 Binary files a/CPUAffinityEditor/obj/Debug/CPUAffinityEditor.csproj.AssemblyReference.cache and b/CPUAffinityEditor/obj/Debug/CPUAffinityEditor.csproj.AssemblyReference.cache differ diff --git a/CPUAffinityEditor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/CPUAffinityEditor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache index f7575e21..8be17816 100644 Binary files a/CPUAffinityEditor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache and b/CPUAffinityEditor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ diff --git a/Nebula.dll b/Nebula.dll new file mode 100644 index 00000000..b35af1f6 Binary files /dev/null and b/Nebula.dll differ diff --git a/Nebula.sln b/Nebula.sln index 017c533a..fa154d4e 100644 --- a/Nebula.sln +++ b/Nebula.sln @@ -2,8 +2,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33110.190 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaPlugin", "Nebula\NebulaPlugin.csproj", "{A700F889-7DDD-40BD-8375-1145CA84AA78}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPUAffinityEditor", "CPUAffinityEditor\CPUAffinityEditor.csproj", "{BAB59E0C-F39B-4DC5-8C3F-0519DE5BB418}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NebulaPluginNova", "NebulaPluginNova\NebulaPluginNova.csproj", "{2412DC6B-C621-45B1-AB38-DDD784712818}" @@ -18,18 +16,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|x64.ActiveCfg = Debug|x64 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|x64.Build.0 = Debug|x64 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|x86.ActiveCfg = Debug|x86 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Debug|x86.Build.0 = Debug|x86 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|Any CPU.Build.0 = Release|Any CPU - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|x64.ActiveCfg = Release|x64 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|x64.Build.0 = Release|x64 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|x86.ActiveCfg = Release|x86 - {A700F889-7DDD-40BD-8375-1145CA84AA78}.Release|x86.Build.0 = Release|x86 {BAB59E0C-F39B-4DC5-8C3F-0519DE5BB418}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BAB59E0C-F39B-4DC5-8C3F-0519DE5BB418}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAB59E0C-F39B-4DC5-8C3F-0519DE5BB418}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/NebulaPluginNova/Modules/ModUpdater.cs b/NebulaPluginNova/Modules/ModUpdater.cs index d6078c2e..739b3736 100644 --- a/NebulaPluginNova/Modules/ModUpdater.cs +++ b/NebulaPluginNova/Modules/ModUpdater.cs @@ -92,7 +92,8 @@ public ReleasedInfo(string tag) private async Task UpdateAsync() { - string url = $"https://github.com/Dolly1016/Nebula/releases/download/{rawTag}/Nebula.dll"; + string url = $"https://gh-proxy.com/https://github.com/ZsFabTest/Nebula-Public/releases/download/{rawTag}/Nebula.dll"; + //https://gh-proxy.com/https://github.com/Dolly1016/Nebula/releases/download/s%2CSnapshot_23.11.02a%2C101%2C1043/Nebula.dll var response = await NebulaPlugin.HttpClient.GetAsync(url); if (response.StatusCode != HttpStatusCode.OK) return; var dllStream = await response.Content.ReadAsStreamAsync(); @@ -122,7 +123,7 @@ public IEnumerator CoUpdateAndShowDialog() } } - static string GetTagsUrl(int page) => "https://api.github.com/repos/Dolly1016/Nebula/tags?per_page=100&page=" + (page); + static string GetTagsUrl(int page) => "https://api.github.com/repos/ZsFabTest/Nebula-public/tags?per_page=100&page=" + (page); private static async Task FetchAsync() { List releases = new(); diff --git a/NebulaPluginNova/Nebula.cs b/NebulaPluginNova/Nebula.cs index e3098042..13904076 100644 --- a/NebulaPluginNova/Nebula.cs +++ b/NebulaPluginNova/Nebula.cs @@ -56,16 +56,16 @@ public class NebulaPlugin : BasePlugin { public const string AmongUsVersion = "2023.7.12"; public const string PluginGuid = "jp.dreamingpig.amongus.nebula"; - public const string PluginName = "NebulaOnTheShip"; - public const string PluginVersion = "2.0.0"; + public const string PluginName = "NebulaOnTheShip-Remake"; + public const string PluginVersion = "1.1.0.0"; public const bool IsSnapshot = false; //public const string VisualVersion = "v2.0"; - public const string VisualVersion = "Snapshot 23.11.02a"; + public const string VisualVersion = "Test Build 16"; //public const string VisualVersion = "Mayor Debug"; - public const int PluginEpoch = 101; - public const int PluginBuildNum = 1043; + public const int PluginEpoch = 100; + public const int PluginBuildNum = 1006; static public HttpClient HttpClient { @@ -87,7 +87,7 @@ static public HttpClient HttpClient public static string GetNebulaVersionString() { - return "NoS " + VisualVersion; + return "NoS-R " + VisualVersion; } public Harmony Harmony = new Harmony(PluginGuid); @@ -192,7 +192,7 @@ override public void Load() Harmony.PatchAll(); - SetWindowText(FindWindow(null!, Application.productName),"Among Us w/ " + GetNebulaVersionString()); + SetWindowText(FindWindow(null!, Application.productName),"Among Us " + GetNebulaVersionString()); SceneManager.sceneLoaded += (UnityEngine.Events.UnityAction)((scene, loadMode) => { diff --git a/NebulaPluginNova/NebulaPluginNova.csproj b/NebulaPluginNova/NebulaPluginNova.csproj index 3c086493..d0dca0c1 100644 --- a/NebulaPluginNova/NebulaPluginNova.csproj +++ b/NebulaPluginNova/NebulaPluginNova.csproj @@ -56,11 +56,12 @@ - - + + + @@ -68,8 +69,8 @@ - - - + + + diff --git a/NebulaPluginNova/Patches/ExilePatch.cs b/NebulaPluginNova/Patches/ExilePatch.cs index 41c2e15b..b928f77f 100644 --- a/NebulaPluginNova/Patches/ExilePatch.cs +++ b/NebulaPluginNova/Patches/ExilePatch.cs @@ -137,3 +137,16 @@ static bool Prefix(AirshipExileController __instance,ref Il2CppSystem.Collection return false; } } + +[HarmonyPatch(typeof(ExileController), nameof(ExileController.Begin))] +class ExileControllerBeginPatch +{ + + public static void Postfix(ExileController __instance, [HarmonyArgument(0)] ref GameData.PlayerInfo exiled, [HarmonyArgument(1)] bool tie) + { + try{ + var role = NebulaGameManager.Instance?.GetModPlayerInfo(exiled.PlayerId)?.Role; + if (role != null) __instance.completeString = Language.Translate("game.exile.roleText").Replace("%NAME%", exiled.PlayerName).Replace("%ROLE%", Language.Translate("role." + role.Role.LocalizedName + ".name")); + }catch(Exception e){ Debug.LogError(e.StackTrace); } + } +} diff --git a/NebulaPluginNova/Player/PlayerModInfo.cs b/NebulaPluginNova/Player/PlayerModInfo.cs index a61ed270..c27cef3e 100644 --- a/NebulaPluginNova/Player/PlayerModInfo.cs +++ b/NebulaPluginNova/Player/PlayerModInfo.cs @@ -297,11 +297,17 @@ private void SetRole(AbstractRole role, int[] arguments) { myRole?.Inactivate(); + bool state = MyControl.Data.IsDead; + + //* if (role.RoleCategory == Roles.RoleCategory.ImpostorRole) DestroyableSingleton.Instance.SetRole(MyControl, RoleTypes.Impostor); else DestroyableSingleton.Instance.SetRole(MyControl, RoleTypes.Crewmate); - + //*/ + + if (state) MyControl.Die(DeathReason.Kill,false); + myRole = role.CreateInstance(this, arguments); if(NebulaGameManager.Instance?.GameState == NebulaGameStates.Initialized)myRole.OnActivated(); @@ -407,6 +413,7 @@ public IEnumerator CoGetLeftGuess(Action callback) (message, isCalledByMe) => { var player = NebulaGameManager.Instance!.RegisterPlayer(PlayerControl.AllPlayerControls.Find((Il2CppSystem.Predicate)(p => p.PlayerId == message.playerId))); + //var player = NebulaGameManager.Instance!.GetModPlayerInfo(message.playerId)!; if (message.isRole) player.SetRole(Roles.Roles.AllRoles[message.assignableId], message.arguments); else diff --git a/NebulaPluginNova/Resources/Addons/ChineseLanguagePack.zip b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack.zip new file mode 100644 index 00000000..39f379ba Binary files /dev/null and b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack.zip differ diff --git a/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/Language/SChinese.dat b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/Language/SChinese.dat new file mode 100644 index 00000000..4143a1fd --- /dev/null +++ b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/Language/SChinese.dat @@ -0,0 +1,805 @@ +# Title + +"title.buttons.nebula" : "星云舰设置" +"title.label.nebula" : "Nebula on the Ship" + +"title.buttons.update" : "更新到最新版" +"title.buttons.addons" : "插件" +"title.buttons.developersStudio" : "开发者工具" + +# Certification + +"certification.uncertified" : "未验证" +"certification.uncertified.detail" : "玩家没有安装星云舰模组" +"certification.uncertified.client" : "不能在安装星云舰的情况下
游玩原版游戏" +"certification.unmatchedEpoch" : "远古版本" +"certification.unmatchedEpoch.detail" : "玩家的星云舰版本过老
指导他们从Github或从获得最新版" +"certification.unmatchedEpoch.client" : "您的星云舰版本过老
请从Github或从获得最新版" +"certification.unmatchedBuild" : "未匹配版本" +"certification.unmatchedBuild.detail" : "玩家的星云舰版本不匹配
指导他们从标题页面或从获得最新版" +"certification.unmatchedBuild.client" : "您的星云舰版本不匹配
请从标题页面或从获得最新版" + +# UI + +"ui.dialog.yes" : "是" +"ui.dialog.no" : "否" +"ui.dialog.ok" : "好" +"ui.dialog.exit" : "退出" +"ui.common.loading" : "正在加载" +"ui.update.waitFinishing" : "正在等待更新" +"ui.update.finishUpdate" : "更新完成
请重启游戏" +"ui.document.tooLongNesting" : "[The nesting is too long.]" + +# Versions + +"version.category.all" : "全部" +"version.category.major" : "可用" +"version.category.snapshot" : "快照" +"version.category.preRelease" : "预发布" +"version.category.custom" : "自定义" +"version.category.unknown" : "未知" +"version.fetching.gainPackage" : "下载" +"version.fetching.current" : "当前" +"version.fetching.mismatched" : "停止支持" + +# Game Mode + +"gamemode.standard" : "标准模式" +"gamemode.freeplay" : "自由模式" + +# Options + +"options.switch.off" : "关" +"options.switch.on" : "开" +"options.percentage" : "%" +"options.cross" : "x" +"options.sec" : "s" +"options.followPrimaryChance" : "-" +"options.inactivated" : "未设置" + +"options.gamemode" : "游戏模式" + +"options.tab.setting" : "游戏[设置]" +"options.tab.crewmate" : "[船员]职业" +"options.tab.impostor" : "[伪装者]职业" +"options.tab.neutral" : "[中立]职业" +"options.tab.ghost" : "[灵魂]职业" +"options.tab.modifier" : "[附加]职业" + +"options.assignment" : "数量设置" +"options.assignment.detail" : "设置职业数量" +"options.assignment.crewmate" : "船员职业数量" +"options.assignment.impostor" : "伪装者职业数量" +"options.assignment.neutral" : "中立职业数量" +"options.assignment.unlimited" : "不限制" + +"options.soloFreePlay" : "自由模式假人数量" +"options.soloFreePlay.detail" : "关于假人" +"options.soloFreePlay.numOfDummies" : "假人数量" + +"options.map" : "地图设置" +"options.map.detail" : "关于游戏地图设置" +"options.map.spawnMethod" : "出生点" +"options.map.spawnMethod.default" : "默认" +"options.map.spawnMethod.selective" : "可选择" +"options.map.spawnMethod.random" : "随机" +"options.map.spawnCandidates" : "出生点个数" +"options.map.silentVents" : "阴影中管道动画剔除" +"options.map.silentVents.detail" : "你将不会看见阴影中的管道开关" +"options.map.customization" : "地图自定义" +"options.map.customization.skeld.useAdmin" : "管理室控制台" +"options.map.customization.skeld.cafeteriaVent" : "附加管道(餐厅)" +"options.map.customization.skeld.storageVent" : "附加管道(仓库)" +"options.map.customization.mira.useAdmin" : "管理室控制台" +"options.map.customization.polus.useAdmin" : "管理室控制台" +"options.map.customization.polus.specimenVent" : "附加管道(样本室)" +"options.map.customization.airship.useCockpitAdmin" : "管理室控制台(领航室)" +"options.map.customization.airship.useRecordsAdmin" : "管理室控制台(档案室)" +"options.map.customization.airship.meetingVent" : "附加管道(会议室)" +"options.map.customization.airship.electricalVent" : "附加管道(电气室)" +"options.map.customization.airship.oneWayMeetingRoom" : "会议室单向梯" +"options.map.customization.airship.armoryWiring" : "附加连续任务地点(军械室)" +"options.map.customization.airship.vaultWiring" : "附加连续任务地点(金库)" +"options.map.customization.airship.hallwayWiring" : "附加连续任务地点(大厅)" +"options.map.customization.airship.medicalWiring" : "附加连续任务地点(医疗室)" +"options.map.customization.fungle.simpleLaboratory" : "简化实验室路径" +"options.map.customization.fungle.thinFog" : "薄雾" +"options.map.customization.fungle.glowingCampfire" : "营火发光" +"options.map.customization.fungle.glowingMushroom" : "蘑菇发光" +"options.map.customization.fungle.quickPaceDoorMinigame" : "小游戏快速开门" + +"options.meeting" : "会议设置" +"options.meeting.detail" : "关于会议" +"options.meeting.noticeExtraVictims" : "显示额外尸体" +"options.meeting.deathPenalty" : "驱逐延长时间" +"options.meeting.numOfMeeting" : "会议总数" + +"options.consoleRestriction" : "终端设置" +"options.consoleRestriction.detail" : "关于管理室控制台,传感器,生命仪和监控" +"options.consoleRestriction.unlimited" : "不限制" +"options.consoleRestriction.adminRestriction" : "管理室控制台" +"options.consoleRestriction.vitalsRestriction" : "生命仪" +"options.consoleRestriction.cameraRestriction" : "监控和传感器" +"options.consoleRestriction.resetRestrictions" : "每回合结束后重置终端" + +"options.voiceChat" : "语音设置" +"options.voiceChat.detail" : "关于NoS作者到底多能造这件事" +"options.voiceChat.useVoiceChat" : "开启语音" +"options.voiceChat.wallsBlockAudio" : "隔墙语音锁定" +"options.voiceChat.killersHearDead" : "杀手听得见所击杀的人" +"options.voiceChat.killersHearDead.onlyImpostors" : "杀手仅限伪装者" +"options.voiceChat.impostorsRadio" : "伪装者特殊频道" +"options.voiceChat.jackalRadio" : "豺狼特殊频道" +"options.voiceChat.affectedByCommsSab" : "受通讯破坏影响" + +"options.role.count" : "职业分配" +"options.role.chance" : "分配几率" +"options.role.secondaryChance" : "多分配纪律" +"options.role.count.short" : "职业个数" +"options.modifier.chance" : "生成概率" +"options.role.crewmateCount" : "船员分配数" +"options.role.impostorCount" : "伪装者分配数" +"options.role.neutralCount" : "中立分配数" + +"options.killCoolDown.type.immediate" : "数值" +"options.killCoolDown.type.relative" : "关联" +"options.killCoolDown.type.ratio" : "倍增" + +"options.exclusiveAssignment" : "分配限制" +"options.exclusiveAssignment.detail" : "禁止某些职业同时分配" +"options.exclusiveAssignment.category.0" : "组合1" +"options.exclusiveAssignment.category.1" : "组合2" +"options.exclusiveAssignment.category.2" : "组合3" +"options.exclusiveAssignment.category.3" : "组合4" +"options.exclusiveAssignment.category.4" : "组合5" +"options.exclusiveAssignment.category.5" : "组合6" +"options.exclusiveAssignment.category.6" : "组合7" +"options.exclusiveAssignment.category.7" : "组合8" +"options.exclusiveAssignment.category.8" : "组合9" +"options.exclusiveAssignment.category.9" : "组合10" + +# Roles + +"role.general.ventOption" : "管道使用设置" +"role.general.ventCoolDown" : "管道使用冷却" +"role.general.ventCoolDown.short" : "冷却" +"role.general.ventDuration" : "最大停留时间" +"role.general.ventDuration.short" : "停留" +"role.general.ventUses" : "做多使用次数" +"role.general.ventUses.short" : "次数" +"role.general.canUseVent" : "可以使用管道" +"role.general.canUseVent.short" : "管道" +"role.general.common" : "#" + +# Complex Roles + +"role.guesser.numOfGuess" : "猜测机会" +"options.role.guesser.detail" : "赌怪可以在会议中猜测别人的职业。
如果猜错了,赌怪就会暴毙。" +"role.guesser.leftGuess" : "剩余猜测机会" + +"role.trapper.placeCoolDown" : "安放冷却时间" +"role.trapper.placeDuration" : "安放所需时间" +"role.trapper.numOfCharges" : "最大螺丝个数" + +# Common Roles + +"options.role.modifierFilter" : "附加职业选项" + +# Crewmate Roles + +"role.crewmate.name" : "船员" +"role.crewmate.short" : "船" +"role.crewmate.blurb" : "完成任务" +"options.role.crewmate.detail" : "船员没有任何特殊能力。" + +"role.agent.name" : "代理人" +"role.agent.short" : "代" +"role.agent.blurb" : "帮助动作慢的船员完成任务" +"options.role.agent.detail" : "代理人可以代替别人完成任务。" +"options.role.agent.numOfExemptedTasks" : "基本任务数量" +"options.role.agent.numOfExtraTasks" : "每次代理的任务数量" + +"role.bait.name" : "诱饵" +"role.bait.short" : "诱" +"role.bait.blurb" : "诱骗你的敌人" +"options.role.bait.reportDelay" : "报告延迟" +"options.role.bait.reportDelayDispersion" : "报告随机延迟" +"options.role.bait.canSeeVentFlash" : "可以看见管道闪烁" +"options.role.bait.detail" : "击杀诱饵的凶手将立刻报告诱饵的尸体。" +"options.role.bait.showKillFlash" : "凶手击杀显示闪光" + +"role.busker.name" : "街头艺人" +"role.busker.short" : "街" +"role.busker.blurb" : "一个不可思议的奇迹" +"options.role.busker.detail" : "街头艺人可以灵魂出窍,若在假死期间报告则被视为死亡。" +"options.role.busker.pseudocideCoolDown" : "假死冷却时间" +"options.role.busker.pseudocideDuration" : "假死最大时间" + +"role.comet.name" : "彗星" +"role.comet.short" : "彗" +"role.comet.blurb" : "一飞冲天!" +"options.role.comet.detail" : "彗星可以隐秘而快速地移动。
彗星使用技能时是隐身的。" +"options.role.comet.blazeCoolDown" : "加速冷却时间" +"options.role.comet.blazeSpeed" : "加速时速度" +"options.role.comet.blazeDuration" : "加速持续时间" +"options.role.comet.blazeVisionRate" : "加速时视野" + +"role.doctor.name" : "医学家" +"role.doctor.short" : "医" +"role.doctor.blurb" : "了解别人的死亡" +"options.role.doctor.detail" : "医学家拥有移动的生命仪。" +"options.role.doctor.portableVitalsCharge" : "初始生命仪充能" +"options.role.doctor.maxPortableVitalsCharge" : "最大充能数量" +"options.role.doctor.chargesPerTasks" : "每个任务的充能数量" +"role.doctor.gadgetLeft" : "%SECOND%s" + +"role.necromancer.name" : "死灵法师" +"role.necromancer.short" : "死" +"role.necromancer.blurb" : "复活死者" +"options.role.necromancer.detail" : "死灵法师可以让尸体复活!
死灵法师需要将尸体拖拽到正确的房间后复活。" +"options.role.necromancer.reviveCoolDown" : "复活冷却时间" +"options.role.necromancer.reviveDuration" : "复活所需时间" +"options.role.necromancer.detectedRange" : "尸体检测半径" +"options.role.necromancer.reviveMinRange" : "最小到正确房间距离" +"options.role.necromancer.reviveMaxRange" : "最大到正确房间距离" +"role.necromancer.phantomMessage" : "请带我去%ROOM%..." + +"role.niceGuesser.name" : "正义的赌怪" +"role.niceGuesser.short" : "正赌" +"role.niceGuesser.blurb" : "生命就是豪赌" +"options.role.niceGuesser.detail" : "赌怪可以在会议中猜测别人的职业。
如果猜错了,赌怪就会暴毙。" + +"role.niceTrapper.name" : "正义的陷阱师" +"role.niceTrapper.short" : "正陷" +"role.niceTrapper.blurb" : "布置陷阱并找出伪装者" +"options.role.niceTrapper.detail" : "陷阱师可以防止不同类型的陷阱" +"options.role.niceTrapper.costOfCommTrap" : "信息陷阱所需螺丝数" + +"role.madmate.name" : "叛徒" +"role.madmate.short" : "叛" +"role.madmate.blurb" : "投靠伪装者" +"options.role.madmate.detail" : "叛徒是伪装者阵营角色。
叛徒需要背叛船员并帮助伪装者胜利。" + +"role.mayor.name" : "市长" +"role.mayor.short" : "市" +"role.mayor.blurb" : "找到并投出伪装者" +"options.role.mayor.detail" : "市长可以在会议中存票。
在有需要时,可以一次性投出。" +"options.role.mayor.fixedVotes" : "投票特殊设置" +"options.role.mayor.minVote" : "最小投票数" +"options.role.mayor.maxVote" : "最大投票数" +"options.role.mayor.maxVotesStock" : "最大存票数" +"options.role.mayor.voteAssignment" : "每轮获得的票数" + +"role.phosphorus.name" : "灯人" +"role.phosphorus.short" : "灯" +"role.phosphorus.blurb" : "驱散黑暗" +"options.role.phosphorus.detail" : "灯人放置的灯可以发光。
伪装者将不能在灯附近击杀。" +"options.role.phosphorus.numOfLamps" : "灯的数量" +"options.role.phosphorus.placeCoolDown" : "放置冷却时间" +"options.role.phosphorus.lampCoolDown" : "点灯冷却时间" +"options.role.phosphorus.lampDuration" : "点灯持续时间" +"options.role.phosphorus.lampStrength" : "照明强度" + +"role.provocateur.name" : "挑衅者" +"role.provocateur.short" : "挑" +"role.provocateur.blurb" : "我死了,你也别想活着!" +"options.role.provocateur.detail" : "挑衅者会连带凶手一同死亡。" +"options.role.provocateur.embroilCoolDown" : "挑衅冷却时间" +"options.role.provocateur.embroilAdditionalCoolDown" : "挑衅递增时间" +"options.role.provocateur.embroilDuration" : "挑衅持续时间" + +"role.seer.name" : "灵媒" +"role.seer.short" : "灵" +"role.seer.blurb" : "你能预见玩家的死亡" +"options.role.seer.detail" : "灵媒可以在死亡位置看见死者的灵魂。" +"options.role.seer.ghostDuration" : "灵魂存在轮数" +"options.role.seer.canSeeGhostsInShadow" : "可以在阴影中看到灵魂" + +"role.sheriff.name" : "警长" +"role.sheriff.short" : "警" +"role.sheriff.blurb" : "击杀伪装者" +"options.role.sheriff.detail" : "警长可以击杀别人。
若尝试击杀了船员,则警长暴毙。" +"options.role.sheriff.canKillMadmate" : "可以击杀叛徒" +"options.role.sheriff.killCoolDown" : "击杀冷却时间" +"options.role.sheriff.numOfShots" : "子弹数量" + +# Impostor Roles + +"role.impostor.name" : "伪装者" +"role.impostor.short" : "伪" +"role.impostor.blurb" : "击杀和破坏" +"options.role.impostor.detail" : "伪装者没有任何特殊能力。" + +"role.bountyHunter.name" : "赏金猎人" +"role.bountyHunter.short" : "赏" +"role.bountyHunter.blurb" : "开启一场杀戮盛宴!" +"options.role.bountyHunter.detail" : "赏金猎人拥有独特的击杀冷却。
如果击杀了非目标,会受到击杀冷却惩罚。" +"options.role.bountyHunter.bountyKillCoolDown" : "击杀赏金目标后的冷却时间" +"options.role.bountyHunter.othersKillCoolDown" : "击杀其他人后的冷却时间" +"options.role.bountyHunter.changeBountyInterval" : "目标切换间隔" +"options.role.bountyHunter.showBountyArrow" : "展示目标箭头" +"options.role.bountyHunter.arrowUpdateInterval" : "箭头刷新间隔" + +"role.camouflager.name" : "隐蔽者" +"role.camouflager.short" : "隐" +"role.camouflager.blurb" : "隐蔽与击杀" +"options.role.camouflager.detail" : "隐蔽者可以让所有人的外观变得相同" +"options.role.camouflager.camoCoolDown" : "隐蔽冷却时间" +"options.role.camouflager.camoDuration" : "隐蔽持续时间" + +"role.cleaner.name" : "清理者" +"role.cleaner.short" : "清" +"role.cleaner.blurb" : "杀人不留痕迹" +"options.role.cleaner.detail" : "清理者可以清理掉尸体。" +"options.role.cleaner.cleanCoolDown" : "清理冷却时间" +"options.role.cleaner.syncKillAndCleanCoolDown" : "击杀与清理共享冷却" + +"role.evilGuesser.name" : "邪恶的赌怪" +"role.evilGuesser.short" : "坏赌" +"role.evilGuesser.blurb" : "生命就是豪赌" +"options.role.evilGuesser.detail" : "赌怪可以在会议中猜测别人的职业。
如果猜错了,赌怪就会暴毙。" + +"role.evilTrapper.name" : "邪恶的陷阱师" +"role.evilTrapper.short" : "坏陷" +"role.evilTrapper.blurb" : "布置陷阱并击杀船员" +"options.role.evilTrapper.detail" : "邪恶的陷阱师拥有布置普通陷阱和击杀陷阱的能力。
击杀陷阱和击杀按键共用冷却。" +"options.role.evilTrapper.killTrapSoundDistance" : "击杀陷阱音效半径" +"options.role.evilTrapper.costOfKillTrap" : "击杀陷阱所需螺丝数" + +"role.illusioner.name" : "幻术师" +"role.illusioner.short" : "幻" +"role.illusioner.blurb" : "这才叫幻术!" +"options.role.illusioner.detail" : "幻术师同时拥有化形和画皮的能力。" +"options.role.illusioner.sampleCoolDown" : "取样冷却时间" +"options.role.illusioner.morphCoolDown" : "化形冷却时间" +"options.role.illusioner.morphDuration" : "化形持续时间" +"options.role.illusioner.paintCoolDown" : "画皮冷却时间" +"options.role.illusioner.loseSampleOnMeeting" : "会议后丢失取样目标" +"options.role.illusioner.transformAfterMeeting" : "会议后更新样貌" +"options.role.illusioner.sampleOriginalLook" : "取样锁定" + +"role.jailer.name" : "狱卒" +"role.jailer.short" : "狱" +"role.jailer.blurb" : "一切尽在掌控" +"options.role.jailer.detail" : "狱卒可以很好地分析局势。
狱卒拥有移动的管理室控制台。" +"options.role.jailer.canMoveWithMapWatching" : "可以在打开控制台时移动" +"options.role.jailer.canIdentifyDeadBodies" : "可以看到尸体" +"options.role.jailer.canIdentifyImpostors" : "可以看到伪装者" + +"role.marionette.name" : "木偶师" +"role.marionette.short" : "木" +"role.marionette.blurb" : "利用木偶欺诈船员" +"options.role.marionette.detail" : "木偶师可以放置木偶。
木偶师可以交换其与木偶的位置。" +"options.role.marionette.placeCoolDown" : "放置冷却时间" +"options.role.marionette.swapCoolDown" : "交换冷却时间" +"options.role.marionette.decoyDuration" : "木偶存在时间" +"options.role.marionette.canSeeDecoyInShadow" : "可以在阴影中看见木偶" + +"role.morphing.name" : "化形者" +"role.morphing.short" : "化" +"role.morphing.blurb" : "通过改变外貌摆脱嫌疑" +"options.role.morphing.detail" : "化形者可以取样船员
并变成他们的样子。" +"options.role.morphing.sampleCoolDown" : "取样冷却时间" +"options.role.morphing.morphCoolDown" : "化形冷却时间" +"options.role.morphing.morphDuration" : "化形持续时间" +"options.role.morphing.loseSampleOnMeeting" : "会议后失去取样目标" + +"role.painter.name" : "画皮师" +"role.painter.short" : "画" +"role.painter.blurb" : "再也没有人认识你了" +"options.role.painter.detail" : "画皮师可以取样船员
并改变别人的外貌。" +"options.role.painter.sampleCoolDown" : "取样冷却时间" +"options.role.painter.paintCoolDown" : "画皮冷却时间" +"options.role.painter.loseSampleOnMeeting" : "会议后失去取样目标" +"options.role.painter.transformAfterMeeting" : "会议后更新样貌" + +"role.raider.name" : "强盗" +"role.raider.short" : "强" +"role.raider.blurb" : "让我们抢劫吧!" +"options.role.raider.detail" : "强盗通过扔出斧子击杀船员。
扔出的斧子将保留在墙上。" +"options.role.raider.throwCoolDown" : "投掷冷却时间" +"options.role.raider.axeSize" : "斧子大小" +"options.role.raider.axeSpeed" : "斧子速度" +"options.role.raider.canKillImpostor" : "可以击杀伪装者" + +"role.reaper.name" : "送葬者" +"role.reaper.short" : "送" +"role.reaper.blurb" : "隐藏船员的尸体" +"options.role.reaper.detail" : "送葬者可以拖拽尸体。" + +"role.sniper.name" : "狙击手" +"role.sniper.short" : "狙" +"role.sniper.blurb" : "射击!" +"options.role.sniper.detail" : "狙击手可以狙击船员。
狙击手射击后,船员将看到提示。" +"options.role.sniper.snipeCoolDown" : "狙击冷却时间" +"options.role.sniper.shotSize" : "子弹大小" +"options.role.sniper.shotEffectiveRange" : "狙击范围" +"options.role.sniper.shotNoticeRange" : "狙击提示范围" +"options.role.sniper.storeRifleOnFire" : "狙击后自动收枪" +"options.role.sniper.canSeeRifleInShadow" : "可以在阴影中看到枪" + +# Neutral Roles + +"role.arsonist.name" : "纵火犯" +"role.arsonist.short" : "纵" +"role.arsonist.blurb" : "让火焰净化一切" +"options.role.arsonist.detail" : "让一切活着的船员都燃烧起来!" +"options.role.arsonist.douseCoolDown" : "涂油冷却时间" +"options.role.arsonist.douseDuration" : "涂油所需时间" + +"role.chainShifter.name" : "连环交换师" +"role.chainShifter.short" : "连" +"role.chainShifter.blurb" : "搅乱局势" +"options.role.chainShifter.detail" : "连环交换师无法获胜。" +"options.role.chainShifter.shiftCoolDown" : "交换冷却时间" + +"role.jackal.name" : "豺狼" +"role.jackal.short" : "豺" +"role.jackal.blurb" : "杀死所有人!" +"options.role.jackal.detail" : "豺狼单独胜利。
驱逐豺狼是伪装者和船员获胜的必要条件。" +"options.role.jackal.killCoolDown" : "击杀冷却时间" +"options.role.jackal.canCreateSidekick" : "可以招募跟班" +"options.role.jackal.numOfKillingToCreateSidekick" : "招募跟班所需的击杀数" + +"role.sidekick.name" : "跟班" +"role.sidekick.short" : "跟" +"options.role.jackal.sidekick.detail" : "跟班隶属豺狼阵营。
跟班将会在豺狼死后上位。" +"options.role.jackal.sidekick.canKill" : "可以击杀" +"options.role.jackal.sidekick.killCoolDown" : "击杀冷却时间" +"options.role.jackal.sidekick.isModifier" : "作为附加职业存在" +"options.role.jackal.sidekick.canCreateSidekickChainly" : "上位后可以再次招募跟班" + +"role.jester.name" : "小丑" +"role.jester.short" : "小" +"role.jester.blurb" : "想办法被投出去" +"options.role.jester.detail" : "小丑只要被驱逐就获胜。" +"options.role.jester.canDragDeadBody" : "可以拖拽尸体" + +"role.paparazzo.name" : "摄影师" +"role.paparazzo.short" : "摄" +"role.paparazzo.blurb" : "一,二,三,茄子!" +"role.paparazzo.taskText" : "拍照并公开(%DETAIL%)" +"role.paparazzo.taskTextSubject" : "包含人数: %CS%/%GS%" +"role.paparazzo.taskTextDisclosed" : "已公开人数: %CD%/%GD%" +"options.role.paparazzo.detail" : "摄影师要拍照并在会议期间公开照片。" +"options.role.paparazzo.shotCoolDown" : "拍照冷却时间" +"options.role.paparazzo.requiredSubjects" : "所需照片包含人数" +"options.role.paparazzo.requiredDisclosed" : "所需公开包含人数" + +"role.vulture.name" : "秃鹫" +"role.vulture.short" : "秃" +"role.vulture.blurb" : "吞噬尸体" +"options.role.vulture.detail" : "秃鹫通过吞噬尸体获胜。" +"options.role.vulture.eatCoolDown" : "吞噬冷却时间" +"options.role.vulture.numOfTheEatenToWin" : "所需吞噬尸体数" + +# Modifiers + +"role.metaRole.ui.roles" : "分配的职业" + +"role.guesser.name" : "赌怪" +"role.guesser.blurb" : "你可以赌任何人" + +"role.metaRole.name" : "自由模式附加" + +"role.bloody.name" : "血语者" +"options.role.bloody.detail" : "凶手将会留下一道血迹" +"options.role.bloody.curseDuration" : "血迹持续时间" + +"role.tieBreaker.name" : "破平者" +"options.role.tieBreaker.detail" : "当投票持平时,破平者一票算作两票。" + +"role.lover.name" : "恋人" +"options.role.lover.detail" : "在更多获胜方式的同时更容易暴毙" +"role.lover.blurb" : "你与 %NAME% 坠入了爱河" +"options.role.lover.numOfPairs" : "生成对数" +"options.role.lover.chanceOfAssigningImpostors" : "脏链子生成概率" +"options.role.lover.allowExtraWin" : "允许跟随原阵营获胜" + +# Teams + +"teams.crewmate" : "船员" +"teams.impostor" : "伪装者" +"teams.arsonist" : "纵火犯" +"teams.chainShifter" : "交换师" +"teams.jackal" : "豺狼" +"teams.jester" : "小丑" +"teams.paparazzo" : "摄影师" +"teams.vulture" : "秃鹫" + +# Location + +"location.skeld.admin" : "管理室" +"location.skeld.cafeteria" : "餐厅" +"location.skeld.comms" : "通讯室" +"location.skeld.electrical" : "电气室" +"location.skeld.lifeSupp" : "氧气室" +"location.skeld.lifeSupport" : "氧气室" +"location.skeld.lowerEngine" : "下引擎" +"location.skeld.medBay" : "医疗室" +"location.skeld.nav" : "导航室" +"location.skeld.navigation" : "导航室" +"location.skeld.reactor" : "反应堆" +"location.skeld.security" : "监控室" +"location.skeld.shields" : "护盾室" +"location.skeld.storage" : "仓库" +"location.skeld.upperEngine" : "上引擎" +"location.skeld.weapons" : "武器室" +"location.mira.admin" : "管理室" +"location.mira.balcony" : "阳台" +"location.mira.cafeteria" : "餐厅" +"location.mira.comms" : "通讯室" +"location.mira.decontamination" : "消毒室" +"location.mira.greenhouse" : "温室" +"location.mira.laboratory" : "实验室" +"location.mira.lockerRoom" : "更衣室" +"location.mira.medBay" : "医疗室" +"location.mira.office" : "办公室" +"location.mira.reactor" : "反应堆" +"location.mira.rendezvous" : "集合点" +"location.mira.storage" : "仓库" +"location.polus.abditory" : "假山" +"location.polus.admin" : "管理室" +"location.polus.comms" : "通讯室" +"location.polus.boilerRoom" : "锅炉室" +"location.polus.drill" : "电钻处" +"location.polus.dropship" : "运输船" +"location.polus.ejection" : "岩浆" +"location.polus.electrical" : "电气室" +"location.polus.laboratory" : "实验室" +"location.polus.lifeSupp" : "氧气室" +"location.polus.lifeSupport" : "氧气室" +"location.polus.office" : "办公室" +"location.polus.security" : "监控室" +"location.polus.snowdrift" : "雪堆" +"location.polus.specimens" : "样本室" +"location.polus.storage" : "仓库" +"location.polus.weapons" : "武器室" +"location.airship.brig" : "牢房" +"location.airship.engine" : "引擎室" +"location.airship.hallway" : "大厅" +"location.airship.kitchen" : "厨房" +"location.airship.record" : "档案室" +"location.airship.storage" : "货舱" +"location.airship.armory" : "军械室" +"location.airship.cockpit" : "座舱" +"location.airship.comms" : "通讯室" +"location.airship.electrical" : "电气室" +"location.airship.gapRoom" : "间隙室" +"location.airship.lounge" : "休息室" +"location.airship.medical" : "医疗室" +"location.airship.meetingRoom" : "会议室" +"location.airship.security" : "监控室" +"location.airship.shower" : "淋浴室" +"location.airship.toilet" : "厕所" +"location.airship.vault" : "保险库" +"location.airship.viewingDeck" : "观景台" +"location.fungle.beach" : "海滩" +"location.fungle.cafeteria" : "食堂" +"location.fungle.campfire" : "营火" +"location.fungle.comms" : "通讯室" +"location.fungle.dropship" : "运输船" +"location.fungle.fishingDock" : "码头" +"location.fungle.greenhouse" : "温室" +"location.fungle.highlands" : "高地" +"location.fungle.jungle" : "丛林" +"location.fungle.kitchen" : "厨房" +"location.fungle.laboratory" : "实验室" +"location.fungle.lookout" : "瞭望台" +"location.fungle.meetingRoom" : "会议室" +"location.fungle.miningPit" : "矿坑" +"location.fungle.reactor" : "反应堆" +"location.fungle.recRoom" : "水花区" +"location.fungle.storage" : "仓库" +"location.fungle.sleepingQuarters" : "宿舍" +"location.fungle.upperEngine" : "上引擎室" + +# Button + +"button.label.agent" : "代理" +"button.label.blaze" : "加速" +"button.label.camo" : "隐蔽" +"button.label.clean" : "清理" +"button.label.destroy" : "摧毁" +"button.label.douse" : "涂油" +"button.label.drag" : "拖拽" +"button.label.eat" : "吞噬" +"button.label.embroil" : "挑衅" +"button.label.equip" : "抬枪" +"button.label.ignite" : "点火" +"button.label.kill" : "击杀" +"button.label.lantern" : "放置" +"button.label.monitor" : "监视" +"button.label.morph" : "化形" +"button.label.operate" : "操作" +"button.label.paint" : "画皮" +"button.label.place" : "放置" +"button.label.pseudocide" : "假死" +"button.label.rejoin" : "重新加入语音" +"button.label.release" : "释放" +"button.label.revive" : "复活" +"button.label.sample" : "取样" +"button.label.shot" : "射击" +"button.label.snipe" : "狙击" +"button.label.sidekick" : "招募" +"button.label.swap" : "交换" +"button.label.shift" : "交换" +"button.label.throw" : "投掷" +"button.label.unequip" : "放下" +"button.label.vital" : "生命仪" + +# Game + +"game.prespawn.countdown" : "剩余时间: %SECOND%" +"game.prespawn.waiting" : "正在等待其他玩家..." +"game.prespawn.spawnIn" : "你出现在" + +"game.meeting.someoneDisappeared" : "有人也失踪了" + +# Statistics + +"statistics.events.startGame" : "Game Start" +"statistics.events.endGame" : "Game Set" +"statistics.events.kill" : "Kill" +"statistics.events.misfire" : "Misfire" +"statistics.events.exiled" : "Exiled" +"statistics.events.report" : "Report" +"statistics.events.baitReport" : "Bait Report" +"statistics.events.emergency" : "Emergency" +"statistics.events.endMeeting" : "Meeting End" +"statistics.events.disconnect" : "Disconnect" +"statistics.events.revive" : "Revive" +"statistics.events.eat" : "Eat" +"statistics.events.clean" : "Clean" +"statistics.events.missed" : "Missed" +"statistics.events.embroil" : "Embroil" +"statistics.events.trap" : "Entrap" +"statistics.events.guess" : "Guess" + +# States + +"state.alive" : "存活" +"state.dead" : "死亡" +"state.exiled" : "驱逐" +"state.misfired" : "走火" +"state.sniped" : "狙击" +"state.beaten" : "斩首" +"state.guessed" : "赌杀" +"state.misguessed" : "误赌" +"state.embroiled" : "挑衅" +"state.suicide" : "自杀" +"state.trapped" : "落陷" +"state.revived" : "复活" + +# Endings + +"end.crewmate" : "船员胜利%EXTRA%" +"end.impostor" : "伪装者胜利%EXTRA%" +"end.arsonist" : "纵火犯胜利%EXTRA%" +"end.jackal" : "豺狼团队胜利%EXTRA%" +"end.jester" : "小丑胜利%EXTRA%" +"end.vulture" : "秃鹫胜利%EXTRA%" +"end.lover" : "恋人胜利%EXTRA%" +"end.paparazzo" : "摄影师胜利%EXTRA%" +"end.nogame" : "房主结束了游戏" + +"end.extra.lover" : " + 恋人胜利" + +# Help + +"help.tabs.myInfo" : "我的职业" +"help.tabs.roles" : "所有职业" +"help.tabs.modifiers" : "附加职业" +"help.tabs.options" : "设置" +"help.tabs.slides" : "Slides" +"help.slides.share" : "Share" +"help.command" : "命令" +"help.command.nogame" : "没有游戏" +"help.command.quickStart" : "快速开始" +"help.command.cancelStarting" : "中断开始" +"help.command.console" : "控制台" + +# Voice Chat + +"voiceChat.dialog.confirm" : "你确定加入语音频道吗?" +"voiceChat.info.mute" : "静音" +"voiceChat.info.unmute" : "未静音" +"voiceChat.info.radio" : "频道" +"voiceChat.info.impostorRadio" : "伪装者频道" +"voiceChat.info.jackalRadio" : "豺狼团队频道" +"voiceChat.info.loversRadio" : "恋人频道" +"voiceChat.info.roomHostRadio" : "房主频道" + +# Console + +"console.notAvailable" : "不可用" + +# Inventory + +"inventory.palette.catalogue" : "类型" +"inventory.catalogue.innersloth" : "原版颜色" +"inventory.color.vanilla0" : "红色" +"inventory.color.vanilla1" : "蓝色" +"inventory.color.vanilla2" : "绿色" +"inventory.color.vanilla3" : "粉色" +"inventory.color.vanilla4" : "橙色" +"inventory.color.vanilla5" : "黄色" +"inventory.color.vanilla6" : "黑色" +"inventory.color.vanilla7" : "白色" +"inventory.color.vanilla8" : "紫色" +"inventory.color.vanilla9" : "棕色" +"inventory.color.vanilla10" : "青色" +"inventory.color.vanilla11" : "黄绿色" +"inventory.color.vanilla12" : "红褐色" +"inventory.color.vanilla13" : "粉色" +"inventory.color.vanilla14" : "焦黄色" +"inventory.color.vanilla15" : "灰色" +"inventory.color.vanilla16" : "茶色" +"inventory.color.vanilla17" : "珊瑚色" +"inventory.color.visor" : "默认" + +# Input + +"input.kill" : "击杀(模组)" +"input.ability" : "技能" +"input.secondaryAbility" : "第二技能" +"input.aidAction" : "技能切换" +"input.command" : "控制键" +"input.screenshot" : "截屏" +"input.mute" : "静音" +"input.recording" : "录制..." + +# Client Configurations + +"config.client.keyBindings" : "按键绑定" +"config.client.vcSettings" : "VC设置" +"config.client.outputHash" : "输出哈希表" +"config.client.noiseReduction" : "降噪" + +# Preset + +"preset.preset" : "预设" +"preset.saveAs" : "保存到..." +"preset.enterPresetName" : "请输入一个预设名" +"preset.save" : "保存" +"preset.reload" : "加载" +"preset.saveSuccess" : "保存完成" +"preset.loadSuccess" : "预设加载成功" +"preset.loadFailed" : "预设加载失败" + +# Developer Studio + +"devStudio.ui.common.edit" : "编辑" +"devStudio.ui.common.save" : "保存" +"devStudio.ui.common.preview" : "预览" +"devStudio.ui.common.delete" : "删除" +"devStudio.ui.common.clone" : "复制" +"devStudio,ui.common.original" : "原始" +"devStudio.ui.common.generate" : "生成" +"devStudio.ui.common.confirmSaving" : "你确定保存吗?" +"devStudio.ui.common.confirmDeletingAddon" : "你确定删除吗?" +"devStudio.ui.common.confirmDeleting" : "你确定删除吗?" +"devStudio.ui.main.title" : "我的插件" +"devStudio.ui.addon.build" : "导出插件" +"devStudio.ui.addon.document" : "描述" +"devStudio.ui.addon.cosmetics" : "装扮" +"devStudio.ui.addon.language" : "语言" +"devStudio.ui.document.isDuplicatedId" : "该文档已经存在。" +"devStudio.ui.document.isUsingId" : "太棒了!它正常启用了!" +"devStudio.ui.document.element.contents" : "作者" +"devStudio.ui.document.element.aligned" : "副作者" +"devStudio.ui.document.element.localizedText" : "本地化键名" +"devStudio.ui.document.element.rawText" : "插入文本" +"devStudio.ui.document.element.image" : "插入图像" +"devStudio.ui.document.element.vertical" : "创建垂直空间" +"devStudio.ui.document.element.horizontal" : "创建水平空间" +"devStudio.ui.document.element.documentRef" : "添加文档" +"devStudio.ui.document.editor.color" : "颜色" +"devStudio.ui.document.editor.image" : "图像" +"devStudio.ui.document.editor.width" : "宽度" +"devStudio.ui.document.editor.height" : "高度" +"devStudio.ui.document.editor.fontSize" : "字体大小" +"devStudio.ui.document.editor.isBold" : "加粗" +"devStudio.ui.document.editor.document" : "文档 ID" +"devStudio.ui.hint.requiredText" : "#所需文本" +"devStudio.ui.hint.duplicatedId" : "#已存在" \ No newline at end of file diff --git a/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/addon.meta b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/addon.meta new file mode 100644 index 00000000..73a533b1 --- /dev/null +++ b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/addon.meta @@ -0,0 +1,7 @@ +{ + "Id" : "Chinese Language Pack", + "Name" : "Chinese Language Pack", + "Author" : "凛", + "Description" : "添加中文翻译(内置)", + "Version" : "" +} \ No newline at end of file diff --git a/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/icon.png b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/icon.png new file mode 100644 index 00000000..26f3c5b8 Binary files /dev/null and b/NebulaPluginNova/Resources/Addons/ChineseLanguagePack/icon.png differ diff --git a/NebulaPluginNova/Resources/Addons/ModTranslation.zip b/NebulaPluginNova/Resources/Addons/ModTranslation.zip new file mode 100644 index 00000000..795c89da Binary files /dev/null and b/NebulaPluginNova/Resources/Addons/ModTranslation.zip differ diff --git a/NebulaPluginNova/Resources/Addons/ModTranslation/Language/English.dat b/NebulaPluginNova/Resources/Addons/ModTranslation/Language/English.dat new file mode 100644 index 00000000..33cf751e --- /dev/null +++ b/NebulaPluginNova/Resources/Addons/ModTranslation/Language/English.dat @@ -0,0 +1,19 @@ +#Roles + +"role.madman.name" : "Madman" +"role.madman.short" : "Ma" +"role.madman.blurb" : "Swap Your Role With Others By Killing Them" +"options.role.madman.detail" : "Swap the role with others by killing them." +"options.role.madman.killCooldown" : "Kill Cool Down" +"options.role.madman.canBeGuess" : "Can Be Guess" + +"role.hitman.name" : "Hitman" +"role.hitman.short" : "Hi" +"role.hitman.blurb" : "Killing Spree!" +"options.role.hitman.detail" : "Hitman have more than one knife." +"options.role.hitman.killCoolDown" : "Kill Cool Down" +"options.role.hitman.numOfKilling" : "Number Of Kills Per Kill" + +#Exiled + +"game.exile.roleText" : "%NAME% was the %ROLE%" \ No newline at end of file diff --git a/NebulaPluginNova/Resources/Addons/ModTranslation/Language/SChinese.dat b/NebulaPluginNova/Resources/Addons/ModTranslation/Language/SChinese.dat new file mode 100644 index 00000000..57ae1a71 --- /dev/null +++ b/NebulaPluginNova/Resources/Addons/ModTranslation/Language/SChinese.dat @@ -0,0 +1,19 @@ +#Roles + +"role.madman.name" : "疯子" +"role.madman.short" : "疯" +"role.madman.blurb" : "通过击杀交换你的职业" +"options.role.madman.detail" : "疯子通过击杀别人交换职业。" +"options.role.madman.killCooldown" : "击杀冷却时间" +"options.role.madman.canBeGuess" : "是否可以被猜测" + +"role.hitman.name" : "杀手" +"role.hitman.short" : "杀" +"role.hitman.blurb" : "杀戮盛宴!" +"options.role.hitman.detail" : "杀手每次冷却后都有N刀可出。" +"options.role.hitman.killCoolDown" : "击杀冷却时间" +"options.role.hitman.numOfKilling" : "每次冷却获得的击杀数" + +#Exiled + +"game.exile.roleText" : "%NAME% 的职业是 %ROLE%" \ No newline at end of file diff --git a/NebulaPluginNova/Resources/Addons/ModTranslation/addon.meta b/NebulaPluginNova/Resources/Addons/ModTranslation/addon.meta new file mode 100644 index 00000000..5a786836 --- /dev/null +++ b/NebulaPluginNova/Resources/Addons/ModTranslation/addon.meta @@ -0,0 +1,7 @@ +{ + "Id" : "ModTranslation", + "Name" : "Addition Translation", + "Author" : "凛", + "Description" : "A build-in Addon provided he translation for additional roles", + "Version" : "" +} \ No newline at end of file diff --git a/NebulaPluginNova/Resources/Addons/ModTranslation/icon.png b/NebulaPluginNova/Resources/Addons/ModTranslation/icon.png new file mode 100644 index 00000000..5d2874bf Binary files /dev/null and b/NebulaPluginNova/Resources/Addons/ModTranslation/icon.png differ diff --git a/NebulaPluginNova/Roles/Impostor/Hitman.cs b/NebulaPluginNova/Roles/Impostor/Hitman.cs new file mode 100644 index 00000000..6ce96259 --- /dev/null +++ b/NebulaPluginNova/Roles/Impostor/Hitman.cs @@ -0,0 +1,101 @@ +using AmongUs.GameOptions; +using Nebula.Configuration; +using Nebula.Modules.ScriptComponents; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Nebula.Roles.Impostor; + +public class Hitman : ConfigurableStandardRole +{ + static public Hitman MyRole = new Hitman(); + public override RoleCategory RoleCategory => RoleCategory.ImpostorRole; + + public override string LocalizedName => "hitman"; + public override Color RoleColor => Palette.ImpostorRed; + public override Team Team => Impostor.MyTeam; + + public override RoleInstance CreateInstance(PlayerModInfo player, int[] arguments) => new Instance(player); + + private KillCoolDownConfiguration KillCoolDownOption = null!; + private NebulaConfiguration NumOfKillingOption = null!; + protected override void LoadOptions() + { + base.LoadOptions(); + + KillCoolDownOption = new(RoleConfig, "killCoolDown", KillCoolDownConfiguration.KillCoolDownType.Immediate, 2.5f, 2.5f, 60f, -22.5f, 35f, 0.125f, 0.125f, 2f, 30f, 5f, 1.125f); + NumOfKillingOption = new(RoleConfig, "numOfKilling", null, 2f, 5f, 1f, 2f, 2f); + } + + public class Instance : Impostor.Instance + { + private ModAbilityButton? killButton = null; + + public override AbstractRole Role => MyRole; + public override bool HasVanillaKillButton => false; + public Instance(PlayerModInfo player) : base(player) + { + } + + int leftKillingData = 0; + bool pauseCooldown = false; + TMPro.TMP_Text usedIcon = null!; + + public override void OnActivated() + { + base.OnActivated(); + + if (AmOwner) + { + pauseCooldown = false; + leftKillingData = 0; + var killTracker = Bind(ObjectTrackers.ForPlayer(null, MyPlayer.MyControl, (p) => !p.Data.Role.IsImpostor && !p.Data.IsDead)); + + killButton = Bind(new ModAbilityButton(false,true)).KeyBind(KeyAssignmentType.Kill); + killButton.Availability = (button) => killTracker.CurrentTarget != null && MyPlayer.MyControl.CanMove; + killButton.Visibility = (button) => !MyPlayer.MyControl.Data.IsDead; + killButton.OnClick = (button) => { + PlayerControl.LocalPlayer.ModKill(killTracker.CurrentTarget!, true, PlayerState.Dead, EventDetail.Kill); + + leftKillingData--; + usedIcon!.text = leftKillingData.ToString(); + + if (leftKillingData <= 0) + { + button.CoolDownTimer!.Start(MyRole.KillCoolDownOption.CurrentCoolDown); + pauseCooldown = false; + killButton.EffectTimer!.SetTime(0f); + } + else + { + killButton.ActivateEffect(); + } + }; + killButton.EffectTimer = Bind(new Timer(1.5f)); + killButton.OnEffectEnd = (button) => { + leftKillingData = 0; + usedIcon!.text = "0"; + button.CoolDownTimer!.Start(MyRole.KillCoolDownOption.CurrentCoolDown); + pauseCooldown = false; + }; + killButton.CoolDownTimer = Bind(new Timer(MyRole.KillCoolDownOption.CurrentCoolDown)).Start(10f); + killButton.SetLabelType(ModAbilityButton.LabelType.Impostor); + killButton.SetLabel("kill"); + usedIcon = killButton.ShowUsesIcon(2); + usedIcon!.text = "0"; + } + } + + public override void LocalUpdate() + { + if(!killButton!.CoolDownTimer!.IsInProcess && !pauseCooldown){ + pauseCooldown = true; + leftKillingData = (int)MyRole.NumOfKillingOption.GetFloat(); + usedIcon!.text = leftKillingData.ToString(); + } + } + } +} \ No newline at end of file diff --git a/NebulaPluginNova/Roles/Neutral/ChainShifter.cs b/NebulaPluginNova/Roles/Neutral/ChainShifter.cs index d7ed6f9c..2ec1dc11 100644 --- a/NebulaPluginNova/Roles/Neutral/ChainShifter.cs +++ b/NebulaPluginNova/Roles/Neutral/ChainShifter.cs @@ -99,7 +99,7 @@ public override void OnMeetingStart() var player = shiftTarget.GetModInfo(); //会議終了時に死亡している相手とはシフトできない - if(player == null || player.IsDead) yield break; + if(player == null/* || player.IsDead*/) yield break; int[] targetArgument = new int[0]; var targetRole = player.Role.Role; @@ -147,7 +147,7 @@ public override void OnMeetingStart() } } - yield return new WaitForSeconds(0.2f); + //yield return new WaitForSeconds(0.2f); yield break; } diff --git a/NebulaPluginNova/Roles/Neutral/Madman.cs b/NebulaPluginNova/Roles/Neutral/Madman.cs new file mode 100644 index 00000000..e40cc273 --- /dev/null +++ b/NebulaPluginNova/Roles/Neutral/Madman.cs @@ -0,0 +1,151 @@ +using Nebula.Roles.Complex; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine.Profiling; + +namespace Nebula.Roles.Neutral; + +// if (IsMySidekick(player)) player.RpcInvokerSetRole(Jackal.MyRole, new int[] { JackalTeamId }).InvokeSingle(); +public class Madman : ConfigurableStandardRole +{ + static public Madman MyRole = new Madman(); + //static public Team MyTeam = new("teams.chainShifter", MyRole.RoleColor, TeamRevealType.OnlyMe); + + public override RoleCategory RoleCategory => RoleCategory.NeutralRole; + + public override string LocalizedName => "madman"; + public override Color RoleColor => new Color(191f / 255f, 0f / 255f, 32f / 255f); + public override Team Team => ChainShifter.MyTeam; + + public override RoleInstance CreateInstance(PlayerModInfo player, int[] arguments) => new Instance(player); + + private KillCoolDownConfiguration killCooldownOption = null!; + private NebulaConfiguration canBeGuessOption = null!; + + protected override void LoadOptions() + { + base.LoadOptions(); + + killCooldownOption = new(RoleConfig, "killCooldown", KillCoolDownConfiguration.KillCoolDownType.Immediate, 2.5f, 2.5f, 60f, -22.5f, 35f, 0.125f, 0.125f, 2f, 17.5f, -7.5f, 0.875f); + canBeGuessOption = new(RoleConfig, "canBeGuess", null, true, true); + } + + public override bool CanBeGuess => canBeGuessOption.GetBool(); + + public class Instance : RoleInstance + { + private ModAbilityButton? killButton = null; + + public override AbstractRole Role => MyRole; + + public Instance(PlayerModInfo player) : base(player) + { + } + + private PlayerControl? shiftTarget = null; + private bool canExecuteShift = false; + + public override void OnActivated() + { + if (AmOwner) + { + PoolablePlayer? shiftIcon = null; + + var killTracker = Bind(ObjectTrackers.ForPlayer(null, MyPlayer.MyControl, (p) => p.PlayerId != MyPlayer.PlayerId && !p.Data.IsDead)); + + killButton = Bind(new ModAbilityButton()).KeyBind(KeyAssignmentType.Kill); + //chainShiftButton.SetSprite(buttonSprite.GetSprite()); + killButton.Availability = (button) => killTracker.CurrentTarget != null && MyPlayer.MyControl.CanMove && shiftTarget == null; + killButton.Visibility = (button) => !MyPlayer.MyControl.Data.IsDead; + killButton.OnClick = (button) => { + PlayerControl.LocalPlayer.ModKill(killTracker.CurrentTarget!, true, PlayerState.Dead, EventDetail.Kill); + shiftTarget = killTracker.CurrentTarget; + shiftIcon = AmongUsUtil.GetPlayerIcon(shiftTarget.GetModInfo()!.DefaultOutfit, killButton!.VanillaButton.transform, new Vector3(-0.4f, 0.35f, -0.5f), new(0.3f, 0.3f)).SetAlpha(0.5f); + }; + killButton.OnMeeting = (button) => + { + if (shiftIcon) GameObject.Destroy(shiftIcon!.gameObject); + shiftIcon = null; + }; + killButton.CoolDownTimer = Bind(new Timer(MyRole.killCooldownOption.CurrentCoolDown).SetAsAbilityCoolDown().Start()); + killButton.SetLabelType(ModAbilityButton.LabelType.Standard); + killButton.SetLabel("kill"); + } + } + + //会議開始時に生きていればシフトは実行されうる + public override void OnMeetingStart() + { + canExecuteShift = !MyPlayer.IsDead; + } + + public override IEnumerator? CoMeetingEnd() + { + if (!canExecuteShift) yield break; + if (shiftTarget == null) yield break; + if (!shiftTarget) yield break; + var player = shiftTarget.GetModInfo(); + + //会議終了時に死亡している相手とはシフトできない + if (player == null/* || player!.IsDead*/) yield break; + + int[] targetArgument = new int[0]; + var targetRole = player.Role.Role; + int targetGuess = -1; + yield return player.CoGetRoleArgument((args) => targetArgument = args); + yield return player.CoGetLeftGuess((guess) => targetGuess = guess); + + int myGuess = MyPlayer.TryGetModifier(out var guesser) ? guesser.LeftGuess : -1; + + using (RPCRouter.CreateSection("ChainShift")) + { + player.RpcInvokerSetRole(MyRole, null).InvokeSingle(); + MyPlayer.RpcInvokerSetRole(targetRole, targetArgument).InvokeSingle(); + + if (targetGuess != -1) player.RpcInvokerUnsetModifier(GuesserModifier.MyRole).InvokeSingle(); + if (myGuess != -1) MyPlayer.RpcInvokerUnsetModifier(GuesserModifier.MyRole).InvokeSingle(); + + if (myGuess != -1) player.RpcInvokerSetModifier(GuesserModifier.MyRole, new int[] { myGuess }).InvokeSingle(); + if (targetGuess != -1) MyPlayer.RpcInvokerSetModifier(GuesserModifier.MyRole, new int[] { targetGuess }).InvokeSingle(); + + int leftCrewmateTask = 0; + if (player.Tasks.IsCrewmateTask) + { + leftCrewmateTask = Mathf.Max(0, player.Tasks.Quota - player.Tasks.TotalCompleted); + + } + + if (leftCrewmateTask > 0) + { + int commonTasks = GameOptionsManager.Instance.CurrentGameOptions.GetInt(AmongUs.GameOptions.Int32OptionNames.NumCommonTasks); + int shortTasks = GameOptionsManager.Instance.CurrentGameOptions.GetInt(AmongUs.GameOptions.Int32OptionNames.NumShortTasks); + int longTasks = GameOptionsManager.Instance.CurrentGameOptions.GetInt(AmongUs.GameOptions.Int32OptionNames.NumLongTasks); + float longWeight = (float)longTasks / (float)(commonTasks + shortTasks + longTasks); + float commonWeight = (float)commonTasks / (float)(commonTasks + shortTasks + longTasks); + + int actualLongTasks = (int)((float)System.Random.Shared.NextDouble() * longWeight * leftCrewmateTask); + int actualcommonTasks = (int)((float)System.Random.Shared.NextDouble() * commonWeight * leftCrewmateTask); + + MyPlayer.Tasks.ReplaceTasksAndRecompute(leftCrewmateTask - actualLongTasks - actualcommonTasks, actualLongTasks, actualcommonTasks); + MyPlayer.Tasks.BecomeToCrewmate(); + } + else + { + MyPlayer.Tasks.ReleaseAllTaskState(); + } + } + + //yield return new WaitForSeconds(0.2f); + + yield break; + } + + public override void OnMeetingEnd() + { + shiftTarget = null; + } + } +}