mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
763 lines
51 KiB
C#
763 lines
51 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using AmongUs.GameOptions;
|
|
using HarmonyLib;
|
|
using UnityEngine;
|
|
using Random = UnityEngine.Random;
|
|
|
|
/*
|
|
* Earthquake: <size=150%><font="VCR SDF"><line-height=72%><#000000>█<#000000>█<#5e5e5e>█<#adadad>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><#5e5e5e>█<#000000>█<#5e5e5e>█<#adadad>█<#adadad>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><#5e5e5e>█<#000000>█<#000000>█<#5e5e5e>█<#5e5e5e>█<#adadad>█<#adadad>█<alpha=#00>█<br><#adadad>█<#5e5e5e>█<#000000>█<#000000>█<#000000>█<#5e5e5e>█<#5e5e5e>█<#adadad>█<br><alpha=#00>█<#adadad>█<#5e5e5e>█<#5e5e5e>█<#000000>█<#000000>█<#000000>█<#5e5e5e>█<br><alpha=#00>█<alpha=#00>█<#adadad>█<#adadad>█<#5e5e5e>█<#5e5e5e>█<#000000>█<#000000>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<#adadad>█<#adadad>█<#5e5e5e>█<#000000>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<#adadad>█<#5e5e5e>█<#000000>█<br></line-height></size>
|
|
* Meteor: <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<alpha=#00>█<alpha=#00>█<#fff700>█<#fff700>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#fff700>█<#ffae00>█<#ffae00>█<#fff700>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<#fff700>█<#ffae00>█<#ff6f00>█<#ff6f00>█<#ffae00>█<#fff700>█<alpha=#00>█<br><#fff700>█<#ffae00>█<#ff6f00>█<#ff1100>█<#ff1100>█<#ff6f00>█<#ffae00>█<#fff700>█<br><#fff700>█<#ffae00>█<#ff6f00>█<#ff1100>█<#ff1100>█<#ff6f00>█<#ffae00>█<#fff700>█<br><alpha=#00>█<#fff700>█<#ffae00>█<#ff6f00>█<#ff6f00>█<#ffae00>█<#fff700>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#fff700>█<#ffae00>█<#ffae00>█<#fff700>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<#fff700>█<#fff700>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br></line-height></size>
|
|
* Volcano Eruption:
|
|
* 1. <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#ff6200>█<#ff6200>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#ff6200>█<#ff6200>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br></line-height></size>
|
|
* 2. <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<alpha=#00>█<br><alpha=#00>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<alpha=#00>█<br><alpha=#00>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<alpha=#00>█<br><alpha=#00>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br></line-height></size>
|
|
* 3. <size=150%><font="VCR SDF"><line-height=72%><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br></line-height></size>
|
|
* 4. <size=150%><font="VCR SDF"><line-height=72%><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br><#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<#ff6200>█<br></line-height></size>
|
|
* Tornado: <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<alpha=#00>█<#dbdbdb>█<#dbdbdb>█<#dbdbdb>█<#dbdbdb>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<#dbdbdb>█<#b0b0b0>█<#b0b0b0>█<#b0b0b0>█<#b0b0b0>█<#dbdbdb>█<alpha=#00>█<br><#dbdbdb>█<#b0b0b0>█<#b0b0b0>█<#828282>█<#828282>█<#b0b0b0>█<#b0b0b0>█<#dbdbdb>█<br><#dbdbdb>█<#b0b0b0>█<#828282>█<#474747>█<#474747>█<#828282>█<#b0b0b0>█<#dbdbdb>█<br><#dbdbdb>█<#b0b0b0>█<#828282>█<#474747>█<#474747>█<#828282>█<#b0b0b0>█<#dbdbdb>█<br><#dbdbdb>█<#b0b0b0>█<#b0b0b0>█<#828282>█<#828282>█<#b0b0b0>█<#b0b0b0>█<#dbdbdb>█<br><alpha=#00>█<#dbdbdb>█<#b0b0b0>█<#b0b0b0>█<#b0b0b0>█<#b0b0b0>█<#dbdbdb>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#dbdbdb>█<#dbdbdb>█<#dbdbdb>█<#dbdbdb>█<alpha=#00>█<alpha=#00>█<br></line-height></size>
|
|
* Thunderstorm strike: <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<#c6c7c3>█<br><alpha=#00>█<#c6c7c3>█<alpha=#00>█<alpha=#00>█<#c6c7c3>█<alpha=#00>█<br><#c6c7c3>█<alpha=#00>█<#fffb00>█<#fffb00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#fffb00>█<#fffb00>█<alpha=#00>█<#c6c7c3>█<br><#c6c7c3>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#c6c7c3>█<#c6c7c3>█<alpha=#00>█<alpha=#00>█<br></line-height></size>
|
|
* Sandstorm: <size=150%><font="VCR SDF"><line-height=72%><alpha=#00>█<#cf935f>█<#ffd3c2>█<alpha=#00>█<alpha=#00>█<#cf935f>█<#ffd3c2>█<alpha=#00>█<br><alpha=#00>█<#ffd3c2>█<alpha=#00>█<#cf935f>█<#ffd3c2>█<alpha=#00>█<alpha=#00>█<#cf935f>█<br><#cf935f>█<alpha=#00>█<#ffd3c2>█<#ffd3c2>█<alpha=#00>█<#cf935f>█<alpha=#00>█<alpha=#00>█<br><#ffd3c2>█<#ffd3c2>█<#cf935f>█<#ffd3c2>█<alpha=#00>█<alpha=#00>█<#ffd3c2>█<#cf935f>█<br><alpha=#00>█<alpha=#00>█<#ffd3c2>█<alpha=#00>█<#cf935f>█<#ffd3c2>█<alpha=#00>█<#ffd3c2>█<br><#ffd3c2>█<#cf935f>█<alpha=#00>█<#ffd3c2>█<alpha=#00>█<#ffd3c2>█<#cf935f>█<alpha=#00>█<br><alpha=#00>█<alpha=#00>█<#ffd3c2>█<#cf935f>█<alpha=#00>█<alpha=#00>█<alpha=#00>█<#ffd3c2>█<br><#cf935f>█<#ffd3c2>█<alpha=#00>█<alpha=#00>█<#ffd3c2>█<#cf935f>█<alpha=#00>█<#cf935f>█<br></line-height></size>
|
|
* Tsunami:
|
|
* Left to right: <size=150%><font="VCR SDF"><line-height=72%><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br><#0073ff>█<#0095ff>█<#00ccff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<br></line-height></size>
|
|
* Right to left: <size=150%><font="VCR SDF"><line-height=72%><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br><#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#9ce8ff>█<#00ccff>█<#0095ff>█<#0073ff>█<br></line-height></size>
|
|
* Top to bottom: <size=150%><font="VCR SDF"><line-height=72%><#003cff>█<#003cff>█<#003cff>█<#003cff>█<#003cff>█<#003cff>█<#003cff>█<#003cff>█<br><#006aff>█<#006aff>█<#006aff>█<#006aff>█<#006aff>█<#006aff>█<#006aff>█<#006aff>█<br><#00bbff>█<#00bbff>█<#00bbff>█<#00bbff>█<#00bbff>█<#00bbff>█<#00bbff>█<#00bbff>█<br><#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<br><#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<br><#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<br><#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<br><#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<#b8e1ff>█<br></line-height></size>
|
|
* Bottom to top: <size=150%><font="VCR SDF"><line-height=72%><#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<br><#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<br><#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<br><#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<br><#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<#c2e2ff>█<br><#00bfff>█<#00bfff>█<#00bfff>█<#00bfff>█<#00bfff>█<#00bfff>█<#00bfff>█<#00bfff>█<br><#007bff>█<#007bff>█<#007bff>█<#007bff>█<#007bff>█<#007bff>█<#007bff>█<#007bff>█<br><#0033ff>█<#0033ff>█<#0033ff>█<#0033ff>█<#0033ff>█<#0033ff>█<#0033ff>█<#0033ff>█<br></line-height></size>
|
|
* Sinkhole: <size=150%><font="VCR SDF"><line-height=72%><#7d7d7d>█<#7d7d7d>█<#545454>█<#7d7d7d>█<#7d7d7d>█<#7d7d7d>█<#7d7d7d>█<#545454>█<br><#545454>█<#424242>█<#424242>█<#424242>█<#424242>█<#424242>█<#424242>█<#7d7d7d>█<br><#7d7d7d>█<#424242>█<#000000>█<#000000>█<#000000>█<#000000>█<#424242>█<#7d7d7d>█<br><#545454>█<#424242>█<#000000>█<#000000>█<#000000>█<#000000>█<#424242>█<#7d7d7d>█<br><#7d7d7d>█<#424242>█<#000000>█<#000000>█<#000000>█<#000000>█<#424242>█<#545454>█<br><#545454>█<#424242>█<#000000>█<#000000>█<#000000>█<#000000>█<#424242>█<#7d7d7d>█<br><#7d7d7d>█<#424242>█<#424242>█<#424242>█<#424242>█<#424242>█<#424242>█<#7d7d7d>█<br><#545454>█<#545454>█<#7d7d7d>█<#7d7d7d>█<#545454>█<#7d7d7d>█<#7d7d7d>█<#545454>█<br></line-height></size>
|
|
*/
|
|
|
|
namespace EHR
|
|
{
|
|
public static class NaturalDisasters
|
|
{
|
|
private const float Range = 1.5f;
|
|
private static List<Type> AllDisasters = [];
|
|
private static readonly List<Disaster> ActiveDisasters = [];
|
|
private static readonly List<NaturalDisaster> PreparingDisasters = [];
|
|
|
|
private static ((float Left, float Right) X, (float Top, float Bottom) Y) MapBounds;
|
|
|
|
private static OptionItem DisasterFrequency;
|
|
private static OptionItem DisasterWarningTime;
|
|
|
|
public static void SetupCustomOption()
|
|
{
|
|
const int id = 69_216_001;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
DisasterFrequency = new IntegerOptionItem(id, "ND_DisasterFrequency", new(1, 20, 1), 2, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
DisasterWarningTime = new IntegerOptionItem(id + 1, "ND_DisasterWarningTime", new(1, 30, 1), 5, TabGroup.GameSettings)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
AllDisasters = Assembly.GetExecutingAssembly()
|
|
.GetTypes()
|
|
.Where(x => x.IsClass && !x.IsAbstract && x.IsSubclassOf(typeof(Disaster)))
|
|
.ToList();
|
|
|
|
AllDisasters.ForEach(x => x.GetMethod("SetupOwnCustomOption")?.Invoke(null, null));
|
|
}
|
|
|
|
public static void OnGameStart()
|
|
{
|
|
ActiveDisasters.Clear();
|
|
PreparingDisasters.Clear();
|
|
Sinkhole.Sinkholes.Clear();
|
|
BuildingCollapse.CollapsedRooms.Clear();
|
|
BuildingCollapse.LastPosition.Clear();
|
|
|
|
if (Options.CurrentGameMode != CustomGameMode.NaturalDisasters) return;
|
|
|
|
var rooms = Main.CurrentMap switch
|
|
{
|
|
MapNames.Skeld => new RandomSpawn.SkeldSpawnMap().positions.Values,
|
|
MapNames.Mira => new RandomSpawn.MiraHQSpawnMap().positions.Values,
|
|
MapNames.Polus => new RandomSpawn.PolusSpawnMap().positions.Values,
|
|
MapNames.Dleks => new RandomSpawn.DleksSpawnMap().positions.Values,
|
|
MapNames.Airship => new RandomSpawn.AirshipSpawnMap().positions.Values,
|
|
MapNames.Fungle => new RandomSpawn.FungleSpawnMap().positions.Values,
|
|
_ => null
|
|
};
|
|
if (rooms == null) return;
|
|
|
|
var x = rooms.Select(r => r.x).ToArray();
|
|
var y = rooms.Select(r => r.y).ToArray();
|
|
|
|
const float extend = 2.5f;
|
|
MapBounds = ((x.Min() - extend, x.Max() + extend), (y.Min() - extend, y.Max() + extend));
|
|
}
|
|
|
|
public static void ApplyGameOptions(IGameOptions opt, byte id)
|
|
{
|
|
ActiveDisasters.ForEach(x => x.ApplyOwnGameOptions(opt, id));
|
|
}
|
|
|
|
public static string GetSuffixText() // TODO: implement this
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
public static int GetSurvivalTime(byte id) // TODO: implement this
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
public static Color DeathReasonColor(PlayerState.DeathReason deathReason) => deathReason switch
|
|
{
|
|
PlayerState.DeathReason.Meteor => Color.red,
|
|
PlayerState.DeathReason.Lava => Palette.Orange,
|
|
PlayerState.DeathReason.Tornado => Color.gray,
|
|
PlayerState.DeathReason.Lightning => Palette.White_75Alpha,
|
|
PlayerState.DeathReason.Drowned => Color.cyan,
|
|
PlayerState.DeathReason.Sunken => Color.yellow,
|
|
PlayerState.DeathReason.Collapsed => Palette.Brown,
|
|
_ => Color.white
|
|
};
|
|
|
|
private static string Sprite(string name) => name switch
|
|
{
|
|
"Earthquake" => "<size=150%><font=\"VCR SDF\"><line-height=72%><#000000>\u2588<#000000>\u2588<#5e5e5e>\u2588<#adadad>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#5e5e5e>\u2588<#000000>\u2588<#5e5e5e>\u2588<#adadad>\u2588<#adadad>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#5e5e5e>\u2588<#000000>\u2588<#000000>\u2588<#5e5e5e>\u2588<#5e5e5e>\u2588<#adadad>\u2588<#adadad>\u2588<alpha=#00>\u2588<br><#adadad>\u2588<#5e5e5e>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#5e5e5e>\u2588<#5e5e5e>\u2588<#adadad>\u2588<br><alpha=#00>\u2588<#adadad>\u2588<#5e5e5e>\u2588<#5e5e5e>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#5e5e5e>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#adadad>\u2588<#adadad>\u2588<#5e5e5e>\u2588<#5e5e5e>\u2588<#000000>\u2588<#000000>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#adadad>\u2588<#adadad>\u2588<#5e5e5e>\u2588<#000000>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#adadad>\u2588<#5e5e5e>\u2588<#000000>\u2588<br></line-height></size>",
|
|
"Meteor" => "<size=150%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#fff700>\u2588<#fff700>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#fff700>\u2588<#ffae00>\u2588<#ffae00>\u2588<#fff700>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#fff700>\u2588<#ffae00>\u2588<#ff6f00>\u2588<#ff6f00>\u2588<#ffae00>\u2588<#fff700>\u2588<alpha=#00>\u2588<br><#fff700>\u2588<#ffae00>\u2588<#ff6f00>\u2588<#ff1100>\u2588<#ff1100>\u2588<#ff6f00>\u2588<#ffae00>\u2588<#fff700>\u2588<br><#fff700>\u2588<#ffae00>\u2588<#ff6f00>\u2588<#ff1100>\u2588<#ff1100>\u2588<#ff6f00>\u2588<#ffae00>\u2588<#fff700>\u2588<br><alpha=#00>\u2588<#fff700>\u2588<#ffae00>\u2588<#ff6f00>\u2588<#ff6f00>\u2588<#ffae00>\u2588<#fff700>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#fff700>\u2588<#ffae00>\u2588<#ffae00>\u2588<#fff700>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#fff700>\u2588<#fff700>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>",
|
|
"VolcanoEruption" => "<size=150%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>",
|
|
"Tornado" => "<size=150%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#dbdbdb>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<alpha=#00>\u2588<br><#dbdbdb>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#828282>\u2588<#828282>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<br><#dbdbdb>\u2588<#b0b0b0>\u2588<#828282>\u2588<#474747>\u2588<#474747>\u2588<#828282>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<br><#dbdbdb>\u2588<#b0b0b0>\u2588<#828282>\u2588<#474747>\u2588<#474747>\u2588<#828282>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<br><#dbdbdb>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#828282>\u2588<#828282>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<br><alpha=#00>\u2588<#dbdbdb>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#b0b0b0>\u2588<#dbdbdb>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<#dbdbdb>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>",
|
|
"Sandstorm" => "<size=150%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#cf935f>\u2588<br><#cf935f>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<#cf935f>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><#ffd3c2>\u2588<#ffd3c2>\u2588<#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<#cf935f>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<br><#ffd3c2>\u2588<#cf935f>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<#cf935f>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<#cf935f>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<br><#cf935f>\u2588<#ffd3c2>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#ffd3c2>\u2588<#cf935f>\u2588<alpha=#00>\u2588<#cf935f>\u2588<br></line-height></size>",
|
|
"Tsunami" => Tsunami.Sprites[Enum.GetValues<Tsunami.MovingDirection>().RandomElement()],
|
|
"Sinkhole" => "<size=150%><font=\"VCR SDF\"><line-height=72%><#7d7d7d>\u2588<#7d7d7d>\u2588<#545454>\u2588<#7d7d7d>\u2588<#7d7d7d>\u2588<#7d7d7d>\u2588<#7d7d7d>\u2588<#545454>\u2588<br><#545454>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#7d7d7d>\u2588<br><#7d7d7d>\u2588<#424242>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#424242>\u2588<#7d7d7d>\u2588<br><#545454>\u2588<#424242>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#424242>\u2588<#7d7d7d>\u2588<br><#7d7d7d>\u2588<#424242>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#424242>\u2588<#545454>\u2588<br><#545454>\u2588<#424242>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#000000>\u2588<#424242>\u2588<#7d7d7d>\u2588<br><#7d7d7d>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#424242>\u2588<#7d7d7d>\u2588<br><#545454>\u2588<#545454>\u2588<#7d7d7d>\u2588<#7d7d7d>\u2588<#545454>\u2588<#7d7d7d>\u2588<#7d7d7d>\u2588<#545454>\u2588<br></line-height></size>",
|
|
_ => string.Empty
|
|
};
|
|
|
|
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))]
|
|
static class FixedUpdatePatch
|
|
{
|
|
private static long LastDisaster = Utils.TimeStamp;
|
|
|
|
public static void Postfix(PlayerControl __instance)
|
|
{
|
|
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.NaturalDisasters || Main.HasJustStarted || !__instance.IsHost()) return;
|
|
|
|
foreach (NaturalDisaster naturalDisaster in PreparingDisasters.ToArray())
|
|
{
|
|
naturalDisaster.Update();
|
|
if (float.IsNaN(naturalDisaster.SpawnTimer))
|
|
{
|
|
var type = AllDisasters.Find(d => d.Name == naturalDisaster.DisasterName);
|
|
Activator.CreateInstance(type, naturalDisaster.Position, naturalDisaster);
|
|
PreparingDisasters.Remove(naturalDisaster);
|
|
}
|
|
}
|
|
|
|
ActiveDisasters.ForEach(x => x.Update());
|
|
Sinkhole.OnFixedUpdate();
|
|
BuildingCollapse.OnFixedUpdate();
|
|
|
|
if (Utils.TimeStamp - LastDisaster >= DisasterFrequency.GetInt())
|
|
{
|
|
LastDisaster = Utils.TimeStamp;
|
|
var disaster = AllDisasters.RandomElement();
|
|
var position = new Vector2(Random.Range(MapBounds.X.Left, MapBounds.X.Right), Random.Range(MapBounds.Y.Top, MapBounds.Y.Bottom));
|
|
PreparingDisasters.Add(new(position, DisasterWarningTime.GetFloat(), Sprite(disaster.Name), disaster.Name));
|
|
}
|
|
}
|
|
}
|
|
|
|
abstract class Disaster
|
|
{
|
|
protected Disaster(Vector2 position)
|
|
{
|
|
Position = position;
|
|
ActiveDisasters.Add(this);
|
|
}
|
|
|
|
private long StartTimeStamp { get; } = Utils.TimeStamp;
|
|
protected Vector2 Position { get; set; }
|
|
protected NaturalDisaster NetObject { get; init; } = null;
|
|
protected virtual int Duration { get; set; } = 0;
|
|
|
|
protected virtual bool RemoveIfExpired()
|
|
{
|
|
if (Duration == 0 || Utils.TimeStamp - StartTimeStamp >= Duration)
|
|
{
|
|
ActiveDisasters.Remove(this);
|
|
NetObject.Despawn();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public abstract void Update();
|
|
|
|
public virtual void ApplyOwnGameOptions(IGameOptions opt, byte id)
|
|
{
|
|
}
|
|
}
|
|
|
|
sealed class Earthquake : Disaster
|
|
{
|
|
private static OptionItem DurationOpt;
|
|
private static OptionItem Speed;
|
|
|
|
public Earthquake(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
}
|
|
|
|
protected override int Duration { get; set; } = DurationOpt.GetInt();
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_100;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
DurationOpt = new IntegerOptionItem(id, "ND_Earthquake.DurationOpt", new(1, 120, 1), 30, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
Speed = new FloatOptionItem(id + 1, "ND_Earthquake.Speed", new(0.05f, 2f, 0.05f), 0.2f, TabGroup.GameSettings)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Multiplier);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (Vector2.Distance(pc.Pos(), this.Position) <= Range)
|
|
{
|
|
float speed = Speed.GetFloat();
|
|
if (Mathf.Approximately(Main.AllPlayerSpeed[pc.PlayerId], speed)) continue;
|
|
Main.AllPlayerSpeed[pc.PlayerId] = speed;
|
|
pc.MarkDirtySettings();
|
|
}
|
|
else
|
|
{
|
|
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
|
if (Mathf.Approximately(Main.AllPlayerSpeed[pc.PlayerId], speed)) continue;
|
|
Main.AllPlayerSpeed[pc.PlayerId] = speed;
|
|
pc.MarkDirtySettings();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override bool RemoveIfExpired()
|
|
{
|
|
if (base.RemoveIfExpired())
|
|
{
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
float speed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
|
if (Mathf.Approximately(Main.AllPlayerSpeed[pc.PlayerId], speed)) continue;
|
|
Main.AllPlayerSpeed[pc.PlayerId] = speed;
|
|
pc.MarkDirtySettings();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
sealed class Meteor : Disaster
|
|
{
|
|
public Meteor(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (Vector2.Distance(pc.Pos(), this.Position) <= Range)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Meteor);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override int Duration { get; set; } = 5;
|
|
|
|
public override void Update()
|
|
{
|
|
RemoveIfExpired();
|
|
}
|
|
}
|
|
|
|
sealed class VolcanoEruption : Disaster
|
|
{
|
|
private const int Phases = 4;
|
|
private static OptionItem FlowStepDelay;
|
|
private static OptionItem DurationAfterFlowComplete;
|
|
|
|
private int Phase = 1;
|
|
private float Timer;
|
|
|
|
public VolcanoEruption(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
}
|
|
|
|
protected override int Duration { get; set; } = (int)((Phases - 1) * FlowStepDelay.GetFloat()) + DurationAfterFlowComplete.GetInt();
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_200;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
FlowStepDelay = new FloatOptionItem(id, "ND_VolcanoEruption.FlowStepDelay", new(0.5f, 5f, 0.5f), 1f, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
DurationAfterFlowComplete = new IntegerOptionItem(id + 1, "ND_VolcanoEruption.DurationAfterFlowComplete", new(1, 120, 1), 10, TabGroup.GameSettings)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
Timer += Time.deltaTime;
|
|
if (Timer >= FlowStepDelay.GetFloat())
|
|
{
|
|
Timer = 0f;
|
|
Phase++;
|
|
if (Phase > Phases) return;
|
|
|
|
var newSprite = Phase switch
|
|
{
|
|
2 => "<size=150%><font=\"VCR SDF\"><line-height=72%><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>",
|
|
3 => "<size=150%><font=\"VCR SDF\"><line-height=72%><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br></line-height></size>",
|
|
4 => "<size=150%><font=\"VCR SDF\"><line-height=72%><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br><#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<#ff6200>\u2588<br></line-height></size>",
|
|
_ => string.Empty
|
|
};
|
|
|
|
this.NetObject.RpcChangeSprite(newSprite);
|
|
}
|
|
|
|
var range = Range - (Phases - Phase) * 0.25f;
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (Vector2.Distance(pc.Pos(), this.Position) <= range)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Lava);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class Tornado : Disaster
|
|
{
|
|
private static OptionItem DurationOpt;
|
|
private float Angle = Random.Range(0, 2 * Mathf.PI);
|
|
private int Count = 2;
|
|
|
|
private long LastAngleChange = Utils.TimeStamp;
|
|
|
|
public Tornado(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
}
|
|
|
|
protected override int Duration { get; set; } = DurationOpt.GetInt();
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_300;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
DurationOpt = new IntegerOptionItem(id, "ND_Tornado.DurationOpt", new(1, 120, 1), 40, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
const float eyeRange = Range / 3f;
|
|
const float dragRange = Range * 1.5f;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
var pos = pc.Pos();
|
|
switch (Vector2.Distance(pos, this.Position))
|
|
{
|
|
case <= eyeRange:
|
|
pc.Suicide(PlayerState.DeathReason.Tornado);
|
|
continue;
|
|
case <= dragRange:
|
|
Vector2 direction = (this.Position - pos).normalized;
|
|
Vector2 newPosition = pos + direction * 0.1f;
|
|
pc.TP(newPosition);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (Count++ < 3) return;
|
|
Count = 0;
|
|
|
|
float angle;
|
|
long now = Utils.TimeStamp;
|
|
if (LastAngleChange + 7 <= now)
|
|
{
|
|
angle = Random.Range(0, 2 * Mathf.PI);
|
|
LastAngleChange = now;
|
|
Angle = angle;
|
|
}
|
|
else angle = Angle;
|
|
|
|
Vector2 newPos = this.Position + new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)) * 0.1f;
|
|
|
|
this.Position = newPos;
|
|
this.NetObject.TP(this.Position);
|
|
}
|
|
}
|
|
|
|
sealed class Thunderstorm : Disaster
|
|
{
|
|
private static OptionItem HitFrequency;
|
|
private static OptionItem DurationOpt;
|
|
|
|
private long LastHit;
|
|
|
|
public Thunderstorm(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
|
|
naturalDisaster.Despawn();
|
|
}
|
|
|
|
protected override int Duration { get; set; } = DurationOpt.GetInt();
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_400;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
DurationOpt = new IntegerOptionItem(id, "ND_Thunderstorm.DurationOpt", new(1, 20, 1), 20, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
HitFrequency = new IntegerOptionItem(id + 1, "ND_Thunderstorm.HitFrequency", new(1, 20, 1), 3, TabGroup.GameSettings)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
long now = Utils.TimeStamp;
|
|
if (now - LastHit >= HitFrequency.GetInt())
|
|
{
|
|
LastHit = now;
|
|
var hit = new Vector2(Random.Range(MapBounds.X.Left, MapBounds.X.Right), Random.Range(MapBounds.Y.Bottom, MapBounds.Y.Top));
|
|
_ = new Lightning(hit);
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (pc.GetPlainShipRoom() != default) continue;
|
|
if (Vector2.Distance(pc.Pos(), hit) <= Range)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Lightning);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class SandStorm : Disaster
|
|
{
|
|
private static OptionItem DurationOpt;
|
|
private static OptionItem Vision;
|
|
|
|
private readonly HashSet<byte> AffectedPlayers = [];
|
|
|
|
public SandStorm(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
}
|
|
|
|
protected override int Duration { get; set; } = DurationOpt.GetInt();
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_500;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
DurationOpt = new IntegerOptionItem(id, "ND_SandStorm.DurationOpt", new(1, 120, 1), 30, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Seconds);
|
|
|
|
Vision = new FloatOptionItem(id + 1, "ND_SandStorm.Vision", new(0f, 1f, 0.05f), 0.2f, TabGroup.GameSettings)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Multiplier);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if ((Vector2.Distance(pc.Pos(), this.Position) <= Range && AffectedPlayers.Add(pc.PlayerId)) || AffectedPlayers.Remove(pc.PlayerId))
|
|
{
|
|
pc.MarkDirtySettings();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override bool RemoveIfExpired()
|
|
{
|
|
if (base.RemoveIfExpired())
|
|
{
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (AffectedPlayers.Remove(pc.PlayerId))
|
|
{
|
|
pc.MarkDirtySettings();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void ApplyOwnGameOptions(IGameOptions opt, byte id)
|
|
{
|
|
if (AffectedPlayers.Contains(id))
|
|
{
|
|
opt.SetVision(false);
|
|
opt.SetFloat(FloatOptionNames.CrewLightMod, Vision.GetFloat());
|
|
opt.SetFloat(FloatOptionNames.ImpostorLightMod, Vision.GetFloat());
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class Tsunami : Disaster
|
|
{
|
|
public enum MovingDirection
|
|
{
|
|
LeftToRight,
|
|
RightToLeft,
|
|
TopToBottom,
|
|
BottomToTop
|
|
}
|
|
|
|
private static OptionItem MovingSpeed;
|
|
|
|
public static readonly Dictionary<MovingDirection, string> Sprites = new()
|
|
{
|
|
[MovingDirection.LeftToRight] = "<size=150%><font=\"VCR SDF\"><line-height=72%><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br><#0073ff>\u2588<#0095ff>\u2588<#00ccff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<br></line-height></size>",
|
|
[MovingDirection.RightToLeft] = "<size=150%><font=\"VCR SDF\"><line-height=72%><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br><#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#9ce8ff>\u2588<#00ccff>\u2588<#0095ff>\u2588<#0073ff>\u2588<br></line-height></size>",
|
|
[MovingDirection.TopToBottom] = "<size=150%><font=\"VCR SDF\"><line-height=72%><#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<#003cff>\u2588<br><#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<#006aff>\u2588<br><#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<#00bbff>\u2588<br><#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<br><#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<br><#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<br><#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<br><#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<#b8e1ff>\u2588<br></line-height></size>",
|
|
[MovingDirection.BottomToTop] = "<size=150%><font=\"VCR SDF\"><line-height=72%><#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<br><#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<br><#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<br><#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<br><#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<#c2e2ff>\u2588<br><#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<#00bfff>\u2588<br><#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<#007bff>\u2588<br><#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<#0033ff>\u2588<br></line-height></size>"
|
|
};
|
|
|
|
private readonly MovingDirection Direction;
|
|
|
|
public Tsunami(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
|
|
Direction = Sprites.GetKeyByValue(NetObject.Sprite);
|
|
}
|
|
|
|
public static void SetupOwnCustomOption()
|
|
{
|
|
const int id = 69_216_600;
|
|
Color color = Utils.GetRoleColor(CustomRoles.NDPlayer);
|
|
|
|
MovingSpeed = new FloatOptionItem(id, "ND_Tsunami.MovingSpeed", new(0.05f, 0.5f, 0.05f), 0.1f, TabGroup.GameSettings)
|
|
.SetHeader(true)
|
|
.SetGameMode(CustomGameMode.NaturalDisasters)
|
|
.SetColor(color)
|
|
.SetValueFormat(OptionFormat.Multiplier);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
if (RemoveIfExpired()) return;
|
|
|
|
float speed = MovingSpeed.GetFloat();
|
|
Vector2 newPos = this.Position;
|
|
switch (Direction)
|
|
{
|
|
case MovingDirection.LeftToRight:
|
|
newPos.x += speed;
|
|
break;
|
|
case MovingDirection.RightToLeft:
|
|
newPos.x -= speed;
|
|
break;
|
|
case MovingDirection.TopToBottom:
|
|
newPos.y -= speed;
|
|
break;
|
|
case MovingDirection.BottomToTop:
|
|
newPos.y += speed;
|
|
break;
|
|
}
|
|
|
|
if (newPos.x < MapBounds.X.Left || newPos.x > MapBounds.X.Right || newPos.y < MapBounds.Y.Bottom || newPos.y > MapBounds.Y.Top)
|
|
{
|
|
Duration = 0;
|
|
RemoveIfExpired();
|
|
return;
|
|
}
|
|
|
|
this.Position = newPos;
|
|
this.NetObject.TP(this.Position);
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
var pos = pc.Pos();
|
|
var inWay = Direction switch
|
|
{
|
|
MovingDirection.LeftToRight => pos.x >= this.Position.x,
|
|
MovingDirection.RightToLeft => pos.x <= this.Position.x,
|
|
MovingDirection.TopToBottom => pos.y <= this.Position.y,
|
|
MovingDirection.BottomToTop => pos.y >= this.Position.y,
|
|
_ => false
|
|
};
|
|
|
|
if (Vector2.Distance(pos, this.Position) <= Range && inWay)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Drowned);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class Sinkhole : Disaster
|
|
{
|
|
public static readonly List<Vector2> Sinkholes = [];
|
|
|
|
public Sinkhole(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (Vector2.Distance(pc.Pos(), this.Position) <= Range)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Sunken);
|
|
}
|
|
}
|
|
|
|
Sinkholes.Add(position);
|
|
}
|
|
|
|
protected override int Duration { get; set; } = int.MaxValue;
|
|
|
|
public override void Update()
|
|
{
|
|
ActiveDisasters.Remove(this);
|
|
}
|
|
|
|
public static void OnFixedUpdate()
|
|
{
|
|
if (Sinkholes.Count == 0) return;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
var pos = pc.Pos();
|
|
// ReSharper disable once ForCanBeConvertedToForeach
|
|
for (int i = 0; i < Sinkholes.Count; i++)
|
|
{
|
|
if (Vector2.Distance(pos, Sinkholes[i]) <= Range)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Sunken);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sealed class BuildingCollapse : Disaster
|
|
{
|
|
public static readonly List<PlainShipRoom> CollapsedRooms = [];
|
|
public static readonly Dictionary<byte, Vector2> LastPosition = [];
|
|
|
|
public BuildingCollapse(Vector2 position, NaturalDisaster naturalDisaster) : base(position)
|
|
{
|
|
NetObject = naturalDisaster;
|
|
Update();
|
|
|
|
var room = naturalDisaster.playerControl.GetPlainShipRoom();
|
|
if (room == default) return;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (pc.GetPlainShipRoom() == room)
|
|
{
|
|
pc.Suicide(PlayerState.DeathReason.Collapsed);
|
|
}
|
|
}
|
|
|
|
CollapsedRooms.Add(room);
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
Duration = 0;
|
|
RemoveIfExpired();
|
|
}
|
|
|
|
public static void OnFixedUpdate()
|
|
{
|
|
if (CollapsedRooms.Count == 0) return;
|
|
|
|
foreach (var pc in Main.AllAlivePlayerControls)
|
|
{
|
|
if (CollapsedRooms.Find(x => x == pc.GetPlainShipRoom()))
|
|
{
|
|
if (LastPosition.TryGetValue(pc.PlayerId, out var lastPos)) pc.TP(lastPos);
|
|
else pc.Suicide(PlayerState.DeathReason.Collapsed);
|
|
}
|
|
else LastPosition[pc.PlayerId] = pc.Pos();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
- Earthquake: The ground shakes, making it hard to move.
|
|
- Meteor: A meteor falls from the sky, killing players in a certain range.
|
|
- Volcano Eruption: Lava flows from one spot, killing players.
|
|
- Tornado: Players are sucked into the tornado and die.
|
|
- Thunderstorm: Lightning strikes outside of rooms, killing players that are hit by it.
|
|
- Sandstorm: Sand blows, making it hard to see.
|
|
- Tsunami: A giant wave comes moving in a specific direction, drowning players that are in the way.
|
|
- Sinkhole: The ground collapses, killing players in range and any players that enter this range in the future.
|
|
- Building Collapse: A building on the ship collapses, killing everyone inside it. Collapsed rooms cannot be entered in the future.
|
|
*/ |