From eb0e08c8ee6a0a32b88f91cff06e8ee683fdb3f5 Mon Sep 17 00:00:00 2001 From: Regalis Date: Thu, 17 Dec 2015 19:35:14 +0200 Subject: [PATCH] Set orders stay in CrewCommander interface after reopening, minor changes to the interface layout --- Subsurface/Barotrauma.csproj | 13 +- .../Source/Characters/AI/CrewCommander.cs | 85 ++-- .../Source/Characters/AI/HumanAIController.cs | 14 + .../AI/Objectives/AIObjectiveManager.cs | 18 +- Subsurface/Source/Characters/AI/Order.cs | 18 +- Subsurface/Source/Map/azreey13.hzj | 404 ------------------ Subsurface/Source/Screens/GameScreen.cs | 4 +- Subsurface_Solution.v12.suo | Bin 785408 -> 785408 bytes .../Barotrauma_content.csproj.user | 2 +- 9 files changed, 107 insertions(+), 451 deletions(-) delete mode 100644 Subsurface/Source/Map/azreey13.hzj diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 5d3e3e124..0c13edef5 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -77,7 +77,9 @@ - + + + @@ -285,6 +287,9 @@ PreserveNewest + + PreserveNewest + Designer PreserveNewest @@ -292,6 +297,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -591,6 +599,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Subsurface/Source/Characters/AI/CrewCommander.cs b/Subsurface/Source/Characters/AI/CrewCommander.cs index 972d4060f..a56044d43 100644 --- a/Subsurface/Source/Characters/AI/CrewCommander.cs +++ b/Subsurface/Source/Characters/AI/CrewCommander.cs @@ -38,20 +38,20 @@ namespace Barotrauma if (IsOpen) { - CreateGUIFrame(); + if (frame == null) CreateGUIFrame(); UpdateCharacters(); } } private void CreateGUIFrame() { - frame = new GUIFrame(Rectangle.Empty, Color.Black * 0.3f); + frame = new GUIFrame(Rectangle.Empty, Color.Black * 0.6f); frame.Padding = new Vector4(200.0f, 100.0f, 200.0f, 100.0f); //UpdateCharacters(); int buttonWidth = 130; - int spacing = 10; + int spacing = 20; int y = 250; @@ -88,13 +88,16 @@ namespace Barotrauma i++; } - y += 80; + y += 100; } } private GUIButton CreateOrderButton(Rectangle rect, Order order, bool createSymbol = true) { - var orderButton = new GUIButton(rect, order.Name, Color.Black * 0.5f, Alignment.TopCenter, Alignment.Right, null, frame); + var orderButton = new GUIButton(rect, order.Name, Color.Black * 0.7f, Alignment.TopCenter, Alignment.Center, null, frame); + orderButton.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + orderButton.TextColor = Color.White; + orderButton.Color = Color.Black * 0.5f; orderButton.HoverColor = Color.LightGray * 0.5f; orderButton.OutlineColor = Color.LightGray * 0.8f; orderButton.UserData = order; @@ -102,10 +105,10 @@ namespace Barotrauma if (createSymbol) { - var symbol = new GUIImage(new Rectangle(-5,0,64,64), order.SymbolSprite, Alignment.Left | Alignment.CenterY, orderButton); + var symbol = new GUIImage(new Rectangle(0,-60,64,64), order.SymbolSprite, Alignment.TopCenter, orderButton); symbol.Color = order.Color; - orderButton.children.Insert(1, symbol); + orderButton.children.Insert(0, symbol); orderButton.children.RemoveAt(orderButton.children.Count-1); } @@ -123,7 +126,7 @@ namespace Barotrauma prevCharacterFrames.Add(child); } - + foreach (GUIComponent child in prevCharacterFrames) { frame.RemoveChild(child); @@ -183,6 +186,12 @@ namespace Barotrauma new GUIImage(new Rectangle(-5, -5, 0, 0), character.AnimController.Limbs[0].sprite, Alignment.Left, characterButton); + var humanAi = character.AIController as HumanAIController; + if (humanAi.CurrentOrder != null) + { + CreateCharacterOrderFrame(characterButton, humanAi.CurrentOrder, humanAi.CurrentOrderOption); + } + i++; } } @@ -200,30 +209,9 @@ namespace Barotrauma if (!characterButton.Selected) continue; characterButton.Selected = false; - var character = child.UserData as Character; - if (character == null) continue; + CreateCharacterOrderFrame(characterButton, order, ""); - var humanAi = character.AIController as HumanAIController; - if (humanAi == null) continue; - - var existingOrder = characterButton.children.Find(c => c.UserData as Order != null); - if (existingOrder != null) characterButton.RemoveChild(existingOrder); - - var orderFrame = new GUIFrame(new Rectangle(0, characterButton.Rect.Height, 0, 30 + order.Options.Length*15), null, characterButton); - orderFrame.OutlineColor = Color.LightGray * 0.8f; - orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); - orderFrame.UserData = order; - new GUITextBlock(new Rectangle(0,0,0,20), order.DoingText, GUI.Style, Alignment.TopLeft, Alignment.TopCenter, orderFrame); - - var optionList = new GUIListBox(new Rectangle(0,20,0,80), Color.Transparent, null, orderFrame); - optionList.UserData = order; - optionList.OnSelected = SelectOrderOption; - foreach (string option in order.Options) - { - var optionBox = new GUITextBlock(new Rectangle(0,0,0,15), option, GUI.Style, optionList); - optionBox.Font = GUI.SmallFont; - optionBox.UserData = option; - } + var humanAi = (characterButton.UserData as Character).AIController as HumanAIController; humanAi.SetOrder(order, ""); } @@ -233,6 +221,41 @@ namespace Barotrauma return true; } + private void CreateCharacterOrderFrame(GUIComponent characterFrame, Order order, string selectedOption) + { + var character = characterFrame.UserData as Character; + if (character == null) return; + + var humanAi = character.AIController as HumanAIController; + if (humanAi == null) return; + + var existingOrder = characterFrame.children.Find(c => c.UserData as Order != null); + if (existingOrder != null) characterFrame.RemoveChild(existingOrder); + + var orderFrame = new GUIFrame(new Rectangle(0, characterFrame.Rect.Height, 0, 30 + order.Options.Length * 15), null, characterFrame); + orderFrame.OutlineColor = Color.LightGray * 0.8f; + orderFrame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f); + orderFrame.UserData = order; + new GUITextBlock(new Rectangle(0, 0, 0, 20), order.DoingText, GUI.Style, Alignment.TopLeft, Alignment.TopCenter, orderFrame); + + var optionList = new GUIListBox(new Rectangle(0, 20, 0, 80), Color.Transparent, null, orderFrame); + optionList.UserData = order; + + for (int i = 0; i < order.Options.Length; i++ ) + { + var optionBox = new GUITextBlock(new Rectangle(0, 0, 0, 15), order.Options[i], GUI.Style, optionList); + optionBox.Font = GUI.SmallFont; + optionBox.UserData = order.Options[i]; + + if (selectedOption == order.Options[i]) + { + optionList.Select(i); + } + } + optionList.OnSelected = SelectOrderOption; + + } + private bool SelectOrderOption(GUIComponent component, object userData) { string option = userData.ToString(); diff --git a/Subsurface/Source/Characters/AI/HumanAIController.cs b/Subsurface/Source/Characters/AI/HumanAIController.cs index 55d539d1d..5b694e096 100644 --- a/Subsurface/Source/Characters/AI/HumanAIController.cs +++ b/Subsurface/Source/Characters/AI/HumanAIController.cs @@ -20,6 +20,18 @@ namespace Barotrauma private float updateObjectiveTimer; + public Order CurrentOrder + { + get; + private set; + } + + public string CurrentOrderOption + { + get; + private set; + } + public HumanAIController(Character c) : base(c) { indoorsSteeringManager = new IndoorsSteeringManager(this, true); @@ -77,6 +89,8 @@ namespace Barotrauma public void SetOrder(Order order, string option) { + CurrentOrderOption = option; + CurrentOrder = order; objectiveManager.SetOrder(order, option); } diff --git a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs index 29a93b3eb..9cb2e6225 100644 --- a/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs +++ b/Subsurface/Source/Characters/AI/Objectives/AIObjectiveManager.cs @@ -14,13 +14,13 @@ namespace Barotrauma private Character character; - private AIObjective currentOrder; + private AIObjective currentObjective; public AIObjective CurrentObjective { get { - if (currentOrder != null) return currentOrder; + if (currentObjective != null) return currentObjective; return objectives.Any() ? objectives[0] : null; } } @@ -41,7 +41,7 @@ namespace Barotrauma public float GetCurrentPriority(Character character) { - if (currentOrder != null) return OrderPriority; + if (currentObjective != null) return OrderPriority; return (CurrentObjective == null) ? 0.0f : CurrentObjective.GetPriority(character); } @@ -69,9 +69,9 @@ namespace Barotrauma public void DoCurrentObjective(float deltaTime) { - if (currentOrder != null && (!objectives.Any() || objectives[0].GetPriority(character) HullVertices - { - get; - private set; - } - - private float depthDamageTimer; - - private Submarine submarine; - - private Body body; - - private Vector2 targetPosition; - - float mass = 10000.0f; - - //private Vector2? lastContactPoint; - //private VoronoiCell lastContactCell; - - public Rectangle Borders - { - get; - private set; - } - - public Vector2 Velocity - { - get { return body.LinearVelocity; } - set - { - if (!MathUtils.IsValid(value)) return; - body.LinearVelocity = value; - } - } - - public Vector2 TargetPosition - { - get { return targetPosition; } - set - { - if (!MathUtils.IsValid(value)) return; - targetPosition = value; - } - } - - public Vector2 Position - { - get { return ConvertUnits.ToDisplayUnits(body.Position); } - } - - public Vector2 Center - { - get { return new Vector2(Borders.X + Borders.Width / 2, Borders.Y - Borders.Height / 2); } - } - - public bool AtDamageDepth - { - get { return Position.Y < DamageDepth; } - } - - public SubmarineBody(Submarine sub) - { - this.submarine = sub; - - - List convexHull = GenerateConvexHull(); - HullVertices = convexHull; - - for (int i = 0; i < convexHull.Count; i++) - { - convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]); - } - - convexHull.Reverse(); - - //get farseer 'vertices' from vectors - Vertices shapevertices = new Vertices(convexHull); - - AABB hullAABB = shapevertices.GetAABB(); - - Borders = new Rectangle( - (int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X), - (int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y), - (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f), - (int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f)); - - //var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit); - - body = BodyFactory.CreateBody(GameMain.World, this); - - foreach (Hull hull in Hull.hullList) - { - Rectangle rect = hull.Rect; - foreach (Structure wall in Structure.WallList) - { - if (!Submarine.RectsOverlap(wall.Rect, hull.Rect)) continue; - - if (wall.IsHorizontal) - { - if (wall.Rect.Y >= hull.Rect.Y) - { - rect = new Rectangle(rect.X, wall.Rect.Y, rect.Width, rect.Height + (wall.Rect.Y - rect.Y)); - } - else - { - rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + (rect.Y - rect.Height - (wall.Rect.Y - wall.Rect.Height))); - } - } - } - - FixtureFactory.AttachRectangle( - ConvertUnits.ToSimUnits(rect.Width), - ConvertUnits.ToSimUnits(rect.Height), - 5.0f, - ConvertUnits.ToSimUnits(rect.Center.ToVector2()), - body, this); - } - - body.BodyType = BodyType.Dynamic; - body.CollisionCategories = Physics.CollisionMisc | Physics.CollisionWall; - body.CollidesWith = Physics.CollisionLevel | Physics.CollisionCharacter; - body.Restitution = Restitution; - body.Friction = Friction; - body.FixedRotation = true; - body.Mass = mass; - body.Awake = true; - body.SleepingAllowed = false; - body.IgnoreGravity = true; - body.OnCollision += OnCollision; - //body.UserData = this; - } - - - private List GenerateConvexHull() - { - if (!Structure.WallList.Any()) - { - return new List() { new Vector2(-1.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, -1.0f) }; - } - - List points = new List(); - - Vector2 leftMost = Vector2.Zero; - - foreach (Structure wall in Structure.WallList) - { - for (int x = -1; x <= 1; x += 2) - { - for (int y = -1; y <= 1; y += 2) - { - Vector2 corner = new Vector2(wall.Rect.X + wall.Rect.Width / 2.0f, wall.Rect.Y - wall.Rect.Height / 2.0f); - corner.X += x * wall.Rect.Width / 2.0f; - corner.Y += y * wall.Rect.Height / 2.0f; - - if (points.Contains(corner)) continue; - - points.Add(corner); - if (leftMost == Vector2.Zero || corner.X < leftMost.X) leftMost = corner; - } - } - } - - List hullPoints = new List(); - - Vector2 currPoint = leftMost; - Vector2 endPoint; - do - { - hullPoints.Add(currPoint); - endPoint = points[0]; - - for (int i = 1; i < points.Count; i++) - { - if ((currPoint == endPoint) - || (MathUtils.VectorOrientation(currPoint, endPoint, points[i]) == -1)) - { - endPoint = points[i]; - } - } - - currPoint = endPoint; - - } - while (endPoint != hullPoints[0]); - - return hullPoints; - } - - public void Update(float deltaTime) - { - if (targetPosition != Vector2.Zero && targetPosition != Position) - { - float dist = Vector2.Distance(targetPosition, Position); - - if (dist > 1000.0f) - { - body.SetTransform(ConvertUnits.ToSimUnits(targetPosition), 0.0f); - targetPosition = Vector2.Zero; - } - else if (dist > 50.0f) - { - body.SetTransform((ConvertUnits.ToSimUnits(targetPosition) - body.Position) * 0.01f, 0.0f); - } - } - else - { - targetPosition = Vector2.Zero; - } - - - //------------------------- - - Vector2 totalForce = CalculateBuoyancy(); - - if (body.LinearVelocity.LengthSquared() > 0.000001f) - { - float dragCoefficient = 0.01f; - - float speedLength = (body.LinearVelocity == Vector2.Zero) ? 0.0f : body.LinearVelocity.Length(); - float drag = speedLength * speedLength * dragCoefficient * mass; - - totalForce += -Vector2.Normalize(body.LinearVelocity) * drag; - } - - ApplyForce(totalForce); - - UpdateDepthDamage(deltaTime); - - } - - private Vector2 CalculateBuoyancy() - { - float waterVolume = 0.0f; - float volume = 0.0f; - foreach (Hull hull in Hull.hullList) - { - waterVolume += hull.Volume; - volume += hull.FullVolume; - } - - float waterPercentage = waterVolume / volume; - - float neutralPercentage = 0.07f; - - float buoyancy = Math.Max(neutralPercentage - waterPercentage, -neutralPercentage*2.0f); - buoyancy *= mass; - - return new Vector2(0.0f, buoyancy*10.0f); - } - - public void ApplyForce(Vector2 force) - { - body.ApplyForce(force); - } - - public void SetPosition(Vector2 position) - { - body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f); - } - - private void UpdateDepthDamage(float deltaTime) - { - if (Position.Y > DamageDepth) return; - - float depth = DamageDepth - Position.Y; - depth = Math.Min(depth, 40000.0f); - - // float prevTimer = depthDamageTimer; - - depthDamageTimer -= deltaTime*Math.Min(depth,20000)*PressureDamageMultiplier; - - //if (prevTimer>5.0f && depthDamageTimer<=5.0f) - //{ - // SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f,); - //} - - if (depthDamageTimer > 0.0f) return; - - Vector2 damagePos = Vector2.Zero; - if (Rand.Int(2)==0) - { - damagePos = new Vector2( - (Rand.Int(2) == 0) ? Borders.X : Borders.X+Borders.Width, - Rand.Range(Borders.Y - Borders.Height, Borders.Y)); - } - else - { - damagePos = new Vector2( - Rand.Range(Borders.X, Borders.X + Borders.Width), - (Rand.Int(2) == 0) ? Borders.Y : Borders.Y - Borders.Height); - } - - SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f, damagePos, 10000.0f); - - GameMain.GameScreen.Cam.Shake = depth * PressureDamageMultiplier * 0.1f; - - damagePos += submarine.Position + Submarine.HiddenSubPosition; - Explosion.RangedStructureDamage(damagePos, depth * PressureDamageMultiplier * 50.0f, depth * PressureDamageMultiplier); - //SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, Rand.Range(0.0f, 100.0f), damagePos, 5000.0f); - - depthDamageTimer = 10.0f; - } - - public bool OnCollision(Fixture f1, Fixture f2, Contact contact) - { - VoronoiCell cell = f2.Body.UserData as VoronoiCell; - - if (cell == null) - { - Limb limb = f2.Body.UserData as Limb; - if (limb!=null && limb.character.Submarine==null) - { - Vector2 normal2; - FixedArray2 points; - contact.GetWorldManifold(out normal2, out points); - - if (Submarine.PickBody( - points[0] - limb.LinearVelocity * ((float)Physics.step) - ConvertUnits.ToSimUnits(submarine.Position) - submarine.Velocity * ((float)Physics.step) + normal2, - points[0] - ConvertUnits.ToSimUnits(submarine.Position) - normal2, null, Physics.CollisionWall) != null) - { - - return true; - } - - var ragdoll = limb.character.AnimController; - ragdoll.FindHull(); - - return false; - - } - - return true; - } - - Vector2 normal; - FarseerPhysics.Common.FixedArray2 worldPoints; - contact.GetWorldManifold(out normal, out worldPoints); - - Vector2 lastContactPoint = worldPoints[0]; - - normal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(body.Position) - cell.Center); - - float impact = Vector2.Dot(Velocity, -normal); - - //Vector2 u = Vector2.Dot(Velocity, -normal) * normal; - //Vector2 w = (Velocity + u); - - //speed = ConvertUnits.ToDisplayUnits(w * (1.0f - Friction) + u * Restitution); - - if (impact < 3.0f) return true; - - SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, ConvertUnits.ToDisplayUnits(lastContactPoint)); - GameMain.GameScreen.Cam.Shake = impact * 2.0f; - - Vector2 limbForce = -normal * impact * 0.5f; - - float length = limbForce.Length(); - if (length > 10.0f) limbForce = (limbForce / length) * 10.0f; - - foreach (Character c in Character.CharacterList) - { - if (c.AnimController.CurrentHull == null) continue; - - if (impact > 2.0f) c.StartStun((impact - 2.0f) * 0.1f); - - foreach (Limb limb in c.AnimController.Limbs) - { - if (c.AnimController.LowestLimb == limb) continue; - limb.body.ApplyLinearImpulse(limb.Mass * limbForce); - } - } - - Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * DamageMultiplier); - - return true; - } - - } -} diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index e5e8c87cf..e285d77aa 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -134,9 +134,9 @@ namespace Barotrauma public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { - if (Character.Controlled!=null) + if (Character.Controlled != null) { - cam.TargetPos = Character.Controlled.Position; + cam.TargetPos = Character.Controlled.WorldPosition; } cam.UpdateTransform(); diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index f5705f462889fbdaf9ae4b2c4c09d76aaa3eff8f..f44bde1cbd5b3238d4e5281cf0d858167239e140 100644 GIT binary patch delta 3893 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 delta 4909 zcmbW53sjX=7RSGRzH=}4@>Y4PaJwL)JOsp7DWa0%6GhN8GhQl~PXt9Yxs;LRBe|b* zkB{%-CQU0fBQuB9OfGYo&6wj_GZmUTlg$5IF3cTQGi%L!YyH^!?7h!E z-+6xLV!JcIc4xrW;pxRpQNk2Ox!>O24xteE7D!tZI0!=xVhX`>PzF|j#UPixUG)PQ zkEdrbzZ9*EJ;OHpG~8z1WcV7jey*zv)q3$v%g;z10Ye_rZ3icym!o<#bm`M`Ab4!rYPN>ebu?%1q%6psp#-UnYYQq@+PF8tCPO`)aQ2}94U zsmT2ja>zCZK(B#b2KwS%_CcNiH9m^60n~!^;5i`UpLfd_AT>)!kd_?6&0F2Z`#K%Q zm^cb4DAI@|pCb7ukO#mL13Cq%f$vGA7E=G}-@(5J#Di2c-V7<=9|id)cn36r^RRLE zKqa8O6>I>-Kn{Tl-!!lW>Z6F15!c}LhQ1hS$3gdp{&&bj;3(o`jIb5aB<|AA z7g4gkEz|S}T=77h7{h|K{O&zyvsTeoO`Eh^ZJ(KBXqu;2YrB=uUqItJ5p>JtyvnQRr;EV?18+G zmdwnCT_#1jpxvF@Ppj{3HC@4IT?JiJ)6mwKK>IBR{k6SWT#tE;#}HrX86e6J@lEy* ztPR$qm&qP%)vdL3nd+N|+GoV*F%Eu-G}{1pZ(j}-HeH2nzIutAfs|=~62XVneWaaa zDc%WYMcIXU!Op&)N6c5VIb#}Poaf2V1Dk4}cDHvw-CB&)j$8_(MItM{HfH_Yi$Z37zplx3yQ(dTHrFMm;l2Z6;TrSJI^b zv28mg=z)iMGtpb(?co&a$Rg_j>juiut@9~|41dSCuhLeJj~A~lpgHyrFfeDSjsE|h z$<-pxVQ_dd`YEpGlBHv3pl>!;pFX7!z6IkT4t`3xE}yf7jE(EKk?F=(y4TH7skYHZ zajR0rW)v0Qs?~-UG599!?vZ#s<_28}ripbmGpF@K64_iRq#Qo^NGTbM1#3|;0l*5P zL0=$aI-fX{`@3!NkZFPjsnOMgpbl}Hhe8em4})~Kt+V<_lt;O3qanwDOz9AP-cLcV0MSm)#ei(`dsKwf_zW_3PBMl2J^st zumF^RQm_y_1r~wDU{xcZ(~m0tBKt6lKG4q8vVr(C?99|pfIcuQn=J;mb0H8xVu z@K=xfILdu8wIeHr6BjkfY@|qy@CgzZlUYK53@ucWlp`(Ji-Z@O)7L7ou%zT;yC zophT{L4F860w06Z;0!nmJ^|-I3y@9R7sLG2M?}`UJgaVRCasiHo*{C+GNtR)6Vw_n zyMI`ij5~^ckCiiuIoReNPA%C#-*pizgrgP=hI0~VCCyow)Nedg2VzgcCFf6`R`*bD z25BgdguNSNy7sewRCn1*I6QxWRW9;-OiK!|R?A9fVUjWg?iCkgQ5tsoU1JXVV@^QERgj?pjrSum-F9b5}d=GnxTOWkw>IK5V zO{|bG$Xk$W2}f|5M}=)LmZMw&R)STa5>x@%P>p=&P-g^BmRtOBquf~%Mc{bl~mUylVy?kei)Ce+iMaTVXU{9y33p-k{b|P`1N^TOTjv0f*dG0kyDJEZZcnZ1Sqsb#fR=(52V3yFvYgbw8_j9U}4$*A?LNB?9(fxbf)iJ2(Y8 zeAR2FCM@FbF-iJOUp0tC%65tof7?bDJ@a+m?BgirW6VllROt`8a*6U{o-Ix;FM9P1 z-U4kbKVk^hQRycA=WC&kYvCdMn&Ra&T2$onmX6y_lIJT>hN#Hn*`@>-<-e4=UfyTq zzb - ProjectFiles + ShowAllFiles \ No newline at end of file