Permalink
Cannot retrieve contributors at this time
707 lines (655 sloc)
22.5 KB
| using System; | |
| using System.Drawing; | |
| using System.Security.Policy; | |
| using GTA; | |
| using GTA.Native; | |
| using GTA.Math; | |
| using Hash = GTA.Native.Hash; | |
| namespace GTA | |
| { | |
| [Flags] | |
| public enum InvertAxis | |
| { | |
| None = 0, | |
| X = 1, | |
| Y = 2, | |
| Z = 4 | |
| } | |
| public class ParticleEffectsAsset | |
| { | |
| #region Fields | |
| private readonly string _assetName; | |
| #endregion | |
| /// <summary> | |
| /// Creates a class used for loading <see cref="ParticleEffectsAsset"/>s than can be used to start <see cref="ParticleEffect"/>s from inside the Asset | |
| /// </summary> | |
| /// <param name="assetName">The name of the asset file which contains all the <see cref="ParticleEffect"/>s you are wanting to start</param> | |
| /// <remarks>The files have the extension *.ypt in OpenIV, use the file name withouth the extension for the <paramref name="assetName"/></remarks> | |
| public ParticleEffectsAsset(string assetName) | |
| { | |
| _assetName = assetName; | |
| } | |
| /// <summary> | |
| /// Gets the name of the this <see cref="ParticleEffectsAsset"/> file | |
| /// </summary> | |
| public string AssetName | |
| { | |
| get { return _assetName; } | |
| } | |
| /// <summary> | |
| /// Gets a value indicating whether this <see cref="ParticleEffectsAsset"/> is Loaded | |
| /// </summary> | |
| /// <remarks>Use <see cref="Request()"/> or <see cref="Request(int)"/> to load the asset</remarks> | |
| public bool IsLoaded | |
| { | |
| get { return Function.Call<bool>(Hash.HAS_NAMED_PTFX_ASSET_LOADED, _assetName); } | |
| } | |
| /// <summary> | |
| /// Starts a Particle Effect that runs once at a given position then is destroyed. | |
| /// </summary> | |
| /// <param name="effectName">The name of the effect.</param> | |
| /// <param name="pos">The World position where the effect is.</param> | |
| /// <param name="rot">What rotation to apply to the effect.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in.</param> | |
| /// <returns><c>true</c>If the effect was able to start; otherwise, <c>false</c>.</returns> | |
| public bool StartNonLoopedAtCoord(string effectName, Vector3 pos, Vector3 rot = default(Vector3), float scale = 1.0f, InvertAxis invertAxis = InvertAxis.None) | |
| { | |
| if (!SetNextCall()) | |
| { | |
| return false; | |
| } | |
| Function.Call(Hash._USE_PARTICLE_FX_ASSET_NEXT_CALL, _assetName); | |
| return Function.Call<bool>(Hash.START_PARTICLE_FX_NON_LOOPED_AT_COORD, effectName, pos.X, pos.Y, pos.Z, rot.X, rot.Y, | |
| rot.Z, scale, invertAxis.HasFlag(InvertAxis.X), invertAxis.HasFlag(InvertAxis.Y), invertAxis.HasFlag(InvertAxis.Z)); | |
| } | |
| /// <summary> | |
| /// Starts a Particle Effect on an <see cref="Entity"/> that runs once then is destroyed. | |
| /// </summary> | |
| /// <param name="effectName">the name of the effect.</param> | |
| /// <param name="entity">The <see cref="Entity"/> the effect is attached to.</param> | |
| /// <param name="off">The offset from the <paramref name="entity"/> to attach the effect.</param> | |
| /// <param name="rot">The rotation, relative to the <paramref name="entity"/>, the effect has.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in. For a car side exahust you may need to flip in the Y Axis</param> | |
| /// <returns><c>true</c>If the effect was able to start; otherwise, <c>false</c>.</returns> | |
| public bool StartNonLoopedOnEntity(string effectName, Entity entity, Vector3 off = default(Vector3), Vector3 rot = default(Vector3), float scale = 1.0f, InvertAxis invertAxis = InvertAxis.None) | |
| { | |
| if (!SetNextCall()) | |
| { | |
| return false; | |
| } | |
| Function.Call(Hash._USE_PARTICLE_FX_ASSET_NEXT_CALL, _assetName); | |
| return Function.Call<bool>(Hash.START_PARTICLE_FX_NON_LOOPED_ON_PED_BONE, effectName, entity.Handle, off.X, off.Y, off.Z, rot.X, | |
| rot.Y, rot.Z, -1, scale, invertAxis.HasFlag(InvertAxis.X), invertAxis.HasFlag(InvertAxis.Y), | |
| invertAxis.HasFlag(InvertAxis.Z)); | |
| } | |
| /// <summary> | |
| /// Starts a Particle Effect on an <see cref="EntityBone"/> that runs once then is destroyed. | |
| /// </summary> | |
| /// <param name="effectName">the name of the effect.</param> | |
| /// <param name="entityBone">The <see cref="EntityBone"/> the effect is attached to.</param> | |
| /// <param name="off">The offset from the <paramref name="entityBone"/> to attach the effect.</param> | |
| /// <param name="rot">The rotation, relative to the <paramref name="entityBone"/>, the effect has.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in. For a car side exahust you may need to flip in the Y Axis</param> | |
| /// <returns><c>true</c>If the effect was able to start; otherwise, <c>false</c>.</returns> | |
| public bool StartNonLoopedOnEntity(string effectName, EntityBone entityBone, | |
| Vector3 off = default(Vector3), Vector3 rot = default(Vector3), float scale = 1.0f, | |
| InvertAxis invertAxis = InvertAxis.None) | |
| { | |
| if(!SetNextCall()) | |
| { | |
| return false; | |
| } | |
| Function.Call(Hash._USE_PARTICLE_FX_ASSET_NEXT_CALL, _assetName); | |
| return Function.Call<bool>(Hash.START_PARTICLE_FX_NON_LOOPED_ON_PED_BONE, effectName, entityBone.Owner.Handle, off.X, off.Y, off.Z, rot.X, | |
| rot.Y, rot.Z, entityBone, scale, invertAxis.HasFlag(InvertAxis.X), invertAxis.HasFlag(InvertAxis.Y), | |
| invertAxis.HasFlag(InvertAxis.Z)); | |
| } | |
| /// <summary> | |
| /// Creates a <see cref="ParticleEffect"/> on an <see cref="Entity"/> that runs looped. | |
| /// </summary> | |
| /// <param name="effectName">The name of the Effect</param> | |
| /// <param name="entity">The <see cref="Entity"/> the effect is attached to.</param> | |
| /// <param name="off">The offset from the <paramref name="entity"/> to attach the effect.</param> | |
| /// <param name="rot">The rotation, relative to the <paramref name="entity"/>, the effect has.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in. For a car side exahust you may need to flip in the Y Axis.</param> | |
| /// <param name="startNow">if <c>true</c> attempt to start this effect now; otherwise, the effect will start when <see cref="ParticleEffect.Start"/> is called.</param> | |
| /// <returns>The <see cref="EntityParticleEffect"/> represented by this that can be used to start/stop/modify this effect</returns> | |
| public EntityParticleEffect CreateEffectOnEntity(string effectName, Entity entity, | |
| Vector3 off = default(Vector3), Vector3 rot = default(Vector3), float scale = 1.0f, | |
| InvertAxis invertAxis = InvertAxis.None, bool startNow = false) | |
| { | |
| var result = new EntityParticleEffect(this, effectName, entity) | |
| { | |
| Offset = off, | |
| Rotation = rot, | |
| Scale = scale, | |
| InvertAxis = invertAxis | |
| }; | |
| if (startNow) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Creates a <see cref="ParticleEffect"/> on an <see cref="EntityBone"/> that runs looped. | |
| /// </summary> | |
| /// <param name="effectName">The name of the Effect</param> | |
| /// <param name="entityBone">The <see cref="EntityBone"/> the effect is attached to.</param> | |
| /// <param name="off">The offset from the <paramref name="entityBone"/> to attach the effect.</param> | |
| /// <param name="rot">The rotation, relative to the <paramref name="entityBone"/>, the effect has.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in. For a car side exahust you may need to flip in the Y Axis.</param> | |
| /// <param name="startNow">if <c>true</c> attempt to start this effect now; otherwise, the effect will start when <see cref="ParticleEffect.Start"/> is called.</param> | |
| /// <returns>The <see cref="EntityParticleEffect"/> represented by this that can be used to start/stop/modify this effect</returns> | |
| public EntityParticleEffect CreateEffectOnEntity(string effectName, EntityBone entityBone, | |
| Vector3 off = default(Vector3), Vector3 rot = default(Vector3), float scale = 1.0f, | |
| InvertAxis invertAxis = InvertAxis.None, bool startNow = false) | |
| { | |
| var result = new EntityParticleEffect(this, effectName, entityBone) | |
| { | |
| Offset = off, | |
| Rotation = rot, | |
| Scale = scale, | |
| InvertAxis = invertAxis | |
| }; | |
| if(startNow) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Creates a <see cref="ParticleEffect"/> at a position that runs looped. | |
| /// </summary> | |
| /// <param name="effectName">The name of the effect.</param> | |
| /// <param name="pos">The World position where the effect is.</param> | |
| /// <param name="rot">What rotation to apply to the effect.</param> | |
| /// <param name="scale">How much to scale the size of the effect by.</param> | |
| /// <param name="invertAxis">Which axis to flip the effect in.</param> | |
| /// <param name="startNow">if <c>true</c> attempt to start this effect now; otherwise, the effect will start when <see cref="ParticleEffect.Start"/> is called.</param> | |
| /// <returns>The <see cref="CoordinateParticleEffect"/> represented by this that can be used to start/stop/modify this effect</returns> | |
| public CoordinateParticleEffect CreateEffectAtCoord(string effectName, Vector3 pos, Vector3 rot = default(Vector3), float scale = 1.0f, | |
| InvertAxis invertAxis = InvertAxis.None, bool startNow = false) | |
| { | |
| var result = new CoordinateParticleEffect(this, effectName, pos) | |
| { | |
| Rotation = rot, | |
| Scale = scale, | |
| InvertAxis = invertAxis | |
| }; | |
| if (startNow) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Sets the <see cref="Color"/> for all NonLooped Particle Effects | |
| /// </summary> | |
| static Color NonLoopedColor | |
| { | |
| set | |
| { | |
| Function.Call(Hash.SET_PARTICLE_FX_NON_LOOPED_COLOUR, value.R/255f, value.G/255f, value.B/255f); | |
| Function.Call(Hash.SET_PARTICLE_FX_NON_LOOPED_ALPHA, value.A / 255f); | |
| } | |
| } | |
| /// <summary> | |
| /// Attempts to load this <see cref="ParticleEffectsAsset"/> into memory so it can be used for starting <see cref="ParticleEffect"/>s. | |
| /// </summary> | |
| public void Request() | |
| { | |
| Function.Call(Hash.REQUEST_NAMED_PTFX_ASSET, _assetName); | |
| } | |
| /// <summary> | |
| /// Attempts to load this <see cref="ParticleEffectsAsset"/> into memory so it can be used for starting <see cref="ParticleEffect"/>s. | |
| /// </summary> | |
| /// <param name="timeout">How long in milli-seconds should the game wait while the model hasnt been loaded before giving up</param> | |
| /// <returns><c>true</c> if the <see cref="ParticleEffectsAsset"/> is Loaded; otherwise, <c>false</c></returns> | |
| public bool Request(int timeout) | |
| { | |
| Request(); | |
| DateTime endtime = timeout >= 0 ? DateTime.UtcNow + new TimeSpan(0, 0, 0, 0, timeout) : DateTime.MaxValue; | |
| while (!IsLoaded) | |
| { | |
| Script.Yield(); | |
| if (DateTime.UtcNow >= endtime) | |
| { | |
| return false; | |
| } | |
| Request(); | |
| } | |
| return true; | |
| } | |
| internal bool SetNextCall() | |
| { | |
| Request(); | |
| if (IsLoaded) | |
| { | |
| Function.Call(Hash._USE_PARTICLE_FX_ASSET_NEXT_CALL, _assetName); | |
| return true; | |
| } | |
| return false; | |
| } | |
| /// <summary> | |
| /// Tells the game we have finished using this <see cref="ParticleEffectsAsset"/> and it can be freed from memory | |
| /// </summary> | |
| public void MarkAsNoLongerNeeded() | |
| { | |
| Function.Call(Hash._REMOVE_NAMED_PTFX_ASSET, _assetName); | |
| } | |
| public override string ToString() | |
| { | |
| return _assetName; | |
| } | |
| public override int GetHashCode() | |
| { | |
| return _assetName.GetHashCode(); | |
| } | |
| public static implicit operator InputArgument(ParticleEffectsAsset asset) | |
| { | |
| return new InputArgument(asset._assetName); | |
| } | |
| } | |
| public abstract class ParticleEffect | |
| { | |
| #region Fields | |
| protected readonly ParticleEffectsAsset _asset; | |
| protected readonly string _effectName; | |
| protected Vector3 _offset; | |
| protected Vector3 _rotation; | |
| protected Color _color; | |
| protected float _scale; | |
| protected float _range; | |
| protected InvertAxis _InvertAxis; | |
| #endregion | |
| internal ParticleEffect(ParticleEffectsAsset asset, string effectName) | |
| { | |
| Handle = -1; | |
| _asset = asset; | |
| _effectName = effectName; | |
| } | |
| /// <summary> | |
| /// Gets the Handle of this <see cref="ParticleEffect"/> | |
| /// </summary> | |
| /// <value> | |
| /// The handle, will return -1 when the this <see cref="ParticleEffect"/> is not active | |
| /// </value> | |
| public int Handle { get; protected set; } | |
| /// <summary> | |
| /// Gets a value indicating whether this <see cref="ParticleEffect"/> is active. | |
| /// </summary> | |
| /// <value> | |
| /// <c>true</c> if this <see cref="ParticleEffect"/> is active; otherwise, <c>false</c>. | |
| /// </value> | |
| public bool IsActive | |
| { | |
| get { return Handle != -1 && Function.Call<bool>(Hash.DOES_PARTICLE_FX_LOOPED_EXIST, Handle); } | |
| } | |
| public abstract bool Start(); | |
| /// <summary> | |
| /// Deletes this <see cref="ParticleEffect"/>. | |
| /// </summary> | |
| public void Stop() | |
| { | |
| if (IsActive) | |
| { | |
| Function.Call(Hash.REMOVE_PARTICLE_FX, Handle, false); | |
| } | |
| Handle = -1; | |
| } | |
| /// <summary> | |
| /// Gets the memory address where this <see cref="ParticleEffect"/> is located in game memory. | |
| /// </summary> | |
| public IntPtr MemoryAddress | |
| { | |
| get { return IsActive ? MemoryAccess.GetPtfxAddress(Handle) : IntPtr.Zero; } | |
| } | |
| /// <summary> | |
| /// Gets or sets the offset. | |
| /// If this <see cref="ParticleEffect"/> is attached to an <see cref="Entity"/>, this refers to the offset from the <see cref="Entity"/>; | |
| /// otherwise, this refers to its position in World coords | |
| /// </summary> | |
| public Vector3 Offset | |
| { | |
| get | |
| { | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| address = MemoryAccess.ReadPtr(address + 32); | |
| if (address != IntPtr.Zero) | |
| { | |
| return _offset = MemoryAccess.ReadVector3(address + 144); | |
| } | |
| } | |
| return _offset; | |
| } | |
| set | |
| { | |
| _offset = value; | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| address = MemoryAccess.ReadPtr(address + 32); | |
| if (address != IntPtr.Zero) | |
| { | |
| MemoryAccess.WriteVector3(address + 144, value); | |
| } | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or Sets the rotation of this <see cref="ParticleEffect"/> | |
| /// </summary> | |
| public Vector3 Rotation | |
| { | |
| get | |
| { | |
| return _rotation; | |
| } | |
| set | |
| { | |
| _rotation = value; | |
| if (IsActive) | |
| { | |
| //rotation information is stored in a matrix | |
| Vector3 off = Offset; | |
| Function.Call(Hash.SET_PARTICLE_FX_LOOPED_OFFSETS, Handle, off.X, off.Y, off.Z, value.X, value.Y, value.Z); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or sets the <see cref="Color"/> of this <see cref="ParticleEffect"/>. | |
| /// </summary> | |
| public Color Color | |
| { | |
| get | |
| { | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| address = MemoryAccess.ReadPtr(address + 32) + 320; | |
| byte r = Convert.ToByte(MemoryAccess.ReadFloat(address)*255f); | |
| byte g = Convert.ToByte(MemoryAccess.ReadFloat(address+4)*255f); | |
| byte b = Convert.ToByte(MemoryAccess.ReadFloat(address+8) * 255f); | |
| byte a = Convert.ToByte(MemoryAccess.ReadFloat(address+12) * 255f); | |
| return _color = Color.FromArgb(a, r, g, b); | |
| } | |
| return _color; | |
| } | |
| set | |
| { | |
| _color = value; | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| address = MemoryAccess.ReadPtr(address + 32) + 320; | |
| MemoryAccess.WriteFloat(address, value.R / 255f); | |
| MemoryAccess.WriteFloat(address + 4, value.G / 255f); | |
| MemoryAccess.WriteFloat(address + 8, value.B / 255f); | |
| MemoryAccess.WriteFloat(address + 12, value.A / 255f); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or sets the size scaling factor of this <see cref="ParticleEffect"/> | |
| /// </summary> | |
| /// <value> | |
| /// The scale, default = 1.0f; | |
| /// To Decrease the size use a value less than 1.0f; | |
| /// To Increase the size use a value greater than 1.0f; | |
| /// </value> | |
| public float Scale | |
| { | |
| get | |
| { | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| return _scale = MemoryAccess.ReadFloat(MemoryAccess.ReadPtr(address + 32) + 336); | |
| } | |
| return _scale; | |
| } | |
| set | |
| { | |
| _scale = value; | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| MemoryAccess.WriteFloat(MemoryAccess.ReadPtr(address + 32) + 336, value); | |
| } | |
| } | |
| } | |
| public float Range | |
| { | |
| get | |
| { | |
| IntPtr address = MemoryAddress; | |
| if (address != IntPtr.Zero) | |
| { | |
| return _range = MemoryAccess.ReadFloat(MemoryAccess.ReadPtr(address + 32) + 384); | |
| } | |
| return _range; | |
| } | |
| set | |
| { | |
| _range = value; | |
| Function.Call(Hash._SET_PARTICLE_FX_LOOPED_RANGE, Handle, value); | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or sets which axis of this <see cref="ParticleEffect"/> should be inverted. | |
| /// </summary> | |
| public InvertAxis InvertAxis | |
| { | |
| get | |
| { | |
| return _InvertAxis; | |
| } | |
| set | |
| { | |
| _InvertAxis = value; | |
| if (IsActive) | |
| { | |
| Stop(); | |
| Start(); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Modifys parameters of this <see cref="ParticleEffect"/>. | |
| /// </summary> | |
| /// <param name="parameterName">Name of the parameter you want to modify, these are stored inside the effect files.</param> | |
| /// <param name="value">The new value for the parameter.</param> | |
| public void SetParameter(string parameterName, float value) | |
| { | |
| if (IsActive) | |
| Function.Call(Hash.SET_PARTICLE_FX_LOOPED_EVOLUTION, parameterName, value, 0); | |
| } | |
| /// <summary> | |
| /// Gets the name of the asset this effect is stored in. | |
| /// </summary> | |
| public string AssetName | |
| { | |
| get { return _asset.AssetName; } | |
| } | |
| /// <summary> | |
| /// Gets the name of this effect. | |
| /// </summary> | |
| public string EffectName | |
| { | |
| get { return _effectName; } | |
| } | |
| public override string ToString() | |
| { | |
| return string.Format("{0}\\{1}", AssetName, EffectName); | |
| } | |
| public static implicit operator InputArgument(ParticleEffect effect) | |
| { | |
| //we only need to worry about supplying a particle effect to a native, never returning one | |
| return new InputArgument(effect.Handle); | |
| } | |
| } | |
| public class EntityParticleEffect : ParticleEffect | |
| { | |
| #region Fields | |
| private EntityBone _entityBone; | |
| #endregion | |
| internal EntityParticleEffect(ParticleEffectsAsset asset, string effectName, Entity entity) | |
| : base(asset, effectName) | |
| { | |
| _entityBone = entity.Bones.Core; | |
| } | |
| internal EntityParticleEffect(ParticleEffectsAsset asset, string effectName, EntityBone entitybone) | |
| : base(asset, effectName) | |
| { | |
| _entityBone = entitybone; | |
| } | |
| /// <summary> | |
| /// Gets or sets the <see cref="GTA.Entity"/> this <see cref="EntityParticleEffect"/> is attached to. | |
| /// </summary> | |
| public Entity Entity | |
| { | |
| get { return _entityBone.Owner; } | |
| set | |
| { | |
| _entityBone = value.Bones.Core; | |
| if (IsActive) | |
| { | |
| Stop(); | |
| Start(); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or sets the <see cref="EntityBone"/> that this <see cref="EntityParticleEffect"/> is attached to. | |
| /// </summary> | |
| public EntityBone Bone | |
| { | |
| get { return _entityBone;} | |
| set | |
| { | |
| _entityBone = value; | |
| if (IsActive) | |
| { | |
| Stop(); | |
| Start(); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Starts this <see cref="EntityParticleEffect"/>. | |
| /// </summary> | |
| /// <returns><c>true</c> if this <see cref="EntityParticleEffect"/> was sucessfully started; otherwise, <c>false</c>.</returns> | |
| public override bool Start() | |
| { | |
| Stop(); | |
| if (!_asset.SetNextCall()) | |
| return false; | |
| Hash hash = _entityBone.Owner is Ped ? Hash.START_PARTICLE_FX_LOOPED_ON_PED_BONE : Hash._START_PARTICLE_FX_LOOPED_ON_ENTITY_BONE; | |
| Handle = Function.Call<int>(hash, _effectName, _entityBone.Owner.Handle, Offset.X, Offset.Y, Offset.Z, Rotation.X, | |
| Rotation.Y, Rotation.Z, _entityBone.Index, _scale, InvertAxis.HasFlag(InvertAxis.X), InvertAxis.HasFlag(InvertAxis.Y), | |
| InvertAxis.HasFlag(InvertAxis.Z)); | |
| if (IsActive) | |
| return true; | |
| Handle = -1; | |
| return false; | |
| } | |
| /// <summary> | |
| /// Creates a copy of this <see cref="EntityParticleEffect"/> to another <see cref="GTA.Entity"/> to simplify applying the same effect to many Entities. | |
| /// </summary> | |
| /// <param name="entity">The <see cref="GTA.Entity"/> to copy to.</param> | |
| /// <returns>An <see cref="EntityParticleEffect"/> that has all the same properties as this instance, but for a different <see cref="GTA.Entity"/>.</returns> | |
| public EntityParticleEffect CopyTo(Entity entity) | |
| { | |
| var result = new EntityParticleEffect(_asset, _effectName, entity) | |
| { | |
| Bone = entity.Bones[_entityBone.Index], | |
| Offset = _offset, | |
| Rotation = _rotation, | |
| Color = _color, | |
| Scale = _scale, | |
| Range = _range, | |
| InvertAxis = _InvertAxis | |
| }; | |
| if (IsActive) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Creates a copy of this <see cref="EntityParticleEffect"/> to another <see cref="GTA.EntityBone"/> to simplify applying the same effect to many Entities. | |
| /// </summary> | |
| /// <param name="entityBone">The <see cref="GTA.EntityBone"/> to copy to.</param> | |
| /// <returns>An <see cref="EntityParticleEffect"/> that has all the same properties as this instance, but for a different <see cref="GTA.EntityBone"/>.</returns> | |
| public EntityParticleEffect CopyTo(EntityBone entityBone) | |
| { | |
| var result = new EntityParticleEffect(_asset, _effectName, entityBone) | |
| { | |
| Offset = _offset, | |
| Rotation = _rotation, | |
| Color = _color, | |
| Scale = _scale, | |
| Range = _range, | |
| InvertAxis = _InvertAxis | |
| }; | |
| if(IsActive) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| } | |
| public class CoordinateParticleEffect : ParticleEffect | |
| { | |
| public CoordinateParticleEffect(ParticleEffectsAsset asset, string effectName, Vector3 location) : base(asset, effectName) | |
| { | |
| Offset = location; | |
| } | |
| /// <summary> | |
| /// Starts this <see cref="CoordinateParticleEffect"/>. | |
| /// </summary> | |
| /// <returns><c>true</c> if this <see cref="CoordinateParticleEffect"/> was sucessfully started; otherwise, <c>false</c>.</returns> | |
| public override bool Start() | |
| { | |
| Stop(); | |
| if (!_asset.SetNextCall()) | |
| return false; | |
| Handle = Function.Call<int>(Hash.START_PARTICLE_FX_LOOPED_AT_COORD, _effectName, Offset.X, Offset.Y, Offset.Z, Rotation.X, | |
| Rotation.Y, Rotation.Z, Scale, InvertAxis.HasFlag(InvertAxis.X), InvertAxis.HasFlag(InvertAxis.Y), | |
| InvertAxis.HasFlag(InvertAxis.Z), false); | |
| if (IsActive) | |
| return true; | |
| Handle = -1; | |
| return false; | |
| } | |
| /// <summary> | |
| /// Creates a copy of this <see cref="CoordinateParticleEffect"/> to another position to simplify applying the same effect to many positions. | |
| /// </summary> | |
| /// <param name="position">The position to copy to.</param> | |
| /// <returns>A <see cref="CoordinateParticleEffect"/> that has all the same properties as this instance, but for a different position.</returns> | |
| public CoordinateParticleEffect CopyTo(Vector3 position) | |
| { | |
| var result = new CoordinateParticleEffect(_asset, _effectName, position) | |
| { | |
| Rotation = _rotation, | |
| Color = _color, | |
| Scale = _scale, | |
| Range = _range, | |
| InvertAxis = _InvertAxis | |
| }; | |
| if (IsActive) | |
| { | |
| result.Start(); | |
| } | |
| return result; | |
| } | |
| } | |
| } |