[1114] | 1 | using System;
|
---|
| 2 | using System.Collections.Generic;
|
---|
| 3 |
|
---|
| 4 | namespace Oni.Particles
|
---|
| 5 | {
|
---|
| 6 | internal class Particle
|
---|
| 7 | {
|
---|
| 8 | #region Private data
|
---|
| 9 | private ParticleFlags1 flags1;
|
---|
| 10 | private ParticleFlags2 flags2;
|
---|
| 11 | private SpriteType spriteType;
|
---|
| 12 | private DisableDetailLevel disableDetailLevel;
|
---|
| 13 | private Value lifetime;
|
---|
| 14 | private Value collisionRadius;
|
---|
| 15 | private float aiDodgeRadius;
|
---|
| 16 | private float aiAlertRadius;
|
---|
| 17 | private string flybySoundName;
|
---|
| 18 | private Appearance appearance;
|
---|
| 19 | private Attractor attractor;
|
---|
| 20 | private List<Variable> variables;
|
---|
| 21 | private List<Emitter> emitters;
|
---|
| 22 | private List<Event> events;
|
---|
| 23 | #endregion
|
---|
| 24 |
|
---|
| 25 | #region private struct ActionRange
|
---|
| 26 |
|
---|
| 27 | private struct ActionRange
|
---|
| 28 | {
|
---|
| 29 | internal ActionRange(BinaryReader reader)
|
---|
| 30 | {
|
---|
| 31 | First = reader.ReadUInt16();
|
---|
| 32 | Last = reader.ReadUInt16();
|
---|
| 33 | }
|
---|
| 34 |
|
---|
| 35 | public bool IsEmpty => First == Last;
|
---|
| 36 |
|
---|
| 37 | public int First { get; set; }
|
---|
| 38 | public int Last { get; set; }
|
---|
| 39 | }
|
---|
| 40 |
|
---|
| 41 | #endregion
|
---|
| 42 |
|
---|
| 43 | public Particle()
|
---|
| 44 | {
|
---|
| 45 | lifetime = Value.FloatZero;
|
---|
| 46 | collisionRadius = Value.FloatZero;
|
---|
| 47 | appearance = new Appearance();
|
---|
| 48 | attractor = new Attractor();
|
---|
| 49 | variables = new List<Variable>();
|
---|
| 50 | emitters = new List<Emitter>();
|
---|
| 51 | events = new List<Event>();
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | public Particle(BinaryReader reader)
|
---|
| 55 | : this()
|
---|
| 56 | {
|
---|
| 57 | appearance = new Appearance();
|
---|
| 58 | attractor = new Attractor();
|
---|
| 59 |
|
---|
| 60 | reader.Skip(8);
|
---|
| 61 | flags1 = (ParticleFlags1)reader.ReadInt32();
|
---|
| 62 | flags2 = (ParticleFlags2)reader.ReadInt32();
|
---|
| 63 | spriteType = (SpriteType)((int)(flags1 & ParticleFlags1.SpriteModeMask) >> 5);
|
---|
| 64 | disableDetailLevel = (DisableDetailLevel)((int)(flags2 & ParticleFlags2.DisableLevelMask) >> 5);
|
---|
| 65 | reader.Skip(4);
|
---|
| 66 |
|
---|
| 67 | int variableCount = reader.ReadUInt16();
|
---|
| 68 | int actionCount = reader.ReadUInt16();
|
---|
| 69 | int emitterCount = reader.ReadUInt16();
|
---|
| 70 | reader.Skip(2);
|
---|
| 71 |
|
---|
| 72 | variables = new List<Variable>(variableCount);
|
---|
| 73 | emitters = new List<Emitter>(actionCount);
|
---|
| 74 | events = new List<Event>(emitterCount);
|
---|
| 75 |
|
---|
| 76 | ActionRange[] eventActions = new ActionRange[16];
|
---|
| 77 |
|
---|
| 78 | for (int i = 0; i < 16; i++)
|
---|
| 79 | eventActions[i] = new ActionRange(reader);
|
---|
| 80 |
|
---|
| 81 | lifetime = Value.Read(reader);
|
---|
| 82 | collisionRadius = Value.Read(reader);
|
---|
| 83 | aiDodgeRadius = reader.ReadSingle();
|
---|
| 84 | aiAlertRadius = reader.ReadSingle();
|
---|
| 85 | flybySoundName = reader.ReadString(16);
|
---|
| 86 | appearance = new Appearance(reader);
|
---|
| 87 | attractor = new Attractor(reader);
|
---|
| 88 | reader.Skip(12);
|
---|
| 89 |
|
---|
| 90 | for (int i = 0; i < variableCount; i++)
|
---|
| 91 | variables.Add(new Variable(reader));
|
---|
| 92 |
|
---|
| 93 | EventAction[] actions = new EventAction[actionCount];
|
---|
| 94 |
|
---|
| 95 | for (int i = 0; i < actionCount; i++)
|
---|
| 96 | actions[i] = new EventAction(reader);
|
---|
| 97 |
|
---|
| 98 | try
|
---|
| 99 | {
|
---|
| 100 | for (int i = 0; i < emitterCount; i++)
|
---|
| 101 | emitters.Add(new Emitter(reader));
|
---|
| 102 | }
|
---|
| 103 | catch (System.IO.EndOfStreamException)
|
---|
| 104 | {
|
---|
| 105 | // ignore corrupted particles that contain an invalid emitter count field
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | for (int i = 0; i < eventActions.Length; i++)
|
---|
| 109 | {
|
---|
| 110 | ActionRange range = eventActions[i];
|
---|
| 111 |
|
---|
| 112 | if (!range.IsEmpty)
|
---|
| 113 | events.Add(new Event((EventType)i, actions, range.First, range.Last - range.First));
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | public void Write(BinaryWriter writer)
|
---|
| 118 | {
|
---|
| 119 | List<EventAction> actions = new List<EventAction>();
|
---|
| 120 | ActionRange[] ranges = new ActionRange[16];
|
---|
| 121 |
|
---|
| 122 | for (int i = 0; i < ranges.Length; i++)
|
---|
| 123 | {
|
---|
| 124 | Event e = events.Find(x => (int)x.Type == i);
|
---|
| 125 |
|
---|
| 126 | ActionRange range = new ActionRange();
|
---|
| 127 | range.First = actions.Count;
|
---|
| 128 | range.Last = actions.Count + (e == null ? 0 : e.Actions.Count);
|
---|
| 129 | ranges[i] = range;
|
---|
| 130 |
|
---|
| 131 | if (e != null)
|
---|
| 132 | actions.AddRange(e.Actions);
|
---|
| 133 | }
|
---|
| 134 |
|
---|
| 135 | writer.Write((int)flags1 | ((int)spriteType << 5));
|
---|
| 136 | writer.Write((int)flags2 | ((int)disableDetailLevel << 5));
|
---|
| 137 | writer.Skip(4);
|
---|
| 138 | writer.WriteUInt16(variables.Count);
|
---|
| 139 | writer.WriteUInt16(actions.Count);
|
---|
| 140 | writer.WriteUInt16(emitters.Count);
|
---|
| 141 | writer.WriteUInt16(256);
|
---|
| 142 |
|
---|
| 143 | for (int i = 0; i < ranges.Length; i++)
|
---|
| 144 | {
|
---|
| 145 | writer.WriteUInt16(ranges[i].First);
|
---|
| 146 | writer.WriteUInt16(ranges[i].Last);
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | lifetime.Write(writer);
|
---|
| 150 | collisionRadius.Write(writer);
|
---|
| 151 | writer.Write(aiDodgeRadius);
|
---|
| 152 | writer.Write(aiAlertRadius);
|
---|
| 153 | writer.Write(flybySoundName, 16);
|
---|
| 154 | appearance.Write(writer);
|
---|
| 155 | attractor.Write(writer);
|
---|
| 156 | writer.Skip(12);
|
---|
| 157 |
|
---|
| 158 | foreach (Variable variable in variables)
|
---|
| 159 | variable.Write(writer);
|
---|
| 160 |
|
---|
| 161 | foreach (EventAction action in actions)
|
---|
| 162 | action.Write(writer);
|
---|
| 163 |
|
---|
| 164 | foreach (Emitter emitter in emitters)
|
---|
| 165 | emitter.Write(writer);
|
---|
| 166 | }
|
---|
| 167 |
|
---|
| 168 | public ParticleFlags1 Flags1
|
---|
| 169 | {
|
---|
| 170 | get
|
---|
| 171 | {
|
---|
| 172 | return (flags1 & ~ParticleFlags1.SpriteModeMask);
|
---|
| 173 | }
|
---|
| 174 | set
|
---|
| 175 | {
|
---|
| 176 | flags1 = value;
|
---|
| 177 | }
|
---|
| 178 | }
|
---|
| 179 |
|
---|
| 180 | public ParticleFlags2 Flags2
|
---|
| 181 | {
|
---|
| 182 | get
|
---|
| 183 | {
|
---|
| 184 | return (flags2 & ~ParticleFlags2.DisableLevelMask);
|
---|
| 185 | }
|
---|
| 186 | set
|
---|
| 187 | {
|
---|
| 188 | flags2 = value;
|
---|
| 189 | }
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | public SpriteType SpriteType
|
---|
| 193 | {
|
---|
| 194 | get
|
---|
| 195 | {
|
---|
| 196 | return spriteType;
|
---|
| 197 | }
|
---|
| 198 | set
|
---|
| 199 | {
|
---|
| 200 | spriteType = value;
|
---|
| 201 | }
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | public DisableDetailLevel DisableDetailLevel
|
---|
| 205 | {
|
---|
| 206 | get
|
---|
| 207 | {
|
---|
| 208 | return disableDetailLevel;
|
---|
| 209 | }
|
---|
| 210 | set
|
---|
| 211 | {
|
---|
| 212 | disableDetailLevel = value;
|
---|
| 213 | }
|
---|
| 214 | }
|
---|
| 215 |
|
---|
| 216 | public string FlyBySoundName
|
---|
| 217 | {
|
---|
| 218 | get
|
---|
| 219 | {
|
---|
| 220 | return flybySoundName;
|
---|
| 221 | }
|
---|
| 222 | set
|
---|
| 223 | {
|
---|
| 224 | flybySoundName = value;
|
---|
| 225 | }
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 | public Value Lifetime
|
---|
| 229 | {
|
---|
| 230 | get
|
---|
| 231 | {
|
---|
| 232 | return lifetime;
|
---|
| 233 | }
|
---|
| 234 | set
|
---|
| 235 | {
|
---|
| 236 | lifetime = value;
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | public Value CollisionRadius
|
---|
| 241 | {
|
---|
| 242 | get
|
---|
| 243 | {
|
---|
| 244 | return collisionRadius;
|
---|
| 245 | }
|
---|
| 246 | set
|
---|
| 247 | {
|
---|
| 248 | collisionRadius = value;
|
---|
| 249 | }
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | public float AIDodgeRadius
|
---|
| 253 | {
|
---|
| 254 | get
|
---|
| 255 | {
|
---|
| 256 | return aiDodgeRadius;
|
---|
| 257 | }
|
---|
| 258 | set
|
---|
| 259 | {
|
---|
| 260 | aiDodgeRadius = value;
|
---|
| 261 | }
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | public float AIAlertRadius
|
---|
| 265 | {
|
---|
| 266 | get
|
---|
| 267 | {
|
---|
| 268 | return aiAlertRadius;
|
---|
| 269 | }
|
---|
| 270 | set
|
---|
| 271 | {
|
---|
| 272 | aiAlertRadius = value;
|
---|
| 273 | }
|
---|
| 274 | }
|
---|
| 275 |
|
---|
| 276 | public Appearance Appearance => appearance;
|
---|
| 277 |
|
---|
| 278 | public Attractor Attractor => attractor;
|
---|
| 279 |
|
---|
| 280 | public List<Variable> Variables => variables;
|
---|
| 281 |
|
---|
| 282 | public List<Emitter> Emitters => emitters;
|
---|
| 283 |
|
---|
| 284 | public List<Event> Events => events;
|
---|
| 285 | }
|
---|
| 286 | }
|
---|