Skip to content
This repository was archived by the owner on Aug 11, 2025. It is now read-only.

Commit ed26acb

Browse files
committed
1 parent 3090a01 commit ed26acb

9 files changed

Lines changed: 137 additions & 18 deletions

File tree

Nebula/Nebula.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ public class NebulaPlugin : BasePlugin
4343
public const string AmongUsVersion = "2023.3.28";
4444
public const string PluginGuid = "cn.zsfabtest.amongus.nebular";
4545
public const string PluginName = "TheNebula-R-LTS";
46-
public const string PluginVersion = "1.0.4.5";
46+
public const string PluginVersion = "1.0.4.6";
4747
public const bool IsSnapshot = true;
4848

49-
public static string PluginVisualVersion = (IsSnapshot ? "23.08.18-" : "") + PluginVersion;
49+
public static string PluginVisualVersion = (IsSnapshot ? "23.08.17-" : "") + PluginVersion;
5050
public static string PluginStage = IsSnapshot ? "Snapshot" : "";
5151

52-
public const string PluginVersionForFetch = "1.0.4.5";
53-
public byte[] PluginVersionData = new byte[] { 1, 0, 4, 5 };
52+
public const string PluginVersionForFetch = "1.0.4.6";
53+
public byte[] PluginVersionData = new byte[] { 1, 0, 4, 6 };
5454

5555
public static NebulaPlugin Instance;
5656

Nebula/Patches/EndGamePatch.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,8 @@ public PlayerStatistics(ShipStatus __instance)
10811081

10821082
if(data.role == Roles.Roles.Puppeteer) AlivePuppeteer++;
10831083

1084+
if(data.role == Roles.Roles.Infected) AliveInfected++;
1085+
10841086
IsValid = true;
10851087
}
10861088
catch(Exception e)
@@ -1101,7 +1103,7 @@ public PlayerStatistics(ShipStatus __instance)
11011103
AliveOracle = GetAlivePlayers(Roles.Side.Oracle);
11021104
AliveYellowTeam = GetAlivePlayers(Roles.Side.YellowTeam);
11031105
AliveGreenTeam = GetAlivePlayers(Roles.Side.GreenTeam);
1104-
AliveInfected = GetAlivePlayers(Roles.Side.Infected);
1106+
//AliveInfected = GetAlivePlayers(Roles.Side.Infected);
11051107
AliveSurvivals = GetAlivePlayers(Roles.Side.Survival);
11061108

11071109
if (!Roles.Roles.Lover.loversAsIndependentSideOption.getBool())

Nebula/Resources/Languages/SChinese.dat

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2165,10 +2165,17 @@
21652165
"role.gunner.short" : "枪"
21662166
"role.gunner.description" : "击杀<color=#ff1919ff>感染者</color>!"
21672167
"role.gunner.hint" : "击杀<color=#ff1919ff>感染者</color>"
2168-
"role.gunner.info" : "你可以攻击伪装者。\n更重要的是,你只有一次机会(一条命)。"
2168+
"role.gunner.info" : "你可以攻击伪装者。"
21692169
"role.gunner.killcooldown" : "击杀冷却时间"
21702170
"role.gunner.neutrallySpawnCount" : "自然生成的枪手个数"
21712171

2172+
"role.infectedSidekick.name" : "被感染者"
2173+
"role.infectedSidekick.short" : "被"
2174+
"role.infectedSidekick.hint" : "拖住别人的脚步"
2175+
"role.infectedSidekick.info" : "你加入了感染者阵营。\n想办法拖住幸存者们!"
2176+
"role.infectedSidekick.freezecooldown" : "冻结冷却时间"
2177+
"role.infectedSidekick.freezeduring" : "冻结持续时间"
2178+
21722179
"option.display.random" : "随机"
21732180

21742181
"side.paparazzo.name" : "摄影师"
@@ -2246,6 +2253,7 @@
22462253
"button.label.challenge" : "挑战"
22472254
"button.label.releaseSouls" : "超度"
22482255
"button.label.lock" : "上锁"
2256+
"button.label.freeze" : "冻结"
22492257

22502258
"meeting.seb" : "特殊会议"
22512259
"meeting.forbid" : "你不能召开紧急会议"

Nebula/Roles/ExtremeRoles/LuckyMan.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ public override void LoadOptionData()
1414
public override bool OnExiledPost(byte[] voters, byte playerId)
1515
{
1616
if(playerId == PlayerControl.LocalPlayer.PlayerId){
17-
int r = NebulaPlugin.rnd.Next(1,11);
18-
if(r <= (chanceToRevievOption.getFloat() / 10f)) return true;
17+
int r = NebulaPlugin.rnd.Next(1,101);
18+
if(r <= chanceToRevievOption.getFloat()) return true;
1919
}
2020
return false;
2121
}
2222

23+
public override Helpers.MurderAttemptResult OnMurdered(byte murderId,byte playerId){
24+
int r = NebulaPlugin.rnd.Next(1,101);
25+
if(r <= chanceToRevievOption.getFloat()) return Helpers.MurderAttemptResult.SuppressKill;
26+
return Helpers.MurderAttemptResult.PerformKill;
27+
}
28+
2329
public LuckyMan()
2430
: base("LuckyMan","luckyMan",RoleColor,RoleCategory.Crewmate,Side.Crewmate,Side.Crewmate,
2531
Crewmate.crewmateSideSet,Crewmate.crewmateSideSet,Crewmate.crewmateEndSet,

Nebula/Roles/Roles.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ public SideCommonRolesLoader()
230230
public static VirusCrisisRoles.Infected Infected = new();
231231
public static VirusCrisisRoles.Survival Survival = new();
232232
public static VirusCrisisRoles.Gunner Gunner = new();
233+
public static VirusCrisisRoles.InfectedSidekick InfectedSidekick = new();
233234

234235

235236
//全てのロールはこの中に含まれている必要があります
@@ -256,7 +257,7 @@ public SideCommonRolesLoader()
256257
//HnSCleaner,HnSHadar,HnSRaider,HnSReaper
257258

258259
YellowTeam,GreenTeam,
259-
Infected,Survival,Gunner
260+
Infected,Survival,Gunner,InfectedSidekick
260261
};
261262

262263
public static List<ExtraRole> AllExtraRoles = new List<ExtraRole>()

Nebula/Roles/VirusCrisisRoles/Gunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public override void EditDisplayNameColor(byte playerId,ref Color displayColor){
5757
public override void MyPlayerControlUpdate()
5858
{
5959
Game.MyPlayerData data = Game.GameData.data.myData;
60-
data.currentTarget = Patches.PlayerControlPatch.SetMyTarget((p) => { return p.GetModData().role == Roles.Infected; });
60+
data.currentTarget = Patches.PlayerControlPatch.SetMyTarget((p) => { return p.GetModData().role.side == Side.Infected; });
6161
Patches.PlayerControlPatch.SetPlayerOutline(data.currentTarget, Palette.ImpostorRed);
6262
}
6363

Nebula/Roles/VirusCrisisRoles/Infected.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ public override void LoadOptionData(){
1414
TopOption.AddCustomPrerequisite(() => { return CustomOptionHolder.gameModeNormal.getSelection() == 3; });
1515
InitKillCooldown = CreateOption(Color.white,"initkillcooldown",15f,2.5f,45f,2.5f);
1616
InitKillCooldown.suffix = "second";
17-
killCooldown = CreateOption(Color.white,"killcooldown",7.5f,2.5f,45f,2.5f);
17+
killCooldown = CreateOption(Color.white,"killcooldown",25f,10f,45f,2.5f);
1818
killCooldown.suffix = "second";
19-
lives = CreateOption(Color.white,"totalLives",6f,1f,40f,1f);
19+
lives = CreateOption(Color.white,"totalLives",3f,1f,10f,1f);
2020
}
2121

2222
public int TotalLives;
@@ -41,14 +41,17 @@ public override void ButtonInitialize(HudManager __instance)
4141
killButton = new CustomButton(
4242
() =>
4343
{
44-
if(Game.GameData.data.myData.currentTarget.GetModData().role != Roles.Survival || Game.GameData.data.myData.currentTarget.GetModData().extraRole.Contains(Roles.Supportee)) Helpers.checkMuderAttemptAndKill(PlayerControl.LocalPlayer, Game.GameData.data.myData.currentTarget, Game.PlayerData.PlayerStatus.Dead, true);
44+
if(Game.GameData.data.myData.currentTarget.GetModData().extraRole.Contains(Roles.Supportee)){
45+
RPCEventInvoker.ImmediatelyChangeRole(Game.GameData.data.myData.currentTarget, Roles.InfectedSidekick);
46+
RPCEventInvoker.ImmediatelyUnsetExtraRole(PlayerControl.LocalPlayer,Roles.Supportee);
47+
} //Helpers.checkMuderAttemptAndKill(PlayerControl.LocalPlayer, Game.GameData.data.myData.currentTarget, Game.PlayerData.PlayerStatus.Dead, true);
4548
else{
4649
RPCEventInvoker.SetExtraRole(Game.GameData.data.myData.currentTarget,Roles.Supportee,0);
4750
Game.GameData.data.myData.currentTarget.ShowFailedMurder();
4851
}
4952
killButton.Timer = killButton.MaxTimer;
5053
},
51-
() => { return !PlayerControl.LocalPlayer.Data.IsDead && Roles.SchrodingersCat.canUseKillButton.getBool(); },
54+
() => { return !PlayerControl.LocalPlayer.Data.IsDead; },
5255
() => { return Game.GameData.data.myData.currentTarget && PlayerControl.LocalPlayer.CanMove; },
5356
() => { killButton.Timer = killButton.MaxTimer; },
5457
__instance.KillButton.graphic.sprite,
@@ -88,7 +91,7 @@ public override void EditDisplayName(byte playerId, ref string displayName, bool
8891

8992
public Infected() : base("Infected","infected",Palette.ImpostorRed,RoleCategory.Neutral,Side.Infected,Side.Infected,
9093
new HashSet<Side>() { Side.Infected },new HashSet<Side>() { Side.Infected },new HashSet<Patches.EndCondition> { Patches.EndCondition.InfectedWin },
91-
false,VentPermission.CanNotUse,false,true,true){
94+
true,VentPermission.CanNotUse,false,true,true){
9295
//IsHideRole = true;
9396
Allocation = AllocationType.None;
9497
ValidGamemode = Module.CustomGameMode.VirusCrisis;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
namespace Nebula.Roles.VirusCrisisRoles;
2+
3+
public class InfectedSidekick : Role{
4+
private Module.CustomOption freezeCooldown;
5+
private Module.CustomOption freezeDuring;
6+
7+
public override bool IsSpawnable(){
8+
return CustomOptionHolder.gameModeNormal.getSelection() == 3;
9+
}
10+
11+
public override void LoadOptionData(){
12+
TopOption.tab = Module.CustomOptionTab.ImpostorRoles;
13+
TopOption.AddCustomPrerequisite(() => { return CustomOptionHolder.gameModeNormal.getSelection() == 3; });
14+
freezeCooldown = CreateOption(Color.white,"freezecooldown",7.5f,2.5f,25f,2.5f);
15+
freezeCooldown.suffix = "second";
16+
freezeDuring = CreateOption(Color.white,"freezeduring",2.5f,1f,5f,0.5f);
17+
freezeDuring.suffix = "second";
18+
}
19+
20+
//public int TotalLives;
21+
22+
private SpriteLoader buttonSprite = new("Nebula.Resources.ChainShiftButton.png",115f);
23+
24+
/*
25+
public override void Initialize(PlayerControl __instance){
26+
RPCEventInvoker.SetInfectLives((byte)(int)lives.getFloat());
27+
}
28+
*/
29+
30+
/*
31+
public override Helpers.MurderAttemptResult OnMurdered(byte murderId,byte playerId){
32+
//Helpers.RoleAction(Helpers.playerById(playerId),(role) => { role.OnMeetingStart(); });
33+
RPCEventInvoker.SetInfectLives((byte)(Roles.Infected.TotalLives - 1));
34+
return Helpers.MurderAttemptResult.SuppressKill;
35+
}
36+
*/
37+
38+
private CustomButton freeze;
39+
public override void ButtonInitialize(HudManager __instance)
40+
{
41+
if(freeze != null)
42+
{
43+
freeze.Destroy();
44+
}
45+
freeze = new CustomButton(
46+
() =>
47+
{
48+
RPCEventInvoker.EmitSpeedFactor(Game.GameData.data.myData.currentTarget,new Game.SpeedFactor(255, freezeDuring.getFloat(), 0.1f, true));
49+
freeze.Timer = freeze.MaxTimer;
50+
},
51+
() => { return !PlayerControl.LocalPlayer.Data.IsDead; },
52+
() => { return Game.GameData.data.myData.currentTarget && PlayerControl.LocalPlayer.CanMove; },
53+
() => { freeze.Timer = freeze.MaxTimer; },
54+
buttonSprite.GetSprite(),
55+
Expansion.GridArrangeExpansion.GridArrangeParameter.AlternativeKillButtonContent,
56+
__instance,
57+
Module.NebulaInputManager.abilityInput.keyCode,
58+
"button.label.freeze"
59+
).SetTimer(freezeCooldown.getFloat());
60+
freeze.MaxTimer = freezeCooldown.getFloat();
61+
//killButton.SetButtonCoolDownOption(true);
62+
}
63+
64+
public override void CleanUp(){
65+
if(freeze != null){
66+
freeze.Destroy();
67+
freeze = null;
68+
}
69+
}
70+
71+
public override void MyPlayerControlUpdate()
72+
{
73+
Game.MyPlayerData data = Game.GameData.data.myData;
74+
data.currentTarget = Patches.PlayerControlPatch.SetMyTarget();
75+
Patches.PlayerControlPatch.SetPlayerOutline(data.currentTarget, Palette.ImpostorRed);
76+
//if(TotalLives <= 0 && !PlayerControl.LocalPlayer.Data.IsDead) RPCEventInvoker.UncheckedMurderPlayer(PlayerControl.LocalPlayer.PlayerId,PlayerControl.LocalPlayer.PlayerId,Game.PlayerData.PlayerStatus.Dead.Id,false);
77+
}
78+
79+
public override void EditDisplayNameColor(byte playerId,ref Color displayColor){
80+
displayColor = Color;
81+
}
82+
83+
/*
84+
public override void EditDisplayName(byte playerId, ref string displayName, bool hideFlag)
85+
{
86+
displayName += " " + TotalLives.ToString() + "♥";
87+
}
88+
*/
89+
90+
public InfectedSidekick() : base("InfectedSidekick","infectedSidekick",Palette.ImpostorRed,RoleCategory.Neutral,Side.Infected,Side.Infected,
91+
new HashSet<Side>() { Side.Infected },new HashSet<Side>() { Side.Infected },new HashSet<Patches.EndCondition> { Patches.EndCondition.InfectedWin },
92+
true,VentPermission.CanUseUnlimittedVent,true,true,true){
93+
//IsHideRole = true;
94+
Allocation = AllocationType.None;
95+
ValidGamemode = Module.CustomGameMode.VirusCrisis;
96+
canReport = false;
97+
CanCallEmergencyMeeting = false;
98+
freeze = null;
99+
}
100+
}

Nebula/Roles/VirusCrisisRoles/Survival.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ public override void Initialize(PlayerControl __instance){
1919

2020
public override void OnTaskComplete(PlayerTask? task){
2121
if(Game.GameData.data.myData.getGlobalData().Tasks.Completed < taskCount.getFloat()) return;
22-
if(PlayerControl.LocalPlayer.GetModData().extraRole.Contains(Roles.Supportee)){
23-
RPCEventInvoker.ImmediatelyUnsetExtraRole(PlayerControl.LocalPlayer,Roles.Supportee);
24-
}
22+
//if(PlayerControl.LocalPlayer.GetModData().extraRole.Contains(Roles.Supportee)){
23+
RPCEventInvoker.ImmediatelyUnsetExtraRole(PlayerControl.LocalPlayer,Roles.Supportee);
2524
RPCEventInvoker.ImmediatelyChangeRole(PlayerControl.LocalPlayer,Roles.Gunner);
2625
}
2726

0 commit comments

Comments
 (0)