Транспорт Return (#98)

* returnvehicles

* tags
This commit is contained in:
Zekins
2025-06-07 23:16:31 +03:00
committed by GitHub
parent 58f1b9b3ea
commit 5ea4428d1e
38 changed files with 1524 additions and 3 deletions

View File

@@ -0,0 +1,63 @@
using Content.Shared.Vehicle;
using Content.Shared.Vehicle.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Vehicle;
public sealed class VehicleSystem : SharedVehicleSystem
{
[Dependency] private EyeSystem _eye = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RiderComponent, ComponentStartup>(OnRiderStartup);
SubscribeLocalEvent<RiderComponent, ComponentShutdown>(OnRiderShutdown);
SubscribeLocalEvent<VehicleComponent, AppearanceChangeEvent>(OnVehicleAppearanceChange);
}
private void OnRiderStartup(EntityUid uid, RiderComponent component, ComponentStartup args)
{
// Center the player's eye on the vehicle
if (TryComp(uid, out EyeComponent? eyeComp))
{
_eye.SetTarget(uid, eyeComp.Target ?? component.Vehicle, eyeComp);
}
}
private void OnRiderShutdown(EntityUid uid, RiderComponent component, ComponentShutdown args)
{
// reset the riders eye centering.
if (TryComp(uid, out EyeComponent? eyeComp))
{
_eye.SetTarget(uid, null, eyeComp);
}
}
private void OnVehicleAppearanceChange(EntityUid uid, VehicleComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (component.HideRider
&& Appearance.TryGetData<bool>(uid, VehicleVisuals.HideRider, out var hide, args.Component)
&& TryComp<SpriteComponent>(component.LastRider, out var riderSprite))
riderSprite.Visible = !hide;
// First check is for the sprite itself
if (Appearance.TryGetData<int>(uid, VehicleVisuals.DrawDepth, out var drawDepth, args.Component))
args.Sprite.DrawDepth = drawDepth;
// Set vehicle layer to animated or not (i.e. are the wheels turning or not)
if (component.AutoAnimate
&& Appearance.TryGetData<bool>(uid, VehicleVisuals.AutoAnimate, out var autoAnimate, args.Component))
args.Sprite.LayerSetAutoAnimated(VehicleVisualLayers.AutoAnimate, autoAnimate);
}
}
public enum VehicleVisualLayers : byte
{
/// Layer for the vehicle's wheels
AutoAnimate,
}

View File

@@ -0,0 +1,7 @@
using Content.Shared.Vehicle;
namespace Content.Server.Vehicle;
public sealed class VehicleSystem : SharedVehicleSystem
{
}

View File

@@ -1,5 +1,6 @@
using System.Numerics;
using Content.Shared.Alert;
using Content.Shared.Vehicle; // Corvax-Wega-Vehicles
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
@@ -9,7 +10,7 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Buckle.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedBuckleSystem))]
[Access(typeof(SharedBuckleSystem), typeof(SharedVehicleSystem))] // Corvax-Wega-Vehicles-Edit
public sealed partial class StrapComponent : Component
{
/// <summary>

View File

@@ -16,6 +16,7 @@ using Content.Shared.Standing;
using Content.Shared.Storage.Components;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Vehicle.Components; // Corvax-Wega-Vehicles
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
@@ -165,6 +166,15 @@ public abstract partial class SharedBuckleSystem
private void OnBuckleStandAttempt(EntityUid uid, BuckleComponent component, StandAttemptEvent args)
{
// Corvax-Wega-Vehicles-start
if (component.BuckledTo != null)
{
var buckle = component.BuckledTo;
if (HasComp<VehicleComponent>(buckle))
return;
}
// Corvax-Wega-Vehicles-end
if (component.Buckled)
args.Cancel();
}
@@ -177,7 +187,7 @@ public abstract partial class SharedBuckleSystem
private void OnBuckleUpdateCanMove(EntityUid uid, BuckleComponent component, UpdateCanMoveEvent args)
{
if (component.Buckled)
if (component.Buckled && !HasComp<VehicleComponent>(component.BuckledTo)) // Corvax-Wega-Vehicles-Edit
args.Cancel();
}
@@ -524,6 +534,9 @@ public abstract partial class SharedBuckleSystem
if (unbuckleAttempt.Cancelled)
return false;
if (TryComp<VehicleComponent>(strapUid, out var vehicle) && vehicle.Rider != user && !_mobState.IsIncapacitated(buckle)) // Corvax-Wega-Vehicles
return false; // Corvax-Wega-Vehicles
var unstrapAttempt = new UnstrapAttemptEvent(strap, buckle!, user, popup);
RaiseLocalEvent(strap, ref unstrapAttempt);
return !unstrapAttempt.Cancelled;

View File

@@ -4,6 +4,7 @@ using Content.Shared.Movement.Events;
using Content.Shared.Movement.Systems;
using Content.Shared.Standing;
using Content.Shared.Throwing;
using Content.Shared.Vehicle.Components; // Corvax-Wega-Vehicles
namespace Content.Shared.Traits.Assorted;
@@ -47,6 +48,9 @@ public sealed class LegsParalyzedSystem : EntitySystem
private void OnUpdateCanMoveEvent(EntityUid uid, LegsParalyzedComponent component, UpdateCanMoveEvent args)
{
if (TryComp<BuckleComponent>(uid, out var buckle) && HasComp<VehicleComponent>(buckle.BuckledTo)) // Corvax-Wega-Vehicles
return; // Corvax-Wega-Vehicles
args.Cancel();
}

View File

@@ -0,0 +1,46 @@
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Database;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.EntityEffects.Effects;
public sealed partial class DamageEntityEffect : EntityEffect
{
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<DamageTypePrototype>))]
public string DamageType = string.Empty;
[DataField]
public float Amount = 5f;
[DataField(required: true)]
public string RequiredComponent = string.Empty;
public override bool ShouldLog => true;
public override LogImpact LogImpact => LogImpact.Medium;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-damage-if-component",
("chance", Probability),
("damage", Amount),
("type", DamageType),
("component", RequiredComponent));
public override void Effect(EntityEffectBaseArgs args)
{
var entMan = args.EntityManager;
var uid = args.TargetEntity;
var componentType = entMan.ComponentFactory.GetRegistration(RequiredComponent).Type;
if (!entMan.HasComponent(uid, componentType))
return;
if (entMan.TryGetComponent<DamageableComponent>(uid, out _))
{
var damage = new DamageSpecifier();
damage.DamageDict.Add(DamageType, Amount);
entMan.System<DamageableSystem>().TryChangeDamage(uid, damage, true);
}
}
}

View File

@@ -0,0 +1,17 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Vehicle.Components
{
/// <summary>
/// Added to objects inside a vehicle to stop people besides the rider from
/// removing them.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class InVehicleComponent : Component
{
/// <summary>
/// The vehicle this rider is currently riding.
/// </summary>
[ViewVariables] public VehicleComponent? Vehicle;
}
}

View File

@@ -0,0 +1,26 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Vehicle.Components;
/// <summary>
/// Added to people when they are riding in a vehicle
/// used mostly to keep track of them for entityquery.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class RiderComponent : Component
{
/// <summary>
/// The vehicle this rider is currently riding.
/// </summary>
[ViewVariables, AutoNetworkedField]
public EntityUid? Vehicle;
public override bool SendOnlyToOwner => true;
}
[Serializable, NetSerializable]
public sealed class RiderComponentState : ComponentState
{
public NetEntity? Entity;
}

View File

@@ -0,0 +1,114 @@
using System.Numerics;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Vehicle.Components;
/// <summary>
/// This is particularly for vehicles that use
/// buckle. Stuff like clown cars may need a different
/// component at some point.
/// All vehicles should have Physics, Strap, and SharedPlayerInputMover components.
/// </summary>
[AutoGenerateComponentState]
[RegisterComponent, NetworkedComponent]
[Access(typeof(SharedVehicleSystem))]
public sealed partial class VehicleComponent : Component
{
/// <summary>
/// The entity currently riding the vehicle.
/// </summary>
[ViewVariables]
[AutoNetworkedField]
public EntityUid? Rider;
[ViewVariables]
[AutoNetworkedField]
public EntityUid? LastRider;
/// <summary>
/// The base offset for the vehicle (when facing east)
/// </summary>
[ViewVariables]
public Vector2 BaseBuckleOffset = Vector2.Zero;
/// <summary>
/// The sound that the horn makes
/// </summary>
[DataField("hornSound")]
[ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier? HornSound = new SoundPathSpecifier("/Audio/Effects/Vehicle/carhorn.ogg")
{
Params = AudioParams.Default.WithVolume(-3f)
};
[ViewVariables]
public EntityUid? HonkPlayingStream;
/// Use ambient sound component for the idle sound.
[DataField("hornAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? HornAction = "ActionVehicleHorn";
/// <summary>
/// The action for the horn (if any)
/// </summary>
[DataField("hornActionEntity")]
[ViewVariables(VVAccess.ReadWrite)]
public EntityUid? HornActionEntity;
/// <summary>
/// Whether the vehicle has a key currently inside it or not.
/// </summary>
[DataField("hasKey")]
[ViewVariables(VVAccess.ReadWrite)]
public bool HasKey;
/// <summary>
/// Determines from which side the vehicle will be displayed on top of the player.
/// </summary>
[DataField("southOver")]
[ViewVariables(VVAccess.ReadWrite)]
public bool SouthOver;
[DataField("northOver")]
[ViewVariables(VVAccess.ReadWrite)]
public bool NorthOver;
[DataField("westOver")]
[ViewVariables(VVAccess.ReadWrite)]
public bool WestOver;
[DataField("eastOver")]
[ViewVariables(VVAccess.ReadWrite)]
public bool EastOver;
/// <summary>
/// What the y buckle offset should be in north / south
/// </summary>
[DataField("northOverride")]
[ViewVariables(VVAccess.ReadWrite)]
public float NorthOverride;
/// <summary>
/// What the y buckle offset should be in north / south
/// </summary>
[DataField("southOverride")]
[ViewVariables(VVAccess.ReadWrite)]
public float SouthOverride;
[DataField("autoAnimate")]
[ViewVariables(VVAccess.ReadWrite)]
public bool AutoAnimate = true;
[DataField("useHand")]
[ViewVariables(VVAccess.ReadWrite)]
public bool UseHand = true;
[DataField("hideRider")]
[ViewVariables(VVAccess.ReadWrite)]
public bool HideRider;
}

View File

@@ -0,0 +1,30 @@
using System.Numerics;
using Content.Shared.Hands;
using Content.Shared.Movement.Pulling.Events;
using Content.Shared.Vehicle.Components;
using Robust.Shared.GameStates;
namespace Content.Shared.Vehicle;
public abstract partial class SharedVehicleSystem
{
private void InitializeRider()
{
SubscribeLocalEvent<RiderComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
SubscribeLocalEvent<RiderComponent, PullAttemptEvent>(OnPullAttempt);
}
private void OnVirtualItemDeleted(EntityUid uid, RiderComponent component, VirtualItemDeletedEvent args)
{
if (args.BlockingEntity == component.Vehicle)
{
_buckle.TryUnbuckle(uid, null);
}
}
private void OnPullAttempt(EntityUid uid, RiderComponent component, PullAttemptEvent args)
{
if (component.Vehicle != null)
args.Cancelled = true;
}
}

View File

@@ -0,0 +1,336 @@
using System.Numerics;
using Content.Shared.Access.Components;
using Content.Shared.Actions;
using Content.Shared.Audio;
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Item;
using Content.Shared.Light.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Content.Shared.Vehicle.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Network;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Serialization;
namespace Content.Shared.Vehicle;
/// <summary>
/// Stores the VehicleVisuals and shared event
/// Nothing for a system but these need to be put somewhere in
/// Content.Shared
/// </summary>
public abstract partial class SharedVehicleSystem : EntitySystem
{
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly MovementSpeedModifierSystem _modifier = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedVirtualItemSystem _virtualItemSystem = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedJointSystem _joints = default!;
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
[Dependency] private readonly SharedMoverController _mover = default!;
[ValidatePrototypeId<TagPrototype>]
private const string Dump = "DoorBumpOpener";
[ValidatePrototypeId<TagPrototype>]
private const string Key = "VehicleKey";
private const string KeySlot = "key_slot";
public override void Initialize()
{
base.Initialize();
InitializeRider();
SubscribeLocalEvent<VehicleComponent, ComponentStartup>(OnVehicleStartup);
SubscribeLocalEvent<VehicleComponent, StrappedEvent>(OnStrapped);
SubscribeLocalEvent<VehicleComponent, UnstrappedEvent>(OnUnstrapped);
SubscribeLocalEvent<VehicleComponent, HonkActionEvent>(OnHonkAction);
SubscribeLocalEvent<VehicleComponent, EntInsertedIntoContainerMessage>(OnEntInserted);
SubscribeLocalEvent<VehicleComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
SubscribeLocalEvent<VehicleComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeedModifiers);
SubscribeLocalEvent<VehicleComponent, MoveEvent>(OnMoveEvent);
SubscribeLocalEvent<VehicleComponent, GetAdditionalAccessEvent>(OnGetAdditionalAccess);
SubscribeLocalEvent<InVehicleComponent, GettingPickedUpAttemptEvent>(OnGettingPickedUpAttempt);
}
public override void Update(float frameTime)
{
var vehicleQuery = EntityQueryEnumerator<VehicleComponent, InputMoverComponent>();
while (vehicleQuery.MoveNext(out var uid, out var vehicle, out var mover))
{
if (!vehicle.AutoAnimate)
continue;
// Why is this updating appearance data every tick, instead of when it needs to be updated???
if (_mover.GetVelocityInput(mover).Sprinting == Vector2.Zero)
{
UpdateAutoAnimate(uid, false);
continue;
}
UpdateAutoAnimate(uid, true);
}
}
private void OnVehicleStartup(Entity<VehicleComponent> ent, ref ComponentStartup args)
{
UpdateDrawDepth(ent, 2);
// This code should be purged anyway but with that being said this doesn't handle components being changed.
if (TryComp<StrapComponent>(ent, out var strap))
{
ent.Comp.BaseBuckleOffset = strap.BuckleOffset;
strap.BuckleOffset = Vector2.Zero;
}
_modifier.RefreshMovementSpeedModifiers(ent);
}
private void OnStrapped(Entity<VehicleComponent> ent, ref StrappedEvent args)
{
if (ent.Comp.UseHand == true)
{
// Add a virtual item to rider's hand, unbuckle if we can't.
if (!_virtualItemSystem.TrySpawnVirtualItemInHand(ent, args.Buckle))
{
_buckle.TryUnbuckle(args.Buckle, ent);
return;
}
}
// Set up the rider and vehicle with each other
EnsureComp<InputMoverComponent>(ent);
EnsureComp<RiderComponent>(args.Buckle).Vehicle = ent;
ent.Comp.Rider = args.Buckle.Owner;
ent.Comp.LastRider = ent.Comp.Rider;
Dirty(ent);
Appearance.SetData(ent, VehicleVisuals.HideRider, true);
_mover.SetRelay(args.Buckle.Owner, ent.Owner);
// Update appearance stuff, add actions
UpdateBuckleOffset(ent, Transform(ent));
if (TryComp<InputMoverComponent>(ent, out var mover))
UpdateDrawDepth(ent, GetDrawDepth(ent.Comp, Transform(ent), mover.RelativeRotation.Degrees));
if (TryComp<ActionsComponent>(args.Buckle, out var actions) && TryComp<UnpoweredFlashlightComponent>(ent, out var flashlight))
{
_actionsSystem.AddAction(args.Buckle, ref flashlight.ToggleActionEntity, flashlight.ToggleAction, ent, actions);
}
if (ent.Comp.HornSound != null)
{
_actionsSystem.AddAction(args.Buckle, ref ent.Comp.HornActionEntity, ent.Comp.HornAction, ent, actions);
}
_joints.ClearJoints(args.Buckle);
_tagSystem.AddTag(ent, Dump);
}
private void OnUnstrapped(Entity<VehicleComponent> ent, ref UnstrappedEvent args)
{
// Clean up actions and virtual items
_actionsSystem.RemoveProvidedActions(args.Buckle, ent);
if (ent.Comp.UseHand == true)
_virtualItemSystem.DeleteInHandsMatching(args.Buckle, ent);
// Entity is no longer riding
RemComp<RiderComponent>(args.Buckle);
RemComp<RelayInputMoverComponent>(args.Buckle);
_tagSystem.RemoveTag(ent, Dump);
Appearance.SetData(ent, VehicleVisuals.HideRider, false);
// Reset component
ent.Comp.Rider = null;
Dirty(ent);
}
private void OnHonkAction(Entity<VehicleComponent> vehicle, ref HonkActionEvent args)
{
if (args.Handled || vehicle.Comp.HornSound == null)
return;
// TODO: Need audio refactor maybe, just some way to null it when the stream is over.
// For now better to just not loop to keep the code much cleaner.
vehicle.Comp.HonkPlayingStream = _audioSystem.PlayPredicted(vehicle.Comp.HornSound, vehicle, vehicle)?.Entity;
args.Handled = true;
}
private void OnEntInserted(Entity<VehicleComponent> ent, ref EntInsertedIntoContainerMessage args)
{
if (args.Container.ID != KeySlot ||
!_tagSystem.HasTag(args.Entity, Key))
return;
// Enable vehicle
var inVehicle = EnsureComp<InVehicleComponent>(args.Entity);
inVehicle.Vehicle = ent.Comp;
ent.Comp.HasKey = true;
var msg = Loc.GetString("vehicle-use-key",
("keys", args.Entity), ("vehicle", ent));
if (_netManager.IsServer)
_popupSystem.PopupEntity(msg, ent, args.OldParent, PopupType.Medium);
// Audiovisual feedback
_ambientSound.SetAmbience(ent, true);
_modifier.RefreshMovementSpeedModifiers(ent);
}
private void OnEntRemoved(Entity<VehicleComponent> ent, ref EntRemovedFromContainerMessage args)
{
if (args.Container.ID != KeySlot || !RemComp<InVehicleComponent>(args.Entity))
return;
ent.Comp.HasKey = false;
_ambientSound.SetAmbience(ent, false);
_modifier.RefreshMovementSpeedModifiers(ent);
}
private void OnRefreshMovementSpeedModifiers(Entity<VehicleComponent> ent, ref RefreshMovementSpeedModifiersEvent args)
{
if (!ent.Comp.HasKey)
{
args.ModifySpeed(0f, 0f);
}
}
// TODO: Shitcode, needs to use sprites instead of actual offsets.
private void OnMoveEvent(Entity<VehicleComponent> ent, ref MoveEvent args)
{
if (args.NewRotation == args.OldRotation)
return;
// This first check is just for safety
if (ent.Comp.AutoAnimate && !HasComp<InputMoverComponent>(ent))
{
UpdateAutoAnimate(ent, false);
return;
}
UpdateBuckleOffset(ent, args.Component);
if (TryComp<InputMoverComponent>(ent, out var mover))
UpdateDrawDepth(ent, GetDrawDepth(ent.Comp, args.Component, mover.RelativeRotation));
}
private void OnGettingPickedUpAttempt(Entity<InVehicleComponent> ent, ref GettingPickedUpAttemptEvent args)
{
if (ent.Comp.Vehicle == null || ent.Comp.Vehicle.Rider != null && ent.Comp.Vehicle.Rider != args.User)
args.Cancel();
}
private int GetDrawDepth(VehicleComponent component, TransformComponent xform, Angle cameraAngle)
{
var itemDirection = cameraAngle.GetDir() switch
{
Direction.South => xform.LocalRotation.GetDir(),
Direction.North => xform.LocalRotation.RotateDir(Direction.North),
Direction.West => xform.LocalRotation.RotateDir(Direction.East),
Direction.East => xform.LocalRotation.RotateDir(Direction.West),
_ => Direction.South
};
return itemDirection switch
{
Direction.North => component.NorthOver
? (int)DrawDepth.DrawDepth.Doors
: (int)DrawDepth.DrawDepth.WallMountedItems,
Direction.South => component.SouthOver
? (int)DrawDepth.DrawDepth.Doors
: (int)DrawDepth.DrawDepth.WallMountedItems,
Direction.West => component.WestOver
? (int)DrawDepth.DrawDepth.Doors
: (int)DrawDepth.DrawDepth.WallMountedItems,
Direction.East => component.EastOver
? (int)DrawDepth.DrawDepth.Doors
: (int)DrawDepth.DrawDepth.WallMountedItems,
_ => (int)DrawDepth.DrawDepth.WallMountedItems
};
}
private void UpdateBuckleOffset(Entity<VehicleComponent> ent, TransformComponent xform)
{
if (!TryComp<StrapComponent>(ent, out var strap))
return;
// TODO: Strap should handle this but buckle E/C moment.
var oldOffset = strap.BuckleOffset;
strap.BuckleOffset = xform.LocalRotation.Degrees switch
{
< 45f => new(0, ent.Comp.SouthOverride),
<= 135f => ent.Comp.BaseBuckleOffset,
< 225f => new(0, ent.Comp.NorthOverride),
<= 315f => new(ent.Comp.BaseBuckleOffset.X * -1, ent.Comp.BaseBuckleOffset.Y),
_ => new(0, ent.Comp.SouthOverride)
};
if (!oldOffset.Equals(strap.BuckleOffset))
Dirty(ent, strap);
foreach (var buckledEntity in strap.BuckledEntities)
{
_transform.SetLocalPositionNoLerp(buckledEntity, strap.BuckleOffset);
}
}
private void OnGetAdditionalAccess(Entity<VehicleComponent> ent, ref GetAdditionalAccessEvent args)
{
if (ent.Comp.Rider == null)
return;
args.Entities.Add(ent.Comp.Rider.Value);
}
private void UpdateDrawDepth(EntityUid uid, int drawDepth)
{
Appearance.SetData(uid, VehicleVisuals.DrawDepth, drawDepth);
}
private void UpdateAutoAnimate(EntityUid uid, bool autoAnimate)
{
Appearance.SetData(uid, VehicleVisuals.AutoAnimate, autoAnimate);
}
}
/// <summary>
/// Stores the vehicle's draw depth mostly
/// </summary>
[Serializable, NetSerializable]
public enum VehicleVisuals : byte
{
/// <summary>
/// What layer the vehicle should draw on (assumed integer)
/// </summary>
DrawDepth,
/// <summary>
/// Whether the wheels should be turning
/// </summary>
AutoAnimate,
HideRider
}
/// <summary>
/// Raised when someone honks a vehicle horn
/// </summary>
public sealed partial class HonkActionEvent : InstantActionEvent
{
}

View File

@@ -5,6 +5,8 @@ trait-colour-blindness-name = Дальтонизм
trait-colour-blindness-desc = Вы не различаете полный спектр цветов, ващ мир бесцветный
trait-dna-deviation-name = Плохой геном
trait-dna-deviation-desc = Вы подвержены проявлению случайных генетических отклонений
trait-wheelchair-bound-name = Прикованный к инвалидной коляске
trait-wheelchair-bound-desc = Вы не можете передвигаться без инвалидной коляски. Инвалидная коляска входит в комплект!
# Quirks
trait-sneezing-name = Насморк

View File

@@ -0,0 +1,2 @@
vehicle-use-key = Вы используете {THE($keys)} для запуска {THE($vehicle)}.
vehicle-slot-component-slot-name-keys = Ключи

View File

@@ -0,0 +1,2 @@
ent-ActionVehicleHorn = Хонк
.desc = Хонк!

View File

@@ -0,0 +1,4 @@
ent-CrateFunATV = ящик с квадроциклом
.desc = Абсолютно облагаемое налогом транспортное средство, помогающее перевозить грузы.
ent-CrateFunSyndicateSegway = ящик с сигвеем
.desc = Ящик с двухколесным транспортным средством, которое поможет вам скрыться от сотрудников службы безопасности. Или нет.

View File

@@ -0,0 +1,13 @@
ent-SpawnVehicleSecway = Спавнер Секвея
.desc = { ent-MarkerBase.desc }
ent-SpawnVehicleJanicart = Спавнер Тележки уборщика
.desc = { ent-MarkerBase.desc }
ent-SpawnVehicleATV = Спавнер Квадроцикла
.desc = { ent-MarkerBase.desc }
ent-SpawnVehicleMotobike = Спавнер Скелебайка
.desc = { ent-MarkerBase.desc }
ent-SpawnVehicleWheelchair = Спавнер Инвалидной коляски
.desc = { ent-MarkerBase.desc }
ent-SpawnVehicleWheelchairFolded = Спавнер Инвалидной коляски
.desc = { ent-MarkerBase.desc }
.suffix = Сложенная

View File

@@ -0,0 +1,2 @@
ent-MobTaxiBot = таксибот
.desc = Подвезти?

View File

@@ -0,0 +1,18 @@
ent-BaseVehicle = транспорт
ent-VehicleJanicart = тележка уборщика
.desc = Верный конь дворника.
ent-VehicleJanicartDestroyed = уничтоженная тележка уборщика
.desc = { ent-MachineFrameDestroyed.desc }
ent-VehicleSecway = секвей
.desc = Будущее транспорта. Популяризирован святым Иаковом, покровителем сотрудников службы безопасности и модераторов интернет-форумов.
ent-VehicleATV = квадроцикл
.desc = Универсальное транспортное средство.
ent-VehicleSyndicateSegway = сигвей синдиката
.desc = Стань врагом корпорации в стиле.
ent-VehicleSkeletonMotorcycle = скелецикл
.desc = Bad to the Bone.
ent-VehicleWheelchair = инвалидная коляска
.desc = Кресло на больших колесиках. Похоже, в нем можно передвигаться самостоятельно.
ent-VehicleWheelchairFolded = { ent-VehicleWheelchair }
.desc = { ent-VehicleWheelchair.desc }
.suffix = Сложенное

View File

@@ -0,0 +1,12 @@
ent-VehicleKeyJanicart = ключ от тележки уборщика
.desc = Интересный дизайн.
ent-VehicleKeySecway = ключ от секвея
.desc = Ключи к будущему.
ent-VehicleKeyATV = ключи от квадроцикла
.desc = Думаете, это похоже на один ключ? Ключи от квадроцикла означают "на самом деле два ключа от транспорта".
ent-VehicleKeySkeleton = отмычки от транспорта
.desc = Разблокировка любого транспортного средства.
ent-VehicleKeySyndicateSegway = ключ от сигвея синдиката
.desc = Создан по мотивам культового дизайна EMAG.
ent-VehicleKeySkeletonMotorcycle = ключи-скелетоны для мотоцикла
.desc = Красивый набор ключей, украшенный черепом.

View File

@@ -367,6 +367,7 @@
- id: MrDips
orGroup: Giftpool
- id: RevolverCapGun
- id: VehicleUnicycleFolded # Corvax-Wega-Vehicles
- id: BalloonNT
- id: ClothingShoesClownLarge
- id: ClothingHeadHatMagician

View File

@@ -225,6 +225,7 @@
- WetFloorSign
- HolosignProjector
- Plunger
- JanicartKeys # Corvax-Wega-Vehicles
components:
- LightReplacer
- SmokeOnTrigger

View File

@@ -21,6 +21,12 @@
multiplier: 3.75
multiplierOnExisting: 0.75
- !type:Ignite
# Corvax-Wega-Vehicles-start
- !type:DamageEntityEffect
requiredComponent: Vehicle
damageType: Blunt
amount: 500
# Corvax-Wega-Vehicles-end
- type: Transform
anchored: true
- type: SyncSprite

View File

@@ -21,6 +21,12 @@
multiplier: 3.75
multiplierOnExisting: 0.75
- !type:Ignite
# Corvax-Wega-Vehicles-start
- !type:DamageEntityEffect
requiredComponent: Vehicle
damageType: Blunt
amount: 500
# Corvax-Wega-Vehicles-end
- type: Transform
anchored: true
- type: SyncSprite

View File

@@ -51,6 +51,7 @@
- RollerBedSpawnFolded
- CheapRollerBedSpawnFolded
- EmergencyRollerBedSpawnFolded
- VehicleWheelchairFolded # Corvax-Wega-Vehicles
- type: latheRecipePack
id: MedicalClothingStatic

View File

@@ -13,6 +13,8 @@
shoes: ClothingShoesBootsJack
id: PassengerPDA
ears: ClothingHeadsetGrey
pocket1: VehicleSkeletonMotorcycle # Corvax-Wega-Vehicles
pocket2: VehicleKeySkeletonMotorcycle # Corvax-Wega-Vehicles
storage:
back:
- BoxSurvival

View File

@@ -0,0 +1,10 @@
- type: entity
id: ActionVehicleHorn
name: Honk
description: Honk!
noSpawn: true
components:
- type: InstantAction
useDelay: 3.4
icon: Objects/Fun/bikehorn.rsi/icon.png
event: !type:HonkActionEvent

View File

@@ -0,0 +1,9 @@
- type: cargoProduct
id: FunATV
icon:
sprite: Objects/Vehicles/atv.rsi
state: vehicle
product: CrateFunATV
cost: 1500
category: Fun
group: market

View File

@@ -0,0 +1,21 @@
- type: entity
id: CrateFunATV
parent: CrateLivestock
name: ATV crate
description: An Absolutely Taxable Vehicle to help cargo with hauling.
components:
- type: StorageFill
contents:
- id: VehicleATV
- id: VehicleKeyATV
- type: entity
id: CrateFunSyndicateSegway
parent: CrateLivestock
name: Syndicate segway crate
description: A crate containing a two-wheeler that will help you escape from the security officers. Or not.
components:
- type: StorageFill
contents:
- id: VehicleSyndicateSegway
- id: VehicleKeySyndicateSegway

View File

@@ -59,4 +59,21 @@
Telecrystal: 6
categories:
- UplinkDeception
- type: listing
id: UplinkSyndicateSegwayCrate
name: uplink-syndicate-segway-crate-name
description: uplink-syndicate-segway-crate-desc
icon: { sprite: /Textures/Objects/Vehicles/syndicatesegway.rsi, state: icon }
productEntity: CrateFunSyndicateSegway
discountDownTo:
Telecrystal: 3
cost:
Telecrystal: 5
categories:
- UplinkMisc
conditions:
- !type:BuyerWhitelistCondition
blacklist:
components:
- SurplusBundle

View File

@@ -0,0 +1,83 @@
- type: entity
name: Secway Spawner
id: SpawnVehicleSecway
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/secway.rsi
state: keys
- type: ConditionalSpawner
prototypes:
- VehicleSecway
- type: entity
name: Janicart Spawner
id: SpawnVehicleJanicart
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/janicart.rsi
state: keys
- type: ConditionalSpawner
prototypes:
- VehicleJanicart
- type: entity
name: ATV Spawner
id: SpawnVehicleATV
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/atv.rsi
state: keys
- type: ConditionalSpawner
prototypes:
- VehicleATV
- type: entity
name: Motobike Spawner
id: SpawnVehicleMotobike
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/motorbike.rsi
state: keys
- type: ConditionalSpawner
prototypes:
- VehicleSkeletonMotorcycle
- type: entity
name: Wheelchair Spawner
id: SpawnVehicleWheelchair
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/wheelchair.rsi
state: vehicle
- type: ConditionalSpawner
prototypes:
- VehicleWheelchair
- type: entity
name: Wheelchair [Folded] Spawner
id: SpawnVehicleWheelchairFolded
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- sprite: Objects/Vehicles/wheelchair.rsi
state: vehicle_folded
- type: ConditionalSpawner
prototypes:
- VehicleWheelchairFolded

View File

@@ -0,0 +1,37 @@
- type: entity
parent: [ MobSiliconBase, BaseVehicle]
id: MobSiliconBaseVehicle # for vehicles
abstract: true
components:
- type: NoSlip
- type: GhostTakeoverAvailable
- type: GhostRole
makeSentient: true
- type: UnpoweredFlashlight
- type: PointLight
enabled: false
radius: 3.5
softness: 2
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: entity
parent: MobSiliconBaseVehicle
id: MobTaxiBot
name: taxibot
description: Give a ride?
components:
- type: Sprite
sprite: Mobs/Silicon/Bots/taxibot.rsi
layers:
- state: taxibot
map: ["enum.VehicleVisualLayers.AutoAnimate"]
- type: GhostRole
name: ghost-role-information-taxibot-name
description: ghost-role-information-taxibot-description
- type: Strap
buckleOffset: "0, 0"
maxBuckleDistance: 1
- type: Construction
graph: TaxiBot
node: bot

View File

@@ -0,0 +1,462 @@
- type: entity
id: BaseVehicle
save: false
abstract: true
components:
- type: AmbientSound
sound: "/Audio/Effects/Vehicle/vehicleengineidle.ogg"
range: 10
volume: -10
enabled: false
- type: MovementSpeedModifier
weightlessModifier: 0
baseAcceleration: 2
baseFriction: 2
frictionNoInput: 6
baseWalkSpeed: 4.5
baseSprintSpeed: 6
- type: Repairable
fuelcost: 20
doAfterDelay: 20
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 600
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTrigger
damage: 300
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- !type:PlaySoundBehavior
sound:
collection: MetalGlassBreak
- !type:ExplodeBehavior
- type: entity
parent: BaseVehicle
id: BaseVehicleRideable
abstract: true
name: Vehicle
components:
- type: Strap
buckleOffset: "0.10, 0.36"
maxBuckleDistance: 1
- type: InputMover
- type: InteractionOutline
- type: Vehicle
- type: Pullable
- type: Physics
bodyType: KinematicController
- type: Clickable
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.4
density: 360
restitution: 0.0
mask:
- MobMask
layer:
- TableLayer
- type: Appearance
- type: ItemSlots
slots:
key_slot: #this slot name is important
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
- type: StaticPrice
price: 750 # Grand Theft Auto.
- type: entity
id: VehicleJanicart
parent: BaseVehicleRideable
name: janicart
description: The janitor's trusty steed.
components:
- type: Vehicle
southOver: true
westOver: true
eastOver: true
northOverride: -0.15
southOverride: 0.22
- type: Sprite
sprite: Objects/Vehicles/janicart.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate"]
noRot: true
- type: UnpoweredFlashlight
- type: PointLight
enabled: false
radius: 3.5
softness: 2
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 500
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTrigger
damage: 250
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- !type:PlaySoundBehavior
sound:
collection: MetalGlassBreak
- !type:ExplodeBehavior
- !type:SpawnEntitiesBehavior # in future should also emit a cloud of hot gas
spawn:
VehicleJanicartDestroyed:
min: 1
max: 1
- type: ItemSlots
slots:
key_slot:
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
- JanicartKeys
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
trashbag_slot:
name: janitorial-trolley-slot-component-slot-name-trashbag
whitelist:
tags:
- TrashBag
- type: ItemMapper
mapLayers:
storage:
whitelist:
tags:
- TrashBag
sprite: Objects/Vehicles/janicart.rsi
- type: Appearance
- type: entity
id: VehicleJanicartDestroyed
parent: MachineFrameDestroyed
name: destroyed janicart
components:
- type: Sprite
sprite: Objects/Vehicles/janicart.rsi
state: destroyed
- type: entity
id: VehicleSecway
parent: BaseVehicleRideable
name: secway
description: The future of transportation. Popularized by St. James, the patron saint of security officers and internet forum moderators.
components:
- type: Vehicle
northOver: true
westOver: true
eastOver: true
northOverride: -0.1
southOverride: 0.1
hornSound:
path: /Audio/Effects/Vehicle/policesiren.ogg
- type: Sprite
sprite: Objects/Vehicles/secway.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate"]
noRot: true
- type: Strap
buckleOffset: "0.15, -0.05"
maxBuckleDistance: 1
- type: MovementSpeedModifier
baseAcceleration: 1
baseFriction: 1
baseWalkSpeed: 4.5
baseSprintSpeed: 6
- type: Armor
modifiers:
coefficients:
Blunt: 0.8
Slash: 0.6
Piercing: 0.85
- type: ItemSlots
slots:
key_slot:
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
- SecwayKeys
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
- type: StealTarget
stealGroup: VehicleSecway
- type: entity
parent: BaseVehicleRideable
id: VehicleATV
name: ATV
description: All-Tile Vehicle.
components:
- type: Vehicle
southOver: true
northOver: true
northOverride: -0.1
southOverride: 0.1
- type: Sprite
sprite: Objects/Vehicles/atv.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate"]
noRot: true
# - type: RandomMetadata
# descriptionSegments: [ATVDescriptions]
- type: MovementSpeedModifier
baseAcceleration: 1
baseFriction: 1
baseWalkSpeed: 4.5
baseSprintSpeed: 7
- type: Strap
buckleOffset: "0.1, -0.05"
maxBuckleDistance: 1
- type: UnpoweredFlashlight
- type: PointLight
enabled: false
radius: 3.5
softness: 2
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: ItemSlots
slots:
key_slot:
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
- ATVKeys
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
- type: entity
id: VehicleSyndicateSegway
parent: BaseVehicleRideable
name: syndicate segway
description: Be an enemy of the corporation, in style.
components:
- type: Vehicle
southOver: true
westOver: true
eastOver: true
northOverride: -0.1
southOverride: 0.1
hornSound:
path: /Audio/Effects/Vehicle/policesiren.ogg
- type: Sprite
sprite: Objects/Vehicles/syndicatesegway.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate"]
noRot: true
- type: Strap
buckleOffset: "0.15, -0.05"
maxBuckleDistance: 1
- type: Armor
modifiers:
coefficients:
Blunt: 0.8
Slash: 0.6
Piercing: 0.85
- type: ItemSlots
slots:
key_slot:
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
- SyndicateSegwayKeys
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
- type: entity
parent: BaseVehicleRideable
id: VehicleSkeletonMotorcycle
name: skeleton motorcycle
description: Bad to the Bone.
components:
- type: Vehicle
southOver: true
northOver: true
northOverride: -0.1
southOverride: 0.1
- type: Sprite
sprite: Objects/Vehicles/motorbike.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate"]
noRot: true
- type: Strap
buckleOffset: "0.1, -0.05"
maxBuckleDistance: 1
- type: MovementSpeedModifier
baseAcceleration: 2
baseFriction: 1.5
baseWalkSpeed: 4.5
baseSprintSpeed: 7
- type: UnpoweredFlashlight
- type: PointLight
enabled: false
radius: 3.5
softness: 2
mask: /Textures/Effects/LightMasks/cone.png
autoRot: true
- type: ItemSlots
slots:
key_slot:
name: vehicle-slot-component-slot-name-keys
whitelist:
requireAll: true
tags:
- VehicleKey
- SkeletonMotorcycleKeys
insertSound:
path: /Audio/Effects/Vehicle/vehiclestartup.ogg
params:
volume: -3
- type: entity
id: VehicleUnicycle
parent: [BaseVehicleRideable, BaseFoldable, BaseItem]
name: unicycle
description: It only has one wheel!
components:
- type: Vehicle
northOver: true
southOver: true
northOverride: -0.15
southOverride: 0.15
hasKey: true
hornSound:
path: /Audio/Effects/Vehicle/bicyclebell.ogg
- type: Sprite
sprite: Objects/Vehicles/unicycle.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate", "unfoldedLayer"]
- state: vehicle_folded
map: ["foldedLayer"]
visible: false
noRot: true
- type: Strap
buckleOffset: "0.1, -0.05"
maxBuckleDistance: 1
- type: MovementSpeedModifier
baseAcceleration: 1
baseFriction: 0.8
baseWalkSpeed: 3.5
baseSprintSpeed: 4.3
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 200
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTrigger
damage: 240
behaviors:
- !type:DoActsBehavior
acts: ["Destruction"]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- type: entity
parent: VehicleUnicycle
id: VehicleUnicycleFolded
suffix: folded
components:
- type: Foldable
folded: true
- type: entity
id: VehicleWheelchair
parent: [BaseVehicleRideable, BaseFoldable, BaseItem]
name: wheelchair
description: A chair with big wheels. It looks like you can move in these on your own.
components:
- type: Vehicle
northOver: true
hasKey: true
northOverride: 0
southOverride: 0
- type: Sprite
sprite: Objects/Vehicles/wheelchair.rsi
layers:
- state: vehicle
map: ["enum.VehicleVisualLayers.AutoAnimate", "unfoldedLayer"]
- state: vehicle_folded
map: ["foldedLayer"]
visible: false
noRot: true
- type: MovementSpeedModifier
baseWalkSpeed: 2
baseSprintSpeed: 2
- type: Strap
buckleOffset: "0,0"
maxBuckleDistance: 1
- type: Fixtures
fixtures:
fix1:
shape:
!type:PhysShapeCircle
radius: 0.2
density: 360
restitution: 0.0
mask:
- MobMask
layer:
- TableLayer
- type: StaticPrice
price: 70
- type: entity
parent: VehicleWheelchair
id: VehicleWheelchairFolded
suffix: folded
components:
- type: Foldable
folded: true

View File

@@ -0,0 +1,86 @@
- type: entity
parent: BaseItem
id: VehicleKeyJanicart
name: janicart keys
description: Interesting design.
components:
- type: Item
size: Tiny
- type: Tag
tags:
- VehicleKey
- JanicartKeys
- type: Sprite
sprite: Objects/Vehicles/janicart.rsi
state: keys
- type: entity
parent: VehicleKeyJanicart
id: VehicleKeySecway
name: secway keys
description: The keys to the future.
components:
- type: Tag
tags:
- VehicleKey
- SecwayKeys
- type: Sprite
sprite: Objects/Vehicles/secway.rsi
state: keys
- type: entity
parent: VehicleKeyJanicart
id: VehicleKeyATV
name: ATV keys
description: Think this looks like just one key? ATV keys means "actually two vehicle keys."
components:
- type: Tag
tags:
- VehicleKey
- ATVKeys
- type: Sprite
sprite: Objects/Vehicles/atv.rsi
state: keys
- type: entity
parent: VehicleKeyATV
id: VehicleKeySkeleton
name: vehicle skeleton keys
description: Unlock any vehicle.
components:
- type: Tag
tags:
- VehicleKey
- JanicartKeys
- SecwayKeys
- ATVKeys
- SyndicateSegwayKeys
- SkeletonMotorcycleKeys
- type: entity
parent: VehicleKeyJanicart
id: VehicleKeySyndicateSegway
name: syndicate segway keys
description: Patterned after the iconic EMAG design.
components:
- type: Tag
tags:
- VehicleKey
- SyndicateSegwayKeys
- type: Sprite
sprite: Objects/Vehicles/syndicatesegway.rsi
state: keys
- type: entity
parent: VehicleKeyATV
id: VehicleKeySkeletonMotorcycle
name: skeleton motorcycle keys
description: A beautiful set of keys adorned with a skull.
components:
- type: Tag
tags:
- VehicleKey
- SkeletonMotorcycleKeys
- type: Sprite
sprite: Objects/Vehicles/motorbike.rsi
state: keys

View File

@@ -0,0 +1,29 @@
- type: constructionGraph
id: TaxiBot
start: start
graph:
- node: start
edges:
- to: bot
steps:
- tag: ProximitySensor
icon:
sprite: Objects/Misc/proximity_sensor.rsi
state: icon
name: proximity sensor
- tag: BorgHead
icon:
sprite: Objects/Specific/Robotics/cyborg_parts.rsi
state: borg_head
name: borg head
doAfter: 1
- tag: BorgArm
icon:
sprite: Mobs/Silicon/drone.rsi
state: l_hand
name: borg arm
doAfter: 2
- material: Steel
amount: 5
- node: bot
entity: MobTaxiBot

View File

@@ -0,0 +1,12 @@
- type: construction
name: taxibot
id: taxibot
graph: TaxiBot
startNode: start
targetNode: bot
category: construction-category-utilities
objectType: Item
description: This bot takes people to their destination.
icon:
sprite: Mobs/Silicon/Bots/taxibot.rsi
state: taxibot

View File

@@ -0,0 +1,7 @@
- type: latheRecipe
id: VehicleWheelchairFolded
result: VehicleWheelchairFolded
completetime: 1
materials:
Steel: 500
Plastic: 300

View File

@@ -24,3 +24,16 @@
category: Disabilities
components:
- type: DnaModifierDeviation
- type: trait
id: WheelchairBound
name: trait-wheelchair-bound-name
description: trait-wheelchair-bound-desc
category: Disabilities
blacklist:
components:
- BorgChassis
components:
- type: BuckleOnMapInit
prototype: VehicleWheelchair
- type: LegsParalyzed

View File

@@ -107,3 +107,9 @@
- type: Tag
id: RightFoot
# Surgery end
- type: Tag
id: JanicartKeys
- type: Tag
id: VehicleKey