Demiplan polishing (#524)

* 10 -> 20 sharpening stone durability

* auto destroy demiplans try 2 (better)

* start demiplan protection time

* buying demiplan key

* increase island size
This commit is contained in:
Ed
2024-11-01 09:23:22 +03:00
committed by GitHub
parent 5c4b5d1572
commit f9fea9e6ed
19 changed files with 201 additions and 94 deletions

View File

@@ -73,10 +73,18 @@ public sealed partial class CP14DemiplaneSystem
if (generator.Comp.LocationConfig is null)
return;
//We cant open demiplan in another demiplan
if (HasComp<CP14DemiplaneComponent>(Transform(generator).MapUid))
{
_popup.PopupEntity(Loc.GetString("cp14-demiplan-cannot-open", ("name", MetaData(generator).EntityName)), generator, args.User);
return;
}
SpawnRandomDemiplane(generator.Comp.LocationConfig.Value, out var demiplane, out var mapId);
//Admin log needed
//TEST
EnsureComp<CP14DemiplaneDestroyWithoutPlayersComponent>(demiplane);
EnsureComp<CP14DemiplaneDestroyWithoutStabilizationComponent>(demiplane);
var tempRift = EntityManager.Spawn("CP14DemiplaneTimedRadiusPassway");
var tempRift2 = EntityManager.Spawn("CP14DemiplanRiftCore");
@@ -93,8 +101,6 @@ public sealed partial class CP14DemiplaneSystem
private void GeneratorMapInit(Entity<CP14DemiplaneGeneratorDataComponent> generator, ref MapInitEvent args)
{
// Here, a unique Demiplan config should be generated based on the CP14DemiplanGeneratorDataComponent
//Location generation
HashSet<CP14DemiplaneLocationPrototype> suitableConfigs = new();
foreach (var locationConfig in _proto.EnumeratePrototypes<CP14DemiplaneLocationPrototype>())

View File

@@ -0,0 +1,61 @@
using Content.Shared._CP14.Demiplane.Components;
using Content.Shared.Mobs.Systems;
namespace Content.Server._CP14.Demiplane;
public sealed partial class CP14DemiplaneSystem
{
private readonly TimeSpan _checkFrequency = TimeSpan.FromSeconds(15f);
private TimeSpan _nextCheckTime = TimeSpan.Zero;
[Dependency] private readonly MobStateSystem _mobState = default!;
private void InitStabilization()
{
_nextCheckTime = _timing.CurTime + _checkFrequency;
SubscribeLocalEvent<CP14DemiplaneDestroyWithoutStabilizationComponent, MapInitEvent>(OnStabilizationMapInit);
}
private void OnStabilizationMapInit(Entity<CP14DemiplaneDestroyWithoutStabilizationComponent> ent, ref MapInitEvent args)
{
ent.Comp.EndProtectionTime = _timing.CurTime + ent.Comp.ProtectedSpawnTime;
}
private void UpdateStabilization(float frameTime)
{
if (_timing.CurTime < _nextCheckTime)
return;
_nextCheckTime = _timing.CurTime + _checkFrequency;
HashSet<EntityUid> stabilizedMaps = new();
var query = EntityQueryEnumerator<CP14DemiplaneStabilizerComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var stabilizer, out var transform))
{
var map = transform.MapUid;
if (map is null)
continue;
if (stabilizer.RequireAlive && !(_mobState.IsAlive(uid) || _mobState.IsCritical(uid)))
continue;
if (stabilizedMaps.Contains(map.Value))
continue;
stabilizedMaps.Add(map.Value);
}
var query2 = EntityQueryEnumerator<CP14DemiplaneComponent, CP14DemiplaneDestroyWithoutStabilizationComponent>();
while (query2.MoveNext(out var uid, out var demiplan, out var stabilization))
{
if (_timing.CurTime < stabilization.EndProtectionTime)
continue;
if (!stabilizedMaps.Contains(uid))
QueueDel(uid);
}
}
}

View File

@@ -2,10 +2,12 @@ using Content.Server.Flash;
using Content.Server.Procedural;
using Content.Shared._CP14.Demiplane;
using Content.Shared._CP14.Demiplane.Components;
using Content.Shared.Popups;
using Robust.Server.Audio;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Demiplane;
@@ -21,6 +23,8 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly FlashSystem _flash = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
@@ -28,6 +32,7 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
InitGeneration();
InitConnections();
InitStabilization();
SubscribeLocalEvent<CP14DemiplaneComponent, ComponentShutdown>(OnDemiplanShutdown);
}
@@ -37,8 +42,8 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
base.Update(frameTime);
UpdateGeneration(frameTime);
UpdateStabilization(frameTime);
}
/// <summary>
/// Teleports the entity inside the demiplane, to one of the random entry points.
/// </summary>
@@ -61,10 +66,6 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
_transform.SetCoordinates(entity.Value, targetCoord);
_audio.PlayGlobal(demiplane.Comp.ArrivalSound, entity.Value);
var ev = new CP14DemiplanEntityEnterEvent(entity.Value);
RaiseLocalEvent(demiplane, ev);
return true;
}
@@ -93,9 +94,6 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
_transform.SetCoordinates(entity.Value, targetCoord);
_audio.PlayGlobal(demiplane.Comp.DepartureSound, entity.Value);
var ev = new CP14DemiplanEntityLeaveEvent(entity.Value);
RaiseLocalEvent(demiplane, ev);
return true;
}

View File

@@ -1,10 +1,12 @@
using Content.Server._CP14.Demiplane;
using Content.Server.Mind;
using Content.Server.Popups;
using Content.Shared._CP14.Demiplane;
using Content.Shared._CP14.Demiplane.Components;
using Content.Shared._CP14.DemiplaneTraveling;
using Content.Shared.Ghost;
using Content.Shared.Movement.Pulling.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
@@ -17,6 +19,8 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
@@ -32,15 +36,15 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
//Radius passway
var query = EntityQueryEnumerator<CP14DemiplaneRadiusTimedPasswayComponent, CP14DemiplaneRiftComponent>();
while (query.MoveNext(out var uid, out var passway, out var rift))
while (query.MoveNext(out var uid, out var passWay, out var rift))
{
if (_timing.CurTime < passway.NextTimeTeleport)
if (_timing.CurTime < passWay.NextTimeTeleport)
continue;
passway.NextTimeTeleport = _timing.CurTime + passway.Delay;
passWay.NextTimeTeleport = _timing.CurTime + passWay.Delay;
HashSet<EntityUid> teleportedEnts = new();
var nearestEnts = _lookup.GetEntitiesInRange(uid, passway.Radius);
var nearestEnts = _lookup.GetEntitiesInRange(uid, passWay.Radius);
foreach (var ent in nearestEnts)
{
if (HasComp<GhostComponent>(ent))
@@ -52,7 +56,7 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
teleportedEnts.Add(ent);
}
while (teleportedEnts.Count > passway.MaxEntities)
while (teleportedEnts.Count > passWay.MaxEntities)
{
teleportedEnts.Remove(_random.Pick(teleportedEnts));
}
@@ -69,6 +73,7 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
_demiplan.TryTeleportOutDemiplane((map.Value, demiplan), puller.Pulling);
_demiplan.TryTeleportOutDemiplane((map.Value, demiplan), ent);
_audio.PlayPvs(passWay.ArrivalSound, ent);
}
}
else
@@ -84,9 +89,11 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
_demiplan.TryTeleportIntoDemiplane(rift.Demiplan.Value, puller.Pulling);
_demiplan.TryTeleportIntoDemiplane(rift.Demiplan.Value, ent);
_audio.PlayPvs(passWay.ArrivalSound, ent);
}
}
}
_audio.PlayPvs(passWay.DepartureSound, Transform(uid).Coordinates);
QueueDel(uid);
}
}
@@ -94,6 +101,7 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
private void RadiusMapInit(Entity<CP14DemiplaneRadiusTimedPasswayComponent> radiusPassWay, ref MapInitEvent args)
{
radiusPassWay.Comp.NextTimeTeleport = _timing.CurTime + radiusPassWay.Comp.Delay;
//Popup caution here
}
private void OnOpenRiftInteractDoAfter(Entity<CP14DemiplaneRiftOpenedComponent> passWay, ref CP14DemiplanPasswayUseDoAfter args)
@@ -121,13 +129,19 @@ public sealed partial class CP14DemiplaneTravelingSystem : EntitySystem
}
}
if (passWay.Comp.MaxUse > 0 && used)
if (used)
{
passWay.Comp.MaxUse--;
if (passWay.Comp.MaxUse == 0)
QueueDel(passWay);
_audio.PlayPvs(passWay.Comp.DepartureSound, Transform(passWay).Coordinates);
_audio.PlayPvs(passWay.Comp.ArrivalSound, args.User);
if (passWay.Comp.MaxUse > 0)
{
passWay.Comp.MaxUse--;
if (passWay.Comp.MaxUse == 0)
QueueDel(passWay);
}
}
args.Handled = true;
}
}

View File

@@ -15,31 +15,6 @@ public abstract partial class CP14SharedDemiplaneSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<CP14DemiplaneRiftOpenedComponent, InteractHandEvent>(OnDemiplanPasswayInteract);
SubscribeLocalEvent<CP14DemiplaneDestroyWithoutPlayersComponent, CP14DemiplanEntityEnterEvent>(OnEntityEnter);
SubscribeLocalEvent<CP14DemiplaneDestroyWithoutPlayersComponent, CP14DemiplanEntityLeaveEvent>(OnEntityLeave);
}
private void OnEntityLeave(Entity<CP14DemiplaneDestroyWithoutPlayersComponent> ent, ref CP14DemiplanEntityLeaveEvent args)
{
//это можно легко абузить, если игроки найдут способ выходить из
//демиплана другим способом. Лучше добавлять на игроков компонент, и тречить все смены карт у этого компонента
if (ent.Comp.Players.Contains(args.Player))
{
ent.Comp.Players.Remove(args.Player);
if (ent.Comp.Players.Count == 0)
{
QueueDel(ent);
}
}
}
private void OnEntityEnter(Entity<CP14DemiplaneDestroyWithoutPlayersComponent> ent, ref CP14DemiplanEntityEnterEvent args)
{
if (!TryComp<ActorComponent>(args.Player, out var actor))
return;
ent.Comp.Players.Add(args.Player);
}
private void OnDemiplanPasswayInteract(Entity<CP14DemiplaneRiftOpenedComponent> passway, ref InteractHandEvent args)
@@ -64,29 +39,3 @@ public abstract partial class CP14SharedDemiplaneSystem : EntitySystem
public sealed partial class CP14DemiplanPasswayUseDoAfter : SimpleDoAfterEvent
{
}
/// <summary>
/// Is invoked on the demiplane when new players enter. This only applies to rift entrances, any other methods will not be taken into account.
/// </summary>
public sealed class CP14DemiplanEntityEnterEvent : EntityEventArgs
{
public EntityUid Player;
public CP14DemiplanEntityEnterEvent(EntityUid player)
{
Player = player;
}
}
/// <summary>
/// Is invoked on the demiplane when some players left. This only applies to rift entrances, any other methods will not be taken into account.
/// </summary>
public sealed class CP14DemiplanEntityLeaveEvent : EntityEventArgs
{
public EntityUid Player;
public CP14DemiplanEntityLeaveEvent(EntityUid player)
{
Player = player;
}
}

View File

@@ -0,0 +1,14 @@
namespace Content.Shared._CP14.Demiplane.Components;
/// <summary>
/// Keeps the demiplanes from being destroyed while they're in it.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
public sealed partial class CP14DemiplaneStabilizerComponent : Component
{
/// <summary>
/// must be a being and be alive to work as a stabilizer
/// </summary>
[DataField]
public bool RequireAlive = false;
}

View File

@@ -1,11 +0,0 @@
namespace Content.Shared._CP14.Demiplane.Components;
/// <summary>
/// Automatically deletes the demiplane if everyone who entered it, exited back out, or died.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem))]
public sealed partial class CP14DemiplaneDestroyWithoutPlayersComponent : Component
{
[DataField]
public HashSet<EntityUid> Players = new();
}

View File

@@ -0,0 +1,18 @@
namespace Content.Shared._CP14.Demiplane.Components;
/// <summary>
/// is automatically delete over time if there are no active stabilizers inside this demiplane.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharedDemiplaneSystem)), AutoGenerateComponentPause]
public sealed partial class CP14DemiplaneDestroyWithoutStabilizationComponent : Component
{
/// <summary>
/// how many time after generation the demiplane cannot be destroyed.
/// </summary>
[DataField]
public TimeSpan ProtectedSpawnTime = TimeSpan.FromMinutes(1);
[DataField]
[AutoPausedField]
public TimeSpan EndProtectionTime = TimeSpan.Zero;
}

View File

@@ -1,9 +1,11 @@
using Robust.Shared.Audio;
namespace Content.Shared._CP14.DemiplaneTraveling;
/// <summary>
/// teleports a certain number of entities between demiplanes with a delay
/// </summary>
[RegisterComponent]
[RegisterComponent, AutoGenerateComponentPause]
public sealed partial class CP14DemiplaneRadiusTimedPasswayComponent : Component
{
[DataField]
@@ -16,5 +18,12 @@ public sealed partial class CP14DemiplaneRadiusTimedPasswayComponent : Component
public float Radius = 3f;
[DataField]
[AutoPausedField]
public TimeSpan NextTimeTeleport = TimeSpan.Zero;
[DataField("arrivalSound")]
public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
[DataField("departureSound")]
public SoundSpecifier DepartureSound = new SoundPathSpecifier("/Audio/Effects/teleport_departure.ogg");
}

View File

@@ -1,3 +1,5 @@
using Robust.Shared.Audio;
namespace Content.Shared._CP14.DemiplaneTraveling;
/// <summary>
@@ -14,4 +16,10 @@ public sealed partial class CP14DemiplaneRiftOpenedComponent : Component
[DataField]
public float DoAfter = 4f;
[DataField("arrivalSound")]
public SoundSpecifier ArrivalSound = new SoundPathSpecifier("/Audio/Effects/teleport_arrival.ogg");
[DataField("departureSound")]
public SoundSpecifier DepartureSound = new SoundPathSpecifier("/Audio/Effects/teleport_departure.ogg");
}

View File

@@ -0,0 +1,3 @@
cp14-demiplan-active-rift-warning = {$name} begins dragging surrounding creatures into the demiplane!
cp14-demiplan-cannot-open = You can't use {$name} here.

View File

@@ -10,4 +10,7 @@ cp14-store-buy-alchemy-bureaucracy-name = Bureaucratic reserve
cp14-store-buy-alchemy-bureaucracy-desc = Feather pens, inkwells and a big stack of paper. In folders of different colors, or without folders at all: because we make sure that you can choose the option that is most comfortable for you.
cp14-store-buy-alchemy-farm-seeds-name = Seeds for farming
cp14-store-buy-alchemy-farm-seeds-desc = A set of different seeds, for farming of all kinds! Don't limit yourself, buy several boxes at once, just in case the farmers eat everything and don't have any food left to process into seeds.
cp14-store-buy-alchemy-farm-seeds-desc = A set of different seeds, for farming of all kinds! Don't limit yourself, buy several boxes at once, just in case the farmers eat everything and don't have any food left to process into seeds.
cp14-store-buy-alchemy-demiplan-name = Demiplan key
cp14-store-buy-alchemy-demiplan-desc = An unstable pocket dimension where doom or riches may await you? What could be better for your adventurers? Buy from us for a couple of gold pieces - resell to them for more, or bail them out.

View File

@@ -0,0 +1,3 @@
cp14-demiplan-active-rift-warning = {$name} начинает затягивать окружающих существ в демиплан!
cp14-demiplan-cannot-open = Вы не можете использовать {$name} здесь.

View File

@@ -10,4 +10,7 @@ cp14-store-buy-alchemy-bureaucracy-name = Бюрократический зап
cp14-store-buy-alchemy-bureaucracy-desc = Ручки, чернильницы и большая пачка бумаги. В папках разных цветов, и вовсе без папок: ведь мы заботимся о том, чтобы вы могли выбирать тот вариант, который вам комфортнее.
cp14-store-buy-alchemy-farm-seeds-name = Семена для фермерства
cp14-store-buy-alchemy-farm-seeds-desc = Набор разных семян, для фермерства всех видов! Не ограничивайте себя, купите сразу несколько ящиков, на случай, если фермеры все съедят и не оставят еды на переработку в семена.
cp14-store-buy-alchemy-farm-seeds-desc = Набор разных семян, для фермерства всех видов! Не ограничивайте себя, купите сразу несколько ящиков, на случай, если фермеры все съедят и не оставят еды на переработку в семена.
cp14-store-buy-alchemy-demiplan-name = Ключ демиплана
cp14-store-buy-alchemy-demiplan-desc = Нестабильное карманное измерение, в котором вас может поджидать гибель или богатства? Что может быть лучше для ваших авантюристов? Купите у нас за пару золотых - перепродайте им подороже, или под залог.

View File

@@ -221,6 +221,8 @@
- type: CP14FootprintHolder
decalProto: CP14Footprints
- type: CP14FootprintTrailer
- type: CP14DemiplaneStabilizer
requireAlive: true
- type: entity

View File

@@ -17,7 +17,7 @@
thresholds:
- trigger:
!type:DamageTrigger
damage: 10
damage: 20
behaviors:
- !type:PlaySoundBehavior
sound:

View File

@@ -14,7 +14,7 @@
shader: unshaded
- type: entity
id: CP14SubdimensionalKey
id: CP14DemiplanKey
parent: CP14BaseSubdimensionalKey
components:
- type: CP14DemiplaneGeneratorData
@@ -58,7 +58,7 @@
- type: CP14DemiplaneRift
activeTeleport: false
- type: CP14DemiplaneRadiusTimedPassway
maxEntities: 3
maxEntities: 4
delay: 4
- type: Sprite
drawdepth: Effects
@@ -71,6 +71,11 @@
- type: SingularityDistortion
falloffPower: 1.5
intensity: 50
- type: AmbientSound
volume: -3
range: 7
sound:
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
- type: entity
id: CP14DemiplanePassway
@@ -90,6 +95,11 @@
- type: SingularityDistortion
falloffPower: 1.5
intensity: 50
- type: AmbientSound
volume: -3
range: 7
sound:
path: /Audio/Ambience/Objects/gravity_gen_hum.ogg
- type: entity
parent: MarkerBase

View File

@@ -7,6 +7,7 @@
- type: CP14MapFloorOccluder
- type: Parallax
parallax: CP14Ocean
- type: CP14CloudShadows
- type: CP14WeatherController
entries:
- visuals: CP14Rain
@@ -77,8 +78,8 @@
maxGroupSize: 15
# Mobs
- !type:MobsDunGen
minCount: 2
maxCount: 5
minCount: 3
maxCount: 6
groups:
- id: CP14SpawnMobDinoYumkaraptor
amount: 1
@@ -106,7 +107,7 @@
id: CP14ExpeditionGrasslandIslandFloorMaskStone
layers:
- !type:NoiseDistanceDunGen
size: 80, 80
size: 110, 110
distanceConfig: !type:DunGenEuclideanSquaredDistance
blendWeight: 0.5
layers:
@@ -124,7 +125,7 @@
id: CP14ExpeditionGrasslandIslandFloorMaskGrass
layers:
- !type:NoiseDistanceDunGen
size: 120, 120
size: 150, 150
distanceConfig: !type:DunGenEuclideanSquaredDistance
blendWeight: 0.6
layers:
@@ -142,7 +143,7 @@
id: CP14ExpeditionGrasslandIslandFloorMaskSand
layers:
- !type:NoiseDistanceDunGen
size: 130, 130
size: 160, 160
distanceConfig: !type:DunGenEuclideanSquaredDistance
blendWeight: 0.7
layers:

View File

@@ -60,4 +60,20 @@
services:
- !type:CP14BuyItemsService
product:
CP14BrassChestFilledFarmSeeds: 1
CP14BrassChestFilledFarmSeeds: 1
- type: storePositionBuy
id: Demiplan
name: cp14-store-buy-alchemy-demiplan-name
desc: cp14-store-buy-alchemy-demiplan-desc
code: DEMIPLAN
icon:
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift.rsi
state: pulse
price:
min: 100
max: 200
services:
- !type:CP14BuyItemsService
product:
CP14DemiplanKey: 1