mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +03:00
* Add support for contextual information in EntityTables (#37737) * Add context support for entityTables * fix build fail * comments * Update Content.Shared/EntityTable/EntityTableSystem.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> (cherry picked from commit e92b6b6a7e2ed2e5f7473321e391394f28b9ee4a) * Multiantag Gamemode (#37783) Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Co-authored-by: Southbridge <7013162+southbridge-fur@users.noreply.github.com> Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> (cherry picked from commit f23e8c286153b5742de258a4e722803a1a4fba78) * Гейммоды * Ребаланс цен * Фикс линтера * Баланс бюджета + фикс повторения --------- Co-authored-by: Nemanja <98561806+emogarbage404@users.noreply.github.com>
159 lines
6.2 KiB
C#
159 lines
6.2 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Shared._Goobstation.Fishing.Components;
|
|
using Content.Shared._Goobstation.Fishing.Systems;
|
|
using Content.Shared.EntityTable;
|
|
using Content.Shared.Interaction.Events;
|
|
using Content.Shared.Item;
|
|
using Content.Shared.Movement.Pulling.Components;
|
|
using Content.Shared.Physics;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Physics;
|
|
using Robust.Shared.Physics.Events;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
|
|
namespace Content.Server._Goobstation.Fishing;
|
|
|
|
public sealed class FishingSystem : SharedFishingSystem
|
|
{
|
|
// Here we calculate the start of fishing, because apparently StartCollideEvent
|
|
// works janky on clientside so we can't predict when fishing starts.
|
|
[Dependency] private readonly IComponentFactory _compFactory = default!;
|
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
[Dependency] private readonly PhysicsSystem _physics = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<FishingLureComponent, StartCollideEvent>(OnFloatCollide);
|
|
SubscribeLocalEvent<FishingRodComponent, UseInHandEvent>(OnFishingInteract);
|
|
}
|
|
|
|
#region Event handling
|
|
|
|
private void OnFloatCollide(Entity<FishingLureComponent> ent, ref StartCollideEvent args)
|
|
{
|
|
// TODO: make it so this can collide with any unacnchored objects (items, mobs, etc) but not the player casting it (get parent of rod?)
|
|
// Fishing spot logic
|
|
var attachedEnt = args.OtherEntity;
|
|
|
|
if (HasComp<ActiveFishingSpotComponent>(attachedEnt))
|
|
return;
|
|
|
|
if (!FishSpotQuery.TryComp(attachedEnt, out var spotComp))
|
|
{
|
|
if (args.OtherBody.BodyType == BodyType.Static)
|
|
return;
|
|
|
|
Anchor(ent, attachedEnt);
|
|
return;
|
|
}
|
|
|
|
// Anchor fishing float on an entity
|
|
Anchor(ent, attachedEnt);
|
|
|
|
// Currently we don't support multiple loots from this
|
|
var fish = spotComp.FishList.GetSpawns(_random.GetRandom(), EntityManager, _proto, new EntityTableContext()).First();
|
|
|
|
// Get fish difficulty
|
|
_proto.Index(fish).TryGetComponent(out FishComponent? fishComp, _compFactory);
|
|
|
|
// Assign things that depend on the fish
|
|
var activeFishSpot = EnsureComp<ActiveFishingSpotComponent>(attachedEnt);
|
|
activeFishSpot.Fish = fish;
|
|
activeFishSpot.FishDifficulty = fishComp?.FishDifficulty ?? FishComponent.DefaultDifficulty;
|
|
|
|
// Assign things that depend on the spot
|
|
var time = spotComp.FishDefaultTimer + _random.NextFloat(-spotComp.FishTimerVariety, spotComp.FishTimerVariety);
|
|
activeFishSpot.FishingStartTime = Timing.CurTime + TimeSpan.FromSeconds(time);
|
|
activeFishSpot.AttachedFishingLure = ent;
|
|
|
|
// Declares war on prediction
|
|
Dirty(attachedEnt, activeFishSpot);
|
|
Dirty(ent);
|
|
}
|
|
|
|
private void OnFishingInteract(EntityUid uid, FishingRodComponent component, UseInHandEvent args)
|
|
{
|
|
if (!FisherQuery.TryComp(args.User, out var fisherComp) || fisherComp.TotalProgress == null || args.Handled || !Timing.IsFirstTimePredicted)
|
|
return;
|
|
|
|
fisherComp.TotalProgress += fisherComp.ProgressPerUse * component.Efficiency;
|
|
Dirty(args.User, fisherComp); // That's a bit evil, but we want to keep numbers real.
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void Anchor(Entity<FishingLureComponent> ent, EntityUid attachedEnt)
|
|
{
|
|
var spotPosition = Xform.GetWorldPosition(attachedEnt);
|
|
Xform.SetWorldPosition(ent, spotPosition);
|
|
Xform.SetParent(ent, attachedEnt);
|
|
_physics.SetLinearVelocity(ent, Vector2.Zero);
|
|
_physics.SetAngularVelocity(ent, 0f);
|
|
ent.Comp.AttachedEntity = attachedEnt;
|
|
RemComp<ItemComponent>(ent);
|
|
RemComp<PullableComponent>(ent);
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected override void SetupFishingFloat(Entity<FishingRodComponent> fishingRod, EntityUid player, EntityCoordinates target)
|
|
{
|
|
var (uid, component) = fishingRod;
|
|
var targetCoords = Xform.ToMapCoordinates(target);
|
|
var playerCoords = Xform.GetMapCoordinates(Transform(player));
|
|
|
|
var fishFloat = Spawn(component.FloatPrototype, playerCoords);
|
|
component.FishingLure = fishFloat;
|
|
Dirty(uid, component);
|
|
|
|
// Calculate throw direction
|
|
var direction = targetCoords.Position - playerCoords.Position;
|
|
if (direction == Vector2.Zero)
|
|
direction = Vector2.UnitX; // If the user somehow manages to click directly in the center of themself, just toss it to the right i guess.
|
|
|
|
// Yeet
|
|
Throwing.TryThrow(fishFloat, direction, 15f, player, 2f, null, true);
|
|
|
|
// Set up lure component
|
|
var fishLureComp = EnsureComp<FishingLureComponent>(fishFloat);
|
|
fishLureComp.FishingRod = uid;
|
|
Dirty(fishFloat, fishLureComp);
|
|
|
|
// Rope visuals
|
|
var visuals = EnsureComp<JointVisualsComponent>(fishFloat);
|
|
visuals.Sprite = component.RopeSprite;
|
|
visuals.OffsetA = component.RopeLureOffset;
|
|
visuals.OffsetB = component.RopeUserOffset;
|
|
visuals.Target = GetNetEntity(uid);
|
|
}
|
|
|
|
protected override void ThrowFishReward(EntProtoId fishId, EntityUid fishSpot, EntityUid target)
|
|
{
|
|
var position = Transform(fishSpot).Coordinates;
|
|
var fish = Spawn(fishId, position);
|
|
// Throw da fish back to the player because it looks funny
|
|
var direction = Xform.GetWorldPosition(target) - Xform.GetWorldPosition(fish);
|
|
var length = direction.Length();
|
|
var distance = Math.Clamp(length, 0.5f, 15f);
|
|
direction *= distance / length;
|
|
|
|
Throwing.TryThrow(fish, direction, 7f);
|
|
}
|
|
|
|
protected override void CalculateFightingTimings(Entity<ActiveFisherComponent> fisher, ActiveFishingSpotComponent activeSpotComp)
|
|
{
|
|
if (Timing.CurTime < fisher.Comp.NextStruggle)
|
|
return;
|
|
|
|
fisher.Comp.NextStruggle = Timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(0.06f, 0.18f));
|
|
fisher.Comp.TotalProgress -= activeSpotComp.FishDifficulty;
|
|
Dirty(fisher);
|
|
}
|
|
}
|